python中类属性和数据属性的解释

来源:互联网 发布:led发光原理 知乎 编辑:程序博客网 时间:2024/05/16 09:39
python中的类叫class object,类的实例叫instance object. 
类 Class Objects 
类拥有两种操作,1.类属性 attribute references 2.实例化instantiation 
类属性就相当于专属于一个类的变量(即某些语言中的类的静态公共变量static public),使用方法是:类名称.类属性名称 实例化则是创建一个类的实例的方法,使用方法是:类名称() 
在使用实例化方法后,将会创建一个空的类实例,一般的python类的定义中会有一个特殊的方法来初始化,这个方法就是__init__(),当调用了类的实例化方法后,__init__()方法会立刻被这个类的实例调用.也就是说,__init__()不是构造函数,而是一个普通的方法. 类的实例 Instance Objects 
类的实例只拥有一种操作,这就是 1.属性调用 attribute references. 
属性调用指 1.数据属性 2.方法 
数据属性不需要预先定义!当数据属性初次被使用时,它即被创建并赋值(they spring into existence when they are first assigned to) 看下面的例子 
class Test:passt=Test()t.name='notus'print t.name

我们在类Test中并没有定义name这个数据属性,但是在代码中却可以直接使用,这就是数据属性. 现在,抛开广义上对属性attribute的解释,在实际编程中经常用的属性这个词,在python的class中有两种属性:类属性,数据属性.(大多数编程语言都有这样两种属性).类属性属于类,数据属性属于类的实例.我们假设有类Test,则一般这两种属性的用法是 
Test.modet=Test()t.name
那么这两种属性应该在什么时候定义呢? 
按照上面的讨论可知,数据属性不需要预先定义,当数据属性初次被使用时,它即被创建并赋值.而实际上,类属性也是如此. 
因此,我们有了下面的例子
class Test:passt=Test()t.name='notus'print t.nameTest.mode='auto'print Test.mode
大家看,数据属性name和类属性mode均没有在类中被定义,你要做的,只是在需要的时候使用他们即可.如何预先给属性赋值 
可以在类的定义中使用属性,先看这个例子 
class Test:def ask(theInstance):theInstance.name='notus'Test.mode='auto'##print Test.modet=Test()##print t.namet.ask()print Test.modeprint t.name
类Test有方法ask.注意看程序中被注释掉的两行,在没有使用ask()方法前,运行被注释的那两句的任一句均会出错,提示"class Test has no attribute ...".但运行ask()后,我们在ask()方法中初始了这两个属性 ,则运行通过. 
注意看ask()接收的参数theInstance,这个传过来的就是程序中类Test的实例t .一般的命名规范建议将这个参数命名为self.这个参数是python自动传入的,所以不需要再在程序中传. 
如果想要在类实例化后立刻使用这些属性,那就应该把这些属性的初始放在__init__()方法中,前面说过了,__init__()方法在类的实例化结束后立刻被自动调用. 所以我们的例子程序可以改成这样 
class Test:def __init__(self):self.name='notus'Test.mode='auto'##print Test.modet=Test()##print t.nameprint Test.modeprint t.name

所以可以有这样的类定义 
class Test:def __init__(self):self.name='notus'Test.mode='auto'def ask(self):self.date='2008'##print Test.modet=Test()##print t.nameprint Test.modeprint t.name##print t.datet.ask()print t.date

数据属性date只有在调用了ask()方法后才可以被使用.当然这样也可以使用这个属性
##print Test.modet=Test()##print t.nameprint Test.modeprint t.namet.date='2007'print t.date

在程序中创建了date这个数据属性.可以想象,之后调用ask()方法时,数据属性date已经存在,只是被改变了值. 不用方法也可以初始化属性 
看下面的示例程序 
class Test:action='win the game'  #类属性print Test.actiont=Test()print t.actionTest.action='at least 1 point'print Test.actionprint t.actiont.action='dont lose'print Test.actionprint t.action

运行的结果如下 

win the game 
win the game 
at least 1 point 
at least 1 point 
at least 1 point 
dont lose 
现象可以概括为:"改变类属性,数据属性跟着变,改变数据属性,类属性不变".
 class AAA():  aaa = 10  #类属性情形1   obj1 = AAA()  obj2 = AAA()   print obj1.aaa, obj2.aaa, AAA.aaa   情形2  obj1.aaa += 2  print obj1.aaa, obj2.aaa, AAA.aaa   情形3  AAA.aaa += 3  print obj1.aaa, obj2.aaa, AAA.aaa

引用 
对于情形1,我相信绝大多数人都会正确的说出结果,那就是: 
10  10  10 
对于上面这个结果,没有任何悬念,通过两个AAA的实例,以及通过AAA类名引用aaa属性值,都是同样的答案。 那在情形2中,应该是什么结果呢,我相信大多数人还是会说出正确的结果: 
12  10  10 
在上面这个结果中,一旦执行了obj1.aaa += 2,也就意味着obj1这个实例有了个实例的属性值,他的属性名称也为aaa,那是不是obj1的aaa是个新的属性呢,实际上可以说法是对,但也不对,实际上obj1.aaa += 2这个代码的执行,并不像我们想象的那么简单,首先他会到obj1所属的类AAA的属性列表中去找一个名称为aaa的属性,如果有,他就会返回该值作为 obj1中aaa的初始值,也就是说,这以后obj1.aaa的这个属性值跟AAA.aaa就基本没有关系了。 那在情形3中呢,答案是什么呢: 
12  13  13 
这又怎么说呢,其实很简单,AAA.aaa对AAA类属性做了一次设置,obj1.aaa经过一次+=操作后,实际上与AAA.aaa脱离了关系,而obj2.aaa没有经过任何的属性操作,因此其只会从其所属的类AAA中去获得aaa,并返回。 

引用 
《python核心编程》 
如果尝试在实例中设定或更新类属性会创建一个实例属性 c.version,后者会阻止对类属性 
C.versioin 的访问,因为第一个访问的就是 c.version,这样可以对实例有效地“遮蔽”类属性C.version,直到 c.version 被清除掉。 
1 0
原创粉丝点击