实例属性和类属性
实例属性
实例仅拥有数据属性(方法严格来说是类属性),后者只是与某个类的实例相关联的数据值,并且可以通过句点属性标识法来访问。这些值独立于其它实例或类。当一个实例被释放后,它的属性 同时也被清除了。
【1】“实例化”实例属性
设置实例的属性可以在实例创建后任意时间进行,也可以在能够访问实例的代码中进行。构造器__init()__是设置这些属性的关键点之一。
python能够在“运行时”创建实例属性 。
Python 不仅是动态类型,而且在运行时,允许这些对象属性的动态创建。
假如属性在条件语句中创建,如果该条件语句块并未被执行,属性也就不存在,而你 在后面的代码中试着去访问这些属性,就会有错误发生。
class People: #类属性 address = "广东" def __init__(self): #实例属性 self.name = "hugo" self.age = 18 p = People() #修改实例属性 p.age = 19 print(p.address) #广东 print(p.name) #hugo print(p.age) #19 print(People.address) #广东 print(People.name) #报错 print(People.age) #报错
【2】查看实例属
内建函数dir()可以显示类属性,同样还可以显示所有实例属性
class C: pass c = C() c.foo = "FOO" c.bar = "BAR" print(dir(c)) ''' ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__','__ge__', '__getattribute__', '__gt__', '__hash__','__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'foo'] '''
实例中一个特殊属性__dict__,它是实例属性构成的一个字典
print(c.__dict__) #{'foo': 'FOO', 'bar': 'BAR'}
【3】内建类型属性
内建类型有实例属性和类属性
x = 1+2j print(x.__class__) #<class 'complex'> print(dir(x)) ''' ['__abs__', '__add__', '__bool__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__int__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__pos__', '__pow__', '__radd__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruediv__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', 'conjugate', 'imag', 'real'] ''' #访问它的数据属性 print(x.imag) #2.0 print(x.real) #1.0 print(x.conjugate()) #(1-2j) #print(x.__dict__) #报错,内建类型中不存在这个属性
【4】实例属性和类属性
类属性仅是与类相关的数据值,和实例属性不同,类属性和实例无关。这些值像静态成员那样被引用,即使在多次实例化中调用类, 它们的值都保持不变。不管如何,静态成员不会因为实例而改变它们的值,除非实例中显式改变它们的值。
类和实例都是名字空间。类是类属性的名字空间,实例则是实例属性的。
关于类属性和实例属性,还有一些方面需要指出。你可采用类来访问类属性,如果实例没有同 名的属性的话,你也可以用实例来访问。
访问类属性
访问属性,首先会在实例中去搜索,然后是类,再然后就是从继承树中的基类。
class C: bar = "BAR" c = C() #通过类来访问属性 print(C.bar) #BAR #通过实例来访问属性 print(c.bar) #BAR #只能通过类来更新 C.bar = C.bar + "FOO" print(C.bar) #BARFOO #实例访问它,其值已经改变 print(c.bar) #BARFOO # c.bar = c.bar + "GOO" # print(C.bar) #BAR # print(c.bar) #BARGOO
注意:
任何对实例属性的赋值都会创建一个实例属性(如果不存在的话)并且对其赋值。如果类属性中存在同名的属性,有趣的副作用即产生。
class Bar: x = 1 bar = Bar() print(bar.x) #1 bar.x = 2 print(bar.x) #2 print(Bar.x) #1 #总结:没有变,只是创建了一个新的实例属性,覆盖了对类属行的引用。类属性并没有受到影响 #删除实例属性,仍然能够访问到类属性 del bar.x print(bar.x) #1
总结:
- 如果需要在类外修改
类属性
,必须通过类对象
去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性
,这种方式修改的是实例属性
,不会影响到类属性
,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性
,除非删除了该实例属性
。