我已经尝试了一段时间来理解@property在python中的工作原理。我通过在这个网站上阅读类似的问题来寻找答案,但它仍然与主题相关,我不能把我的手指放在它是如何工作的。例如以下情况:
class MyClass(object):
def __init__(self):
self.name = 'x'
del self.name
@property
def name(self):
return 'y'
my_class = MyClass()
print my_class.name # AttributeError: can't set attribute (self.name = 'x')
为什么这个不行?据我所知,你不能设置一个与现有属性同名的属性,这就是为什么你应该用_
作为前缀,所以在我的情况下是self._name
,但我已经删除了self。name为什么它仍然重要?还是python没有按照我假设的顺序执行?
任何访问__init__
中的self.name
都会与您的属性交互。你没有绕过这个属性。
你的属性没有定义setter或deleter,所以不允许给self.name
赋值或用del self.name
删除。
如果您添加setter或deleter,则__init__
中的代码可以工作:
class MyClass(object):
def __init__(self):
self.name = 'x'
del self.name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
@name.deleter
def name(self):
del self._name
我改变了属性,使用一个不同的实例属性,命名为_name
,以不干扰属性本身。self._name
不是属性,可以直接设置和删除。
完整的技术解释是property
对象是一个描述符对象,并且是一个特定的描述符对象。它是一个数据描述符,这意味着它总是在任何实例属性之前使用。
常规的非数据描述符(如函数、classmethod
和staticmethod
对象)只有__get__
方法。数据描述符还至少定义了__set__
或__delete__
方法。当Python在实例中查找属性时,会进行以下搜索:
- 查找类(和基类)上的数据描述符
- 查找实例 上的属性
- 查找类(和基)的属性,包括非数据描述符。
当您尝试访问self.name
时,您正在寻找self
上的属性。Python在类上查找name
属性,这是一个数据描述符。因此这里使用了第一步,并且使用MyClass.name.__get__(self, MyClass)
(间接)调用name
函数。
当试图分配给self.name
时,MyClass.name.__set__(self, newvalue)
被调用,对于del self.name
, MyClass.name.__delete__(self)
被调用。如果您没有在类中定义setter或deleter函数,则property
对象的默认操作是引发AttributeError
。
属性在__init__
之后不存在-它在__init__
被调用之前已经存在了。当你试图做
self.name = 'x'
你调用name
属性的__set__
, AttributeError
,因为你从来没有定义setter。
当你呼叫
del self.name
你(将)调用name
属性的__delete__
(如果你到达了行)。这也是AttributeError
,因为您没有定义deleter。