社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
私信  •  关注

Bicheng

Bicheng 最近创建的主题
Bicheng 最近回复了
7 年前
回复了 Bicheng 创建的主题 » 为什么python中有属性类属性?

我最终通过 Simeon Franklin's excellent presentation 以下内容可作为他讲稿的总结。谢谢他!

要理解属性,首先需要了解描述符,因为属性是由描述符和Python的decorator语法糖实现的。别担心,没那么难。

什么是描述符:

  • 描述符 是实现至少一个名为u get_uuu()、u set_uuu()和uu delete_uuu()的方法的任何对象。

描述符可以分为两类:

  • 数据描述符 实现uu get_uu()和uu set_uu()。
  • 非数据描述符 仅实现uu get_uu()。

根据 python's HowTo :

描述符是具有绑定行为的对象属性,其属性访问被描述符协议中的方法覆盖。

那么什么是描述符协议呢?基本上,它只是说当Python解释器遇到一个属性访问时 obj.attr _¼它将以某种顺序搜索以解决此问题。 .attr 如果这个 attr 是一个描述符属性,那么这个描述符将以这个特定的顺序具有一定的优先级,并且这个属性访问将根据描述符协议被转换成对这个描述符的方法调用,可能会隐藏一个同名实例属性或类属性。更具体地说,如果 阿特尔 是一个数据描述符,那么 对象属性 将转换为此描述符的get方法的调用结果;如果 阿特尔 不是数据描述符并且是实例属性,将匹配此实例属性;如果 阿特尔 不在上面,它是一个非数据描述符,我们得到这个非数据描述符的get方法的调用结果。可以找到有关属性解析的完整规则 here .

现在我们来谈谈财产。如果你看过 Python' descriptor HowTo ,可以找到属性的纯Python版本实现:

class Property(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

显然,属性是一个数据描述符!

@属性只使用python的decorator语法糖。

@property
def attr(self):
    pass

相当于:

attr = property(attr)

所以, 阿特尔 不再是我在问题中发布的实例方法,而是转换为 类属性 按作者所说的装饰句法糖。它是一个描述符对象属性。

它如何有资格成为一个类属性?

好的,我们现在解决了。

然后:

对于任何实例,所有的类属性都应该是相同的,不是吗?

不!

我偷了一个例子 西蒙·富兰克林的精彩演讲 .

>>> class MyDescriptor(object):
...     def __get__(self, obj, type):
...         print self, obj, type
...     def __set__(self, obj, val):
...         print "Got %s" % val
...
>>> class MyClass(object):
...     x = MyDescriptor() # Attached at class definition time!
...
>>> obj = MyClass()
>>> obj.x # a function call is hiding here
<...MyDescriptor object ...> <....MyClass object ...> <class '__main__.MyClass'>
>>>
>>> MyClass.x # and here!
<...MyDescriptor object ...> None <class '__main__.MyClass'>
>>>
>>> obj.x = 4 # and here
Got 4

注意 obj.x 以及它的输出。其输出中的第二个元素是 <....MyClass object ...> . 这是具体的例子 obj . 很快,因为这个属性访问被转换成了一个get方法调用,而这个get方法得到了一个特定的实例参数作为它的方法签名。 descr.__get__(self, obj, type=None) 它可以根据调用它的实例返回不同的值。

注意:我的英文解释可能不够清楚,所以我强烈建议你看一下Simeon Franklin的笔记和Python的描述符Howto。