python描述器_python中的描述器

描述器和装饰器是两个不同的东西,描述器是类中封装了__set__(), __get__(), __delete__()等魔术方法。

python中的属性、实例方法、静态方法、类方法、super都是基于描述器实现的

python中默认的对属性的访问控制是从对象字典__dict__中进行封装的,以obj.x举例,它的默认查找顺序是

先查找实例的__dict__即obj.__dict__[‘x’]

若查找不到,再查找type(obj).__dict__[‘x’]

若查找不到,最后查找type(obj)的父类(不包括__metaclass__)

但是当定义了描述器时,python就会调用描述器的方法来重写默认的控制行为

描述器的分类

资料描述器:同时定义了__set__(),和__get__()方法

非资料描述器:仅定义了__get__()方法

它们的区别在于:主要区别在于实例字典的优先级上。如果访问的属性在字典实例中且是资料描述器那么以资料描述器的为主,否则若是非资料描述器则以实例字典的为主。

与__setattr__(),__getattr__(),__getattribute__()的关系

__setattr__()的优先级高于描述器的__set__()的方法

如果属性已经定义了那么不会再执行__getattr__()了,而是直接通过访问实例字典返回结果,但如果存在描述器则走描述器的__get__()方法,__getattr__()只在访问未定义的属性时被触发

__getattribute__():在调用类方法,字典__dict__属性时会通过访问此魔术方法实现,如果同一个类中也封装了__setattr__()且操作了self.__dict__那么将会陷入无限循环

描述器的调用也是因为__getattribute__(),当重写了__getattribute__()时会阻止描述器的调用

实例

描述器的基本使用

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

26class (object):

'''Descriptor for a meter.'''

def __init__(self, value=0.0):

self.value = float(value)

def __get__(self, instance, owner):

return self.value

def __set__(self, instance, value):

self.value = float(value)

class Foot(object):

'''Descriptor for a foot.'''

def __get__(self, instance, owner):

return instance.meter * 3.2808

def __set__(self, instance, value):

instance.meter = float(value) / 3.2808

class Distance(object):

meter = Meter()

foot = Foot()

d = Distance()

print(d.meter, d.foot)

d.meter = 1

print(d.meter, d.foot) # 1.0 3.2808

d.meter = 2

print(d.meter, d.foot) # 2.0 6.5616

存在__setattr__()时的资料描述器

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

29class (object):

'''Descriptor for a meter.'''

def __init__(self, value=0.0):

self.value = float(value)

def __get__(self, instance, owner):

return self.value

def __set__(self, instance, value):

self.value = float(value)

class Foot(object):

'''Descriptor for a foot.'''

def __get__(self, instance, owner):

return instance.meter * 3.2808

def __set__(self, instance, value):

instance.meter = float(value) / 3.2808

class Distance(object):

meter = Meter()

foot = Foot()

def __setattr__(self, name, value):

print("__setattr__")

self.__dict__[name] = value

d = Distance()

print(d.meter, d.foot)

d.meter = 1

print(d.meter, d.foot)

d.meter = 2

print(d.meter, d.foot)

输出:1

2

3

4

50.0 0.0

__setattr__

0.0 0.0

__setattr__

0.0 0.0

由于资料描述器的__get__()优先级高于实例字典,故会一致访问资料描述器的值,__setattr__()的优先级高于描述器的__set__()所以更新的是实例字典的值

存在__setattr__()时的非资料描述器

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

26class (object):

'''Descriptor for a meter.'''

def __init__(self, value=0.0):

self.value = float(value)

def __get__(self, instance, owner):

return self.value

class Foot(object):

'''Descriptor for a foot.'''

def __get__(self, instance, owner):

return instance.meter * 3.2808

class Distance(object):

meter = Meter()

foot = Foot()

def __setattr__(self, name, value):

print("__setattr__")

self.__dict__[name] = value

d = Distance()

print(d.meter, d.foot)

d.meter = 1

print(d.meter, d.foot)

d.meter = 2

print(d.meter, d.foot)

输出1

2

3

4

50.0 0.0

__setattr__

1 3.2808

__setattr__

2 6.5616

实例字典的优先级高于非资料描述器

Refrence

[1] https://pyzh.readthedocs.io/en/latest/Descriptor-HOW-TO-Guide.html#id11

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值