Python之路:描述符,类装饰器,元类

Posted __Miracle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python之路:描述符,类装饰器,元类相关的知识,希望对你有一定的参考价值。

python基础之面向对象(描述符、类装饰器及元类)

 

描述符

描述符(__get__,__set__,__delete__)   # 这里着重描述了python的底层实现原理

  1、 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议。
    __get__():调用一个属性时,触发
    __set__():为一个属性赋值时,触发
    __delete__():采用del删除属性时,触发

复制代码
1 class Foo:   #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符
2     def __get__(self,instance,owner):
3         print(\'get方法\')
4     def __set__(self, instance, value):
5         print(\'set方法\')
6     def __delete__(self, instance):
7         print(\'delete方法\')
复制代码

  2、描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

复制代码
class Foo:
    def __get__(self,instance,owner):
        print(\'===>get方法\')
    def __set__(self, instance, value):
        print(\'===>set方法\')
    def __delete__(self, instance):
        print(\'===>delete方法\')

#包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法
f1=Foo()
f1.name=\'egon\'
print(f1.name)
del f1.name
#疑问:何时,何地,会触发这三个方法的执行
复制代码

  3、描述符应用在什么时候,什么地方

复制代码
class D:
    def __get__(self, instance, owner):
        print("-->get")
    def __set__(self, instance, value):
        print("-->set")
    def __delete__(self, instance):
        print("-->delete")
class E:
    e = D() # 描述谁?

ee = E()
ee.y = 10 # 此时描述的是e  y则不会被描述
ee.e      # 访问e属性,则会触发__get__
ee.e = 2  # 为e进行赋值操作,则会触发__set__
del ee.e  # 删除e的属性,则会触发__delete__
# print(ee.__dict__)
复制代码

  4、描述符分为俩种形式。

    a.数据描述符(至少实现了__get__()和__set__()两种方法)

class Foo:
     def __set__(self, instance, value):
         print(\'set\')
     def __get__(self, instance, owner):
         print(\'get\')

    b.非数据描述符(没有实现__set__()方法)

1 class Foo:
2     def __get__(self, instance, owner):
3         print(\'get\')    

      注意事项:
      一、描述符本身应该定义成新式类,被代理的类也应该是新式类
      二、必须把描述符定义成另外一个类触发的类属性,不能为定义到构造函数

  5、严格遵循描述符的优先级别,由高到低

     a.类属性—》b.数据数据描述符—》c.实例属性—》d.非数据描述符—》e.找不到的属性触发__getattr__()

复制代码
 1 class Foo:
 2     def __get__(self,instance,owner):
 3         print(\'===>get方法\')
 4     def __set__(self, instance, value):
 5         print(\'===>set方法\')
 6     def __delete__(self, instance):
 7         print(\'===>delete方法\')
 8 
 9 class Bar:
10     x=Foo()   #调用foo()属性,会触发get方法
11 
12 print(Bar.x)  #类属性比描述符有更高的优先级,会触发get方法
13 Bar.x=1       #自己定义了一个类属性,并赋值给x,跟描述符没有关系,所以不会触发描述符的方法
14 # print(Bar.__dict__)
15 print(Bar.x)
16 
17 
18 ===>get方法
19 None
20 1
复制代码
复制代码
#有get,set就是数据描述符,数据描述符比实例属性有更高的优化级

class Foo:
    def __get__(self,instance,owner):
        print(\'===>get方法\')
    def __set__(self, instance, value):
        print(\'===>set方法\')
    def __delete__(self, instance):
        print(\'===>delete方法\')

class Bar:
    x = Foo()  # 调用foo()属性,会触发get方法

b1=Bar()   #在自己的属性字典里面找,找不到就去类里面找,会触发__get__方法
b1.x       #调用一个属性的时候触发get方法
b1.x=1     #为一个属性赋值的时候触发set方法
del b1.x   #采用del删除属性时触发delete方法

===>get方法
===>set方法
===>delete方法
复制代码
复制代码
 1 #类属性>数据描述符>实例属性
 2 
 3 class Foo:
 4     def __get__(self,instance,owner):
 5         print(\'===>get方法\')
 6     def __set__(self, instance, value):
 7         print(\'===>set方法\')
 8     def __delete__(self, instance):
 9         print(\'===>delete方法\')
10 
11 class Bar:
12     x = Foo()             #调用foo()属性,会触发get方法
13 
14 b1=Bar()                  #实例化
15 Bar.x=11111111111111111   #不会触发get方法
16 b1.x                      #会触发get方法
17 
18 del Bar.x                 #已经给删除,所以调用不了!报错:AttributeError: \'Bar\' object has no attribute \'x\'
19 b1.x
复制代码
复制代码
#实例属性>非数据描述符
class Foo:
    def __get__(self,instance,owner):
        print(\'===>get方法\')

class Bar:
    x = Foo()

b1=Bar()
b1.x=1
print(b1.__dict__)  #在自己的属性字典里面,{\'x\': 1}

{\'x\': 1}
复制代码
复制代码
 1 #非数据描述符>找不到
 2 
 3 class Foo:
 4     def __get__(self,instance,owner):
 5         print(\'===>get方法\')
 6 
 7 class Bar:
 8     x = Foo()
 9     def __getattr__(self, item):
10         print(\'------------>\')
11 
12 b1=Bar()
13 b1.xxxxxxxxxxxxxxxxxxx    #调用没有的xxxxxxx,就会触发__getattr__方法
14 
15 
16 ------------>    #解发__getattr__方法
复制代码

   6、关于描述符的应用(类型检测的应用)

复制代码
class Typed:
    def __get__(self, instance,owner):
        print(\'get方法\')
        print(\'instance参数【%s】\' %instance)
        print(\'owner参数【%s】\' %owner)       # owner是显示对象是属于谁拥有的
    def __set__(self, instance, value):
        print(\'set方法\')
        print(\'instance参数【%s】\' %instance) # instance是被描述类的对象(实例)
        print(\'value参数【%s】\' %value)       # value是被描述的值
    def __delete__(self, instance):
        print(\'delete方法\')
        print(\'instance参数【%s】\'% instance)
class People:
    name=Typed()
    def __init__(self,name,age,salary):
        self.name=name        #触发的是代理
        self.age=age
        self.salary=salary

p1=People(\'alex\',13,13.3)
#\'alex\'             #触发set方法
p1.name             #触发get方法,没有返回值
p1.name=\'age\'       #触发set方法
python 描述符 上下文管理协议 类装饰器 property metaclass

Python 元类与类装饰器

Python - 元类装饰器 - 如何使用 @classmethod

Python 中的纯静态类 - 使用元类、类装饰器还是其他东西?

说说 Python 的元编程

说说 Python 的元编程