3

在解释属性的文档中,据说:

确保为附加函数提供与原始属性相同的名称(在本例中为 x。)

即,getter、setter 和 deleter 方法都必须具有相同的名称。

为什么?而且,Python 禁止方法重载,不是吗?

编辑:为什么以下代码在 Python 2.6 中运行时会失败?

class Widget(object):
    def __init__(self, thing):
        self.thing = thing
        print self.thing

    @property
    def thing(self):
        return self._thing

    @thing.setter
    def set_thing(self, value):
        self._thing = value


if __name__ == '__main__':
    Widget('Some nonsense here')  

它的输出是:

 Traceback (most recent call last):   
 File "widget.py", line 16, in <module>
     Widget('Some nonsense here')     
 File "widget.py", line 3, in __init__
     self.thing = thing 
 AttributeError: can't set attribute

当 set_thing() 重命名为 thing() 时,代码可以正常工作。

4

2 回答 2

6

Python 确实不具有方法重载功能,但您是正确的,文档鼓励您以相同的方式命名 getter 和 setter,并演示它以启动。这里发生了什么?

诀窍是了解方法装饰器在 Python 中是如何工作的。每当你看到这样的东西:

@foo
def bar():
    frob()
    quux()

Python 在幕后实际上所做的就是以这种方式重写它:

def bar():
    frob()
    quux()
bar = foo(bar)

换句话说:定义一个函数bar,然后将其替换为调用foo bar 函数的结果。

虽然这都是正确的,但在解析名称时,评估顺序实际上与上述顺序略有不同。你可能更容易假装实际发生的事情看起来更接近这个:

def __secret_internal_function_name__():
    frob()
    quux()
bar = foo(__secret_internal_function_name__)

为什么这很重要?让我们看一下该文档链接中的 Python:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

让我们用我们现在知道的来重写它,以了解 Python 实际在做什么:

class C(object):
    def __init__(self):
        self._x = None

    def __secret_x_prop__(self):
        """I'm the 'x' property."""
        return self._x
    x = property(__secret_x_prop__)

    def __secret_x_setter__(self, value):
        self._x = value
    x = x.setter(__secret_x_setter__)

    def __secret_x_getter__(self):
        del self._x
    x = x.deleter(__secret_x_getter__)

现在,我们实际上可以看到发生了什么:我们没有重载函数;我们正在逐步构建一个property引用其他函数的对象。

还值得注意的是,根据您创建属性的方式,名称不需要匹配。具体来说,如果您使用property函数显式创建属性,如文档中的第一个示例中所做的那样,则名称可以是您想要的任何名称;该示例将它们称为getx,setxdelx, 并且工作正常。在我假设的安全预防措施中,property.setter,property.deleter确实要求传递的函数具有相同的名称,但它们在幕后做的事情与更明确的property示例相同。

于 2012-10-04T15:16:54.700 回答
1

在解释属性的文档中,据说:

不正确。那是解释使用属性名称作为装饰器一部分的文档。以“经典”方式创建属性时,方法可以具有所需的任何名称。

而且由于装饰器正在拦截方法创建,因此没有重载。

于 2012-10-04T15:06:15.720 回答