浅谈Python中的描述符(Descriptor)

简单点

1
2
3
4
5
6
7
8
class Descriptor:
def __get__(self, instance, owner):
print('__get__ called. '
class foo:
t = Descriptor()
if __name__ == '__main__':
c = foo()
c.t #print __get__ called.

详细点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import types
class Descriptor:
def __call__(self, *args, **kwargs):
print('Descriptor called')
def __get__(self, instance, owner):
if instance is not None:
print('__get__ called. ' + 'instance is ' + str(instance) + '; owner is ' + str(owner))
return types.MethodType(self, instance)
else:
print('__get__ called. ' + 'instance is ' + str(instance) + '; owner is ' + str(owner))
return self
def __set__(self, instance, value):
print('set ' + str(instance) + ';value: ' + str(value))
class foo:
t = Descriptor()
class bar:
def __init__(self):
self.t=Descriptor()
if __name__ == '__main__':
c = foo()
print('test 1')
# 相当于foo.__dict__['t'].__get__(None, foo)
foo.t
print('test 2')
# 相当于foo.__dict__['t'].__get__(t, foo)
c.t
print('test 3')
c.t()
print('test 4')
c.t = 1
print('test 5')
d=bar()
d.t
'''
test 1
__get__ called. instance is None; owner is <class '__main__.foo'>
test 2
__get__ called. instance is <__main__.foo object at 0x00000273839F4320>; owner is <class '__main__.foo'>
test 3
__get__ called. instance is <__main__.foo object at 0x00000273839F4320>; owner is <class '__main__.foo'>
Descriptor called
test 4
set <__main__.foo object at 0x00000273839F4320>;value: 1
test 5
'''

有什么用

如果想创建一个新形式的实例属性,可以以描述符类的形式定义其功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Integer:
def __init__(self, name):
self.name = name
def __get__(self, instance, cls):
if instance is None:
return self
else:
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise TypeError('Expected an int')
instance.__dict__[self.name] = value
def __delete__(self, instance):
del instance.__dict__[self.name]
class Point:
x = Integer('x')
y = Integer('y')
def __init__(self, x, y):
self.x = x
self.y = y
if __name__ == '__main__':
p = Point(2, 3)
print(p.x) # calls Point.x.__get__(p,Point)
p.y = 5
try:
p.x = 2.3
except TypeError as e:
print(e)

如果仅仅是像访问某个特定类中的一个属性,并对此做定制化处理,直接用property更加简单。
在需要大量重用代码的情况下,描述符更加有用。

文章目录
  1. 1. 简单点
  2. 2. 详细点
  3. 3. 有什么用
|