zoukankan      html  css  js  c++  java
  • python描述符理解

    Python中的描述符是一个相对底层的概念

    descriptor
    Any object which defines the methods get(), set(), or delete(). When a class attribute is a descriptor, its special binding behavior is triggered upon attribute lookup. Normally, using a.b to get, set or delete an attribute looks up the object named b in the class dictionary for a, but if b is a descriptor, the respective descriptor method gets called. Understanding descriptors is a key to a deep understanding of Python because they are the basis for many features including functions, methods, properties, class methods, static methods, and reference to super classes. For more information about descriptors’ methods, see Implementing Descriptors.

    描述符
    任何实现了__get__(), __set__(), 或者 __delete__()方法的对象就是描述符。一个class的属性是一个描述符的时候,对这个属性的访问会触发特定的绑定行为。一般的我们使用a.b的方式访问,修改和删除属性,它通过查找class的字典来访问属性b,当时如果b是一个描述符,那么get,set和delete相关的描述符方法会被调用。理解描述符是深入理解python的关键,因为描述符是很多特性实现的基础,比如:方法,函数,属性,类方法,静态方法还有对父类方法的引用。详细的说明请看描述符的实现。--CooMark译

    极客学院 - 描述符
    Python方法绑定——Unbound/Bound method object的一些梳理
    http://www.it165.net/pro/html/201406/15171.html - 最后总结的很好

    在说描述符之前,先看一小段代码:

    class Foo(object):
        """docstring for Foo"""
    
        def __init__(self, arg=''):
            super(Foo, self).__init__()
            self.arg = arg
    
        def foo(self):
            print(self)
            print('foo:', 123)
    
    
    print(Foo.foo)
    
    print(Foo().foo)
    
    print(Foo.foo.__get__)
    
    # 输出
    # <function Foo.foo at 0x00550738>
    # <bound method Foo.foo of <__main__.Foo object at 0x0054DB10>>
    # <method-wrapper '__get__' of function object at 0x00550738>
    

    主要想说的是这个__get__,他是一个method-wrapper。每次调用一个方法,其实都是调用这个__get__构造的method对象。我们定义的方法其实都是descriptor,它通过__get__控制了对相应method的访问

    def __get__(self, instance, owner)
    Foo.foo -- Foo.__dict__['foo'].__get__(None,Foo) # 隐式传递的self是Foo class对象, 一切皆对象,class在模块级别中也有instance
    

    下面三种方式的调用输出的结果是一样的,这个None咋来的呢?,有一点可以确认:self都是class对象实例

    # 两种访问方式是一样的
    print(Foo.foo.__get__(Foo(), Foo)())
    print(Foo.__dict__['foo'].__get__(Foo(), Foo)())
    
    c = Foo()
    print(Foo.foo.__get__(c, Foo)())
    
    # <__main__.Foo object at 0x0032DB10>
    # foo: 123
    # None
    # <__main__.Foo object at 0x0032DB10>
    # foo: 123
    # None
    # <__main__.Foo object at 0x0032DB70>
    # foo: 123
    # None
    

    再说说bound method和unbound method

    区分依据就是是否给method绑定了实例对象,也就是调用的时候是否会隐式传递self参数

    print(Foo.foo)
    # 当时3.0之后不再叫unbound method,因为定义为function更贴切
    # <function Foo.foo at 0x006406F0>
    
    print(Foo().foo)
    # <bound method Foo.foo of <__main__.Foo object at 0x0063DB30>>
    

    描述符

    我们定义的属性,方法其实都是描述符,只不过我们习以为常,而没有刻意的去了解背后的机制

    class Bar(object):
        """docstring for Bar"""
        _name = 'Mark Xiao'
    
        def __init__(self, arg=''):
            super(Bar, self).__init__()
            self.arg = arg
            self._name = 'CooMark'
    
        def _get_name(self):
            return self._name
    
        def _set_name(self, value):
            self._name = value
    
        def _del_name(self):
            del self._name
    
        name = property(_get_name, _set_name, _del_name, 'description of property name')
    
    print(Bar.name)
    print(Bar().name)
    
    # <property object at 0x004FBAE0>
    # CooMark
    

    描述符协议:

    __get__(self, instance, owner) --> return value
    __set__(self, instance, value)
    __delete__(self, instance)
    

    描述符对象以类型 (owner class) 成员的方式出现,且最少要实现一个协议方法。最常见的描述符有 property、staticmethod、classsmethod。访问描述符类型成员时,解释器会自动调用与行为相对应的协议方法。

    1. 实现 get 和 set 方法,称为 data descriptor。
    2. 仅有 get 方法的,称为 non-data descriptor。
    3. get 对 owner_class、owner_instance 访问有效。
    4. set、delete 仅对 owner_instance 访问有效。

    instance method, class method, static method

    实例方法bound到instance
    类方法bound到class
    静态方法没有绑定,仅仅是个方法

    总结

    描述符是一种协议,实现了相应的描述符方法便会有相应的描述符行为,property就是一个特定的描述符类型,我们可以自己实现类似的功能

  • 相关阅读:
    软件工程第1次阅读作业
    centOS 7设置静态IP,使用Xshell远程连接
    jmeter响应结果乱码问题
    Jmeter环境搭建详细介绍
    redis常用操作命令集合
    cocoapod 快速更新,加载
    获取验证码倒计时
    支持向量机SVM(Support Vector Machine)
    Ensemble Learning: Bootstrap aggregating (Bagging) & Boosting & Stacked generalization (Stacking)
    Eureka安全下线服务
  • 原文地址:https://www.cnblogs.com/wancy86/p/descriptor.html
Copyright © 2011-2022 走看看