在python中何时以及如何使用内置函数property()

在python中何时以及如何使用内置函数property(),python,properties,Python,Properties,在我看来,除了一点语法上的甜点,property()并没有什么用处 当然,能够编写a.b=2而不是a.setB(2),这很好,但是隐藏a.b=2不是一个简单的作业这一事实看起来像是一个麻烦的配方,或者是因为可能会发生一些意外的结果,例如a.b=2实际上会导致a.b成为1。或者引发异常。或者是性能问题。或者只是困惑 你能给我一个具体的例子来说明它的用途吗?(使用它来修补有问题的代码并不重要;-)这样做的目的是让您避免编写getter和setter,直到您真正需要它们为止 所以,首先你要写: cla

在我看来,除了一点语法上的甜点,property()并没有什么用处

当然,能够编写
a.b=2
而不是
a.setB(2)
,这很好,但是隐藏a.b=2不是一个简单的作业这一事实看起来像是一个麻烦的配方,或者是因为可能会发生一些意外的结果,例如
a.b=2
实际上会导致
a.b
成为
1
。或者引发异常。或者是性能问题。或者只是困惑


你能给我一个具体的例子来说明它的用途吗?(使用它来修补有问题的代码并不重要;-)

这样做的目的是让您避免编写getter和setter,直到您真正需要它们为止

所以,首先你要写:

class MyClass(object):
    def __init__(self):
        self.myval = 4
显然,您现在可以编写
myobj.myval=5


但后来,你决定你确实需要一个二传手,因为你想同时做一些聪明的事情。但是你不想改变所有使用你的类的代码,所以你把setter包装在
@property
decorator中,它就可以正常工作了。

一个基本的原因就是它看起来更好。它更像蟒蛇。尤其是图书馆。getValue()看起来没有.value好

在plone(一个相当大的CMS)中,您曾经拥有document.setTitle(),它可以做很多事情,比如存储值、再次索引值等等。只是做document.title='something'更好。你知道在幕后发生了很多事情

但是隐藏a.b=2不是a 简单的作业看起来就像一个食谱 麻烦

但你并没有隐瞒这个事实;这一事实从一开始就不存在。这就是python——一种高级语言;不是组装。其中很少有“简单”语句可以归结为单CPU指令。把简单性理解到作业中,就是去读那些不存在的东西


当你说x.b=c时,你可能只会想“不管发生了什么,x.b现在应该是c了”

在依赖getter和setter的语言中,比如Java,除了他们说的之外,他们不应该也不应该做任何事情——如果
x.getB()
只返回逻辑属性
b
的当前值,或者如果
x.setB(2)
只做了
x.getB()
返回
2
所需的少量内部工作

但是,对于这种预期的行为,没有语言强制的保证,即编译器对名称以
get
set
开头的方法体施加约束:相反,这取决于常识、社会惯例、“样式指南”和测试

在具有属性的语言(包括但不限于Python的一组语言)中,
x.b
访问和赋值(如
x.b=2
)的行为与例如Java中的getter和setter方法完全相同:相同的期望,相同的缺乏语言强制保证

属性的第一个胜利是语法和可读性。必须写作,例如

x.setB(x.getB() + 1)
而不是显而易见的

x.b += 1
呼喊着向众神复仇。在支持属性的语言中,绝对没有很好的理由强迫类的用户经历这种拜占庭式样板文件的循环,从而影响其代码的可读性,没有任何好处

具体地说,在Python中,使用属性(或其他描述符)代替getter和setter还有一个很大的好处:如果并且当您重新组织类以便不再需要底层的setter和getter时,您可以(不破坏类发布的API)简单地消除那些方法和依赖它们的属性,使
b
成为
x
类的普通“存储”属性,而不是通过计算获得和设置的“逻辑”属性

在Python中,直接(在可行的情况下)而不是通过方法进行操作是一项重要的优化,系统地使用属性使您能够在可行的情况下执行此优化(始终直接公开“正常存储的属性”,并且只有那些在通过方法和属性进行访问和/或设置时确实需要计算的属性)

因此,如果您使用getter和setter而不是属性,除了影响用户代码的可读性之外,您还无缘无故地浪费了机器周期(以及在这些周期中流向计算机的能量;-),再次

您反对属性的唯一理由是,例如,“外部用户通常不会期望分配会产生任何副作用”;但您忽略了一个事实,即同一个用户(在诸如Java这样的语言中,getter和setter非常普遍)也不会期望调用setter会产生(可观察到的)“副作用”(对于getter;-),甚至更少。它们是合理的期望值,作为类作者,您可以尝试并适应它们——不管您的setter和getter是直接使用还是通过属性使用,都没有区别。如果您有具有重要可观察副作用的方法,请不要将它们命名为
getThis
setThat
,不要通过属性使用它们


关于属性“隐藏实现”的抱怨是完全没有道理的:OOP的大部分内容都是关于实现信息隐藏——让一个类负责向外部世界展示逻辑接口,并尽可能在内部实现它。getter和setter与属性一样,都是实现这一目标的工具。属性在这方面做得更好(在支持它们的语言中;-)。

这是我的一个老例子。我包装了一个C库,它有“void dt_setcharge(int atom_handle,int new_charge)”和“int dt_getcharge(int atom_handle)”这样的函数
class Atom(object):
    def __init__(self, handle):
        self.handle = handle
    def _get_charge(self):
        return dt_getcharge(self.handle)
    def _set_charge(self, charge):
        dt_setcharge(self.handle, charge)
    charge = property(_get_charge, _set_charge)
class Atom:
    def __init__(self, handle):
        self.handle = handle
    def __getattr__(self, name):
        if name == "charge":
            return dt_getcharge(self.handle)
        raise AttributeError(name)
    def __setattr__(self, name, value):
        if name == "charge":
            dt_setcharge(self.handle, value)
        else:
            self.__dict__[name] = value