Python描述符与属性[重复]

Posted

技术标签:

【中文标题】Python描述符与属性[重复]【英文标题】:Python descriptor vs property [duplicate] 【发布时间】:2012-10-02 12:06:39 【问题描述】:

可能重复:When and why might I assign an instance of a descriptor class to a class attribute in Python rather than use a property?

我对何时使用属性和描述符感到困惑。我读到一个属性是一个专门的描述符。

有人可以发布这是如何工作的吗?

【问题讨论】:

【参考方案1】:

您应该阅读有关描述符实际是什么的文档。 Cliff's Notes 版本:描述符是一种低级机制,可让您连接到正在访问的对象的属性。属性是对此的高级应用;也就是说,属性是使用描述符实现的。或者,更好的是,属性标准库中已经为您提供的描述符。

如果您需要一种简单的方法来从属性读取返回计算值,或者在属性写入时调用函数,请使用 @property 装饰器。描述符 API 更灵活,但不太方便,并且在这种情况下可以说是“矫枉过正”和非惯用语。它对于更高级的用例很有用,例如实现绑定方法或静态和类方法;例如,当您需要知道属性是通过类型对象还是类型的实例访问时。

【讨论】:

值得注意的是,python 不鼓励使用 getter 和 setter,除非在必要的情况下......或者它可能不会...... @JoranBeasley 与其完全没有必要,不如说是气馁。由于 Python 允许您覆盖属性访问,因此您可以决定在子类中需要它。如果您需要计算属性,则使用 getter 是合适的。在 Java/C# 中,您需要预先决定是否要允许对特定属性的覆盖访问,并在类层次结构的顶部提供此功能。这就是为什么普遍使用属性的原因:这样做是“以防万一”。【参考方案2】:

您可以从here 阅读有关这两个方面的更多信息。但这里有一个来自同一本书的简单例子,它试图解释解决本质上是同一个问题的区别。如您所见,使用属性的实现要简单得多。

有几种方法可以利用 Python 的内部机制来获取和设置属性值。最容易使用的技术是使用属性函数来定义与属性名称关联的 get、set 和 delete 方法。属性函数为您构建描述符。一种稍微不易访问但更可扩展和可重用的技术是自己定义描述符类。这为您提供了相当大的灵活性。为此,您可以创建一个定义 get、set 和 delete 方法的类,并将描述符类与属性名称相关联。

属性函数为我们提供了一种方便的方法来实现一个简单的描述符,而无需定义一个单独的类。而不是创建一个完整的类定义, 我们可以编写getter和setter方法函数,然后将这些函数绑定到一个属性名上。

描述符示例:

class Celsius( object ):
    def __init__( self, value=0.0 ):
        self.value= float(value)
    def __get__( self, instance, owner ):
        return self.value
    def __set__( self, instance, value ):
        self.value= float(value)

class Farenheit( object ):
    def __get__( self, instance, owner ):
        return instance.celsius * 9 / 5 + 32
    def __set__( self, instance, value ):
        instance.celsius= (float(value)-32) * 5 / 9

class Temperature( object ):
    celsius= Celsius()
    farenheit= Farenheit()
>>>
oven= Temperature()
>>>
oven.farenheit= 450
>>>
oven.celsius
232.22222222222223
>>>
oven.celsius= 175
>>>
oven.farenheit
347.0

属性示例:

class Temperature( object ):
    def fget( self ):
        return self.celsius * 9 / 5 + 32
    def fset( self, value ):
        self.celsius= (float(value)-32) * 5 / 9
    farenheit= property( fget, fset )
    def cset( self, value ):
        self.cTemp= float(value)
    def cget( self ):
        return self.cTemp
    celsius= property( cget, cset, doc="Celsius temperature" )
>>>
oven= Temperature()
>>>
oven.farenheit= 450
>>>
oven.celsius
232.22222222222223
>>>
oven.celsius= 175
>>>
oven.farenheit
347.0

【讨论】:

我相信您对摄氏度的描述符实现不正确。您应该将摄氏度设置为instance 而不是self;如果您创建两个温度对象,它们将共享相同的摄氏度值。 我运行了Descriptor example 代码,它运行良好。但我不明白instance.celsius 是如何在Farenheit 类中访问的。谢谢。

以上是关于Python描述符与属性[重复]的主要内容,如果未能解决你的问题,请参考以下文章

Python__new__方法定制属性访问描述符与装饰器

属性与描述符与 __getattribute__ 的用例

限制 C 中的限定符与 LLVM IR 中的 noalias 属性

Java中各种(类方法属性)访问修饰符与修饰符的说明

Java中各种(类方法属性)访问修饰符与修饰符的简单说明

文件描述符与重定向