• Python:高级主题之(属性取值和赋值过程、属性描述符、装饰器)


    属性取值和赋值过程

    • 一切皆是对象,类型也是对象。
    • 对象包含一个__class__属性指向其所属类型。
    • 对象包含一个__dict__属性指向其所包含的成员(属性和方法)。

    取值过程(下面是伪代码)

    复制代码
     1 __getattribute__(property) logic:
     2 
     3 descripter = find first descripter in class and bases's dict(property)
     4 if descripter:
     5     return descripter.__get__(instance, instance.__class__)
     6 else:
     7     if value in instance.__dict__
     8         return value
     9 
    10     value = find first value in class and bases's dict(property)
    11     if value is a function:
    12         return bounded function(value)
    13     else:
    14         return value
    15 
    16 raise AttributeNotFundedException
    复制代码

    赋值过程(下面是伪代码)

    复制代码
    1 __setattr__(property, value)logic:
    2 
    3 descripter = find first descripter in class and bases's dict(property)
    4 if descripter:
    5     descripter.__set__(instance, value)
    6 else:
    7     instance.__dict__[property] = value
    复制代码

    根据取值和赋值过程的逻辑可以得出以下结论

    1. 赋值和取值的位置可能不同。
    2. 取值过程的伪代码第11行会返回绑定方法(我们在Javascript经常会让某个函数绑定到指定的作用域,和这个概念是一样的)。
    3. 取值和赋值过程都会先查找属性描述符,也就是说:属性描述的优先级最高,下文会介绍属性描述符。

    属性描述符

    什么是属性描述符?属性描述符就是一个类型,实现了三个魔法方法而已:__set__、__get__和__del__,属性描述符一般不会独立使用,必须存储在类型的__dict__中才有意义,这样才会参与到属性的取值和赋值过程,具体参见上文。

    属性描述符

    复制代码
    1 #属性描述符
    2 class Descripter:
    3     def __get__(self, instance, owner):
    4         print(self, instance, owner)
    5 
    6     def __set__(self, instance, value):
    7         print(self, instance, value)
    复制代码

    测试代码

    复制代码
     1 class TestClass:
     2     Des = Descripter()
     3 
     4 
     5     def __getattribute__(self, name):
     6         print("before __getattribute__")
     7         return    super(TestClass, self).__getattribute__(name)
     8         print("after __getattribute__")
     9 
    10     def __setattr__(self, name, value):
    11         print("before __setattr__")
    12         super(TestClass, self).__setattr__(name, value)
    13         print("after __setattr__")
    14 
    15 test1 = TestClass()
    16 test2 = TestClass()
    17 
    18 test1.Des = None
    19 test2.Des
    复制代码

    输出结果

    1 before __setattr__
    2 <__main__.Descripter object at 0x01D9A030> <__main__.TestClass object at 0x01D9A090> None
    3 after __setattr__
    4 before __getattribute__
    5 <__main__.Descripter object at 0x01D9A030> <__main__.TestClass object at 0x01D9A0B0> <class '__main__.TestClass'>

    结论

    类型的多个实例共享同一个属性描述符实例,属性描述符的优先级高于实例的__dict__,具体自己可以测试一下。

    装饰器(AOP)

    最基本的函数装饰器

    按 Ctrl+C 复制代码
    按 Ctrl+C 复制代码

    带参数的函数装饰器

    按 Ctrl+C 复制代码
    按 Ctrl+C 复制代码

    最基本的类型装饰器

    按 Ctrl+C 复制代码
    按 Ctrl+C 复制代码

    带参数的类型装饰器

    按 Ctrl+C 复制代码
    按 Ctrl+C 复制代码

    备注:可以使用多个装饰器,不过要保证签名的装饰器也是返回的一个方法或类型。

    自己实现@staticmethod和@classmethod

    理解了属性的取值和赋值过程,开发自定义@staticmethod和@classmethod就不成问题了,let up do it!

    代码

    复制代码
     1 class MyStaticObject:
     2     def __init__(self, fun):
     3         self.fun = fun;
     4 
     5     def __get__(self, instance, owner):
     6         return self.fun
     7 
     8 def my_static_method(fun):
     9     return MyStaticObject(fun)
    10 
    11 class MyClassObject:
    12     def __init__(self, fun):
    13         self.fun = fun;
    14 
    15     def __get__(self, instance, owner):
    16         def class_method(*args, **kargs):
    17             return self.fun(owner, *args, **kargs)
    18 
    19         return class_method
    20 
    21 def my_class_method(fun):
    22     return MyClassObject(fun)
    23 
    24 class C(object):
    25     """docstring for C"""
    26 
    27     def test_instance_method(self):
    28         print(self)
    29 
    30     @staticmethod
    31     def test_static_method(message):
    32         print(message)
    33 
    34     @my_static_method
    35     def test_my_static_method(message):
    36         print(message)
    37 
    38     @classmethod
    39     def test_class_method(cls):
    40         print(cls)
    41 
    42     @my_class_method
    43     def test_my_class_method(cls):
    44         print(cls)
    45 
    46 print("
    实例方法测试")
    47 c = C()
    48 print(C.test_instance_method)
    49 print(C.__dict__["test_instance_method"])
    50 print(c.test_instance_method)    
    51 C.test_instance_method(c)
    52 c.test_instance_method()
    53 
    54 print("
    静态方法测试")
    55 print(C.test_static_method)
    56 print(C.__dict__["test_static_method"])
    57 print(c.test_static_method)
    58 C.test_static_method("静态方法测试")
    59 c.test_static_method("静态方法测试")
    60 
    61 print("
    自定义静态方法测试")
    62 print(C.test_my_static_method)
    63 print(C.__dict__["test_my_static_method"])
    64 print(c.test_my_static_method)
    65 C.test_my_static_method("自定义静态方法测试")
    66 c.test_my_static_method("自定义静态方法测试")
    67 
    68 print("
    类方法测试")
    69 print(C.test_class_method)
    70 print(C.__dict__["test_class_method"])
    71 print(c.test_class_method)
    72 C.test_class_method()
    73 c.test_class_method()
    74 
    75 print("
    自定义类方法测试")
    76 print(C.test_my_class_method)
    77 print(C.__dict__["test_my_class_method"])
    78 print(c.test_my_class_method)
    79 
    80 C.test_my_class_method()
    81 c.test_my_class_method()
    82 
    83 print("
    对象上的方法不会返回绑定方法,对象描述符也不会起作用")
    84 def test(self):
    85     print(self)
    86 
    87 c.test = test
    88 
    89 c.test("测试")
    复制代码

    结果

    复制代码
     1 实例方法测试
     2 <function C.test_instance_method at 0x01D3D8A0>
     3 <function C.test_instance_method at 0x01D3D8A0>
     4 <bound method C.test_instance_method of <__main__.C object at 0x01D8B5B0>>
     5 <__main__.C object at 0x01D8B5B0>
     6 <__main__.C object at 0x01D8B5B0>
     7 
     8 静态方法测试
     9 <function C.test_static_method at 0x01D69108>
    10 <staticmethod object at 0x01D8B4F0>
    11 <function C.test_static_method at 0x01D69108>
    12 静态方法测试
    13 静态方法测试
    14 
    15 自定义静态方法测试
    16 <function C.test_my_static_method at 0x01D69078>
    17 <__main__.MyStaticObject object at 0x01D8B510>
    18 <function C.test_my_static_method at 0x01D69078>
    19 自定义静态方法测试
    20 自定义静态方法测试
    21 
    22 类方法测试
    23 <bound method type.test_class_method of <class '__main__.C'>>
    24 <classmethod object at 0x01D8B530>
    25 <bound method type.test_class_method of <class '__main__.C'>>
    26 <class '__main__.C'>
    27 <class '__main__.C'>
    28 
    29 自定义类方法测试
    30 <function MyClassObject.__get__.<locals>.class_method at 0x01D5EDF8>
    31 <__main__.MyClassObject object at 0x01D8B550>
    32 <function MyClassObject.__get__.<locals>.class_method at 0x01D5EDF8>
    33 <class '__main__.C'>
    34 <class '__main__.C'>
    35 
    36 对象上的方法不会返回绑定方法,对象描述符也不会起作用
    37 测试
  • 相关阅读:
    备忘链接执行js时注意target必须是_self或者_top
    windows2003 Server远程连接Event Error;event id:12517,12503,1111
    网站配置了Url重写的Handler会导致虚拟目录找不到dll
    SEO 搜索引擎优化技巧
    11款开源Wiki管理系统
    收集了几个优秀的设计公司网站
    8款开源聊天系统和程序/Open Chat
    制作Web应用程序安装程序的方法
    转:推荐21套非常棒的网页设计图标素材
    14款开源文档管理系统
  • 原文地址:https://www.cnblogs.com/skying555/p/4973543.html
Copyright © 2020-2023  润新知