文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Python的描述符

2023-01-30 23:06

关注

1、描述符的定义

  描述符是与特定属性互相绑定的一种协议,通过方法被触发修改属性,这些方法包括__get__(),__set__(),__delete__().将这些方法定义在类中,即可实现描述符

2、属性与__dict__

  Python中类有属于自己的字典属性,经过类的实例化的对象也同样有自己的字典属性,__dict__

 1 class Foo(object):
 2     x=10
 3     def f(self):
 4         print('f')
 5     def __init__(self,name,id):
 6         self.name=name
 7         self.id=id
 8 f=Foo('alex','1001')
 9 print(Foo.__dict__)
10 print(f.__dict__)
11 {'__module__': '__main__', 'x': 10, 'f': <function Foo.f at 0x000002677119A950>, '__init__': <function Foo.__init__ at 0x000002677119A840>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
12 {'name': 'alex', 'id': '1001'}

 

  

 对象调用属性的方法查找顺序:对象字典,类字典,父类字典,__getattr__方法

3、描述符方法

   __set__(self,instance,value)

   __get__(self,instance,owner)

 __delete__(self,instance)

     #测试self,instance,value,owner各是何方神圣

 1 class Foo:
 2     def __set__(self, instance, value):
 3         print('set')
 4         print(self)
 5         print(instance,value)
 6     def __get__(self, instance, owner):
 7         print('get')
 8         print(self)
 9         print(instance,owner)
10     def __delete__(self, instance):
11         print('delete')
12         print(self)
13         print(instance)
14 class Test:
15     x=Foo()    
16     def __init__(self,y):
17         self.x=y
18 t=Test(10)
19 t.x

#输出结果 20 set 21 <__main__.Foo object at 0x000002D26D10A438> 22 <__main__.Test object at 0x000002D26D10A470> 10 23 get 24 <__main__.Foo object at 0x000002D26D10A438> 25 <__main__.Test object at 0x000002D26D10A470> <class '__main__.Test'>

 

 

  第15行x=Foo()说明x属性被Foo类所代理一般,涉及对x属性的操作可能会触发Foo类中的三个方法,t为Test实例化的对象,触发构造方法init,执行self.x=y(10),实际类属性与实例新增属性x是井水不犯河水,无相关联,但是类属性x是描述符属性,被Foo代理,python解释器会发现实例字典中的x属性名与类属性同名,类属性(描述符)会优先覆盖。对x的操作交给Foo()代理,触发其中的set函数,打印其中self——类Foo类的信息,instance——被代理的对象信息,value——被代理的值被修改。

 第19行对x的属性访问,理所应当,触发其代理的get方法,self——类Foo类的信息,instance——被代理的对象信息,owner——见名知意,被代理属性的最高拥有着,即Test类

其实当一个类中定义了set,get,delete的一个或多个,就可以把这个类称为描述符类。当没有set方法,有其他2个任意或所有时,又被称为非数据描述符。至少有get和set,称为数据描述符

 

  

4、描述符对象是实例属性 

   从上述可知描述符对象是类属性。当描述符对象是实例属性又会怎么样呢?

 

 1 class Foo:
 2     def __set__(self, instance, value):
 3         print('set')
 4         print(instance,value)
 5     def __get__(self, instance, owner):
 6         print('get')
 7         print(instance,owner)
 8     def __delete__(self, instance):
 9         print('delete')
10         print(instance)
11 class Test:
12     x=Foo()
13     def __init__(self):
14         self.y=Foo()
15 t=Test()
16 t.x
17 t.y
#输出 18 get 19 <__main__.Test object at 0x00000175F2FABF28> <class '__main__.Test'>

  咦?为什么只触发了一个get。t.y并没有触发get方法。why???

  因为调用 t.y 时,首先会去调用Test(即Owner)的 __getattribute__() 方法,该方法将 t.y 转化为Test.__dict__['y'].__get__(t, Test), 但是呢,实际上 Test 并没有 y这个属性,y 是属于实例对象的,so,忽略。

5、类描述符对象属性与实例描述符对象属性同名

 1 class Foo:
 2     def __set__(self, instance, value):
 3         print('set')
 4         print(instance,value)
 5     def __get__(self, instance, owner):
 6         print('get')
 7         print(instance,owner)
 8     def __delete__(self, instance):
 9         print('delete')
10         print(instance)
11 class Test:
12     x=Foo()
13     def __init__(self):
14         self.x=Foo()
15 t=Test()
16 t.x
17 -----------------------------------------------------
18 get
19 <__main__.Test object at 0x00000246E4ACBF28> <class '__main__.Test'>

大家应该会想,实例属性通过__getattribute__()已经在自己字典中可以找到x,为什么还会触发get方法?

  这涉及到优先级的顺序问题,当解释器发现实例字典中有与描述符属性同名的属性时,描述符优先与实例属性,会覆盖掉实例属性。可以通过类字典验证

1 print(Test.__dict__)
2 -------------
3 {'__module__': '__main__', 'x': <__main__.Foo object at 0x000002757C138550>, '__init__': <function Test.__init__ at 0x000002757C1DA9D8>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None}

x所对应的value值是其本类对象,而t.__dict__则是个空字典。

 

 6、描述符优先级别顺序

  上面已经提到,当无set方法的描述符称为非数据描述符,有set和get为数据描述符。这2者有啥区别?优先级别的大区别!!!

  类属性>>>数据描述符>>>实例属性>>>>非数据属性>>>>找不到此属性即__getattribute__`  

 

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯