<p>让我们从“@decorator”语法开始。实际上只是语法上的甜点,所以</p>
<pre><code>@decorate
def myfunc():
pass
</code></pre>
<p>只是一个简写</p>
^{pr2}$
<p>请注意,python函数也是对象(以及类和模块FWIW),因此您可以将函数作为参数传递给其他函数、从函数返回函数、将函数存储为变量或属性等</p>
<p>现在有了<code>property</code>类(是的,它是一个类):它只是<a href="https://docs.python.org/2/howto/descriptor.html" rel="nofollow noreferrer">the ^{<cd2>} protocol</a>的通用实现,这是python支持计算属性的机制。在</p>
<p>一个简单的python实现<code>property</code>通常类似于(我忽略了<code>fdel</code>和{<cd5>}部分):</p>
<pre><code>class propertytype(type):
# this is what will allow you
# to use `property` as decorator,
# it will return a new `property` instance
# with `func` as setter
def __call__(cls, func):
return cls(func)
class property(metaclass=propertytype):
def __init__(self, fget, fset=None):
self.fget = fget
self.fset = fset
# this is the getter
def __get__(self, instance, cls=None):
if instance is None:
return self
return self.fget(instance)
# this is the setter (if there's one)
def __set__(self, instance, value):
if not self.fset:
raise AttributeError("Attribute is read-only")
self.fset(instance, value)
# and this allows you to use`@myprop.setter`
# in your class definition
def setter(self, func):
self.fset = func
return self
</code></pre>
<p>最后:虽然在初始值设定项(方法<code>__init__</code>方法)中创建一个对象的所有实例属性是一个很好的做法,但实际上您可以随时随地设置现有的或新的属性。除了一些类型(主要是出于实现原因)使用完全不同的方法存储属性(如果您想了解更多信息,可以查找<code>slots</code>),普通Python对象主要是伪装的dict,因此<code>myobj.foo = 'bar'</code>通常只将<code>'bar'</code>存储在<code>self.__dict__['foo']</code>中。当然,如果不使用计算属性;)</p>
<p>好了,现在我们有了构建块,让我们分析一下你的类发生了什么:</p>
<pre><code>class P:
# let's ignore the initializer for now
@property
def x(self):
return self.__x
@x.setter
def x(self, x):
if x < 0:
self.__x = 0
else:
self.__x = x
</code></pre>
<p>这可以改写为</p>
<pre><code>class P:
# let's ignore the initializer for now
def _getx(self):
return self.__x
def _setx(self):
if x < 0:
self.__x = 0
else:
self.__x = x
x = property(_getx, setx)
</code></pre>
<p>所以现在</p>
<pre><code>p = P()
</code></pre>
<p>当我们这样做时:</p>
<pre><code>p.x = 5
</code></pre>
<p>属性解析规则(在<code>object.__setattr__(self, name, value)</code>中实现)将实际查找“p”上的“x”,找到我们的“x”属性,并且由于它是一个绑定描述符(它有一个<code>__set__</code>方法),因此调用<code>x.__set__(p, 5)</code>(cf<code>self.fset(p, 5)</code>(cf<code>property.__set__()</code>定义),它将调用<code>p._setx(5)</code>。在</p>
<p>如果我们拿回初始值:</p>
<pre><code>class P:
def __init__(self, x):
self.x = x
# getter / setter / property definition here
</code></pre>
<p>然后,非常精确的事情发生了(除了<code>P</code>实例被命名为<code>self</code>而不是{<cd19>}),它实际上最终调用了<code>P._setx(self, x)</code>。在</p>
<p>与原始实现的唯一区别是使用<code>property</code>有一个修饰符,getter和setter函数不成为类的方法,它们只作为<code>x</code>属性对象的<code>fget</code>和{<cd23>}属性存在。在</p>