类属性与实例属性
class C1 :
x = 3 # 类属性
def __init__(self, y=2):
self.y = 2 # 实例属性
调用C1.__dict__
将返回类的属性,类的属性包括描述符对象(如函数)或者任何普通数据对象,其返回值为
mappingproxy({'__module__': '__main__',
'x': 3,
'__init__': <function __main__.C1.__init__(self, y=2)>,
'__dict__': <attribute '__dict__' of 'C1' objects>,
'__weakref__': <attribute '__weakref__' of 'C1' objects>,
'__doc__': None})
创建类的实例c
, 同样调用c.__dict__
,其返回值为
{'y': 2}
类属性可以在类体之外定义,对上述的C1类
C1.z = 23
C1.__dict__
Out[14]:
mappingproxy({'__module__': '__main__',
'x': 3,
'__init__': <function __main__.C1.__init__(self, y=2)>,
'__dict__': <attribute '__dict__' of 'C1' objects>,
'__weakref__': <attribute '__weakref__' of 'C1' objects>,
'__doc__': None,
'z': 23}) # 类中增加z属性
对于包含在类体中的属性,引用类的属性时可以使用简单名称,而在类的方法中需要引用类的属性时,则需要使用完整名称。如下:
class C1 :
x = 3 # 类属性
z = x + 3
def __init__(self, y=2):
f = C1.x + 3
self.y = 2 # 实例属性
当在__init__
中使用简单名称时,会报错如下:
class C1 :
x = 3 # 类属性
z = C1.x + 3
def __init__(self, y=2):
f = x + 3
self.y = 2 # 实例属性
x = C1()
Traceback (most recent call last):
File "<ipython-input-24-d2acc31e39c1>", line 1, in <module>
x = C1()
File "<ipython-input-23-c9b9efa33951>", line 5, in __init__
f = x + 3
NameError: name 'x' is not defined
属性的引用
引用类的属性
对C1.x
- 当x是类
C1.__dict__
中的键时, 从C1.__dict__
中提取值v。如果v是一个描述器,则C1.x的值是调用type(v).__get__(v,None,C)
的结果,否则,C1.x的值为v - 否则,在基类中查找。
引用实例的属性
对c = C1()
, 引用实例c的属性y时,遵循如下的查找顺序
- 如果y是一个数据描述器v,则c.y 的返回值为
type(v).__get__(v,x,C1)
- 如果y在
c.__dict__
中,则返回c.__dict__['y']
的值 - 否则,在基类中查找
描述器的概念:
描述器是实现了__get__
、__set__
、__delete__
三个任意一个方法的类。
如果一个类仅仅实现了__get__()
方法,称为非数据描述器non-data descriptor;
如果一个类实现了__get__()
,__set__()
方法,称为数据描述器data descriptor;
__slots__
方法
python中,对类C的一个实例c
, 存在c.__dict__
, 通过这个字典,可以将任意属性绑定到实例c上。
class C1 :
x = 3 # 类属性
y = 2
def __init__(self):
self.z = 3
c = C1()
c.m=2
c.__dict__
Out[57]: {'z': 3, 'm': 2}
即没有在实例c可以拥有没有在类C中定义的属性。而通过指定__slots__
方法,实例c将不含有__dict__
属性, 试图在实例上绑定不在__slots__
中的属性将会引发异常。
class C1 :
__slots__ = "z"
x = 3 # 类属性
y = 2
def __init__(self):
self.z = 3
c = C1()
c.__dict__
"""
Traceback (most recent call last):
File "<ipython-input-60-dac4a86e0bb3>", line 1, in <module>
c.__dict__
AttributeError: 'C1' object has no attribute '__dict__'
"""
c.m = 2
"""
Traceback (most recent call last):
File "<ipython-input-61-226b97bd737b>", line 1, in <module>
c.m = 2
"""
参考
- 全面解析python类的绑定方法与非绑定方法
- Python技术手册(第2版)