使用@property定义内置的python属性时,如果属性对象已重载(具有相同的名称),则该属性对象如何将setter与getter方法区分开?
class A:
def __init__(self):
self._x = 12
@property
def x(self) -> int:
return self._x
@notifiable # strangely this stacks on both setter and getter
@x.setter
def x(self, val: int):
self._x = val
如果定义了自定义属性装饰器,请说:
class my_property:
def __init__(self, getter):
print("__init__ getter %s:" % getter)
def setter(self, setter: FunctionType):
print("setter: %s" % setter)
class B:
def __init__(self):
self._val = 44
@my_property
def x(self):
return self._val
@x.setter
def x(self, val):
self._val = val
执行代码将导致以下输出
__init__ getter <function B.x at 0x7ff80c5e1620>:
setter: <function B.x at 0x7ff80c5e1620>
传递给装饰器的getter和setter函数是相同的函数,但是它们应该是不同的功能。
如果我使用这样的注释:
class C:
def __init__(self):
self._val = 44
@my_property
def x(self):
return self._val
@x.setter
def set_x(self, val):
self._val = val
按预期打印了不同的功能。
__init__ getter <function C.x at 0x7f529132c6a8>:
setter: <function C.set_x at 0x7f529132c6a8>
python如何使用内置的@property解决此问题?装饰器与用户装饰器的处理方式不同吗?
答案 0 :(得分:1)
之所以看到这里的内容,是因为您没有在任何地方引用getter。这意味着一旦__init__
方法结束,就不再引用第一个B.x(即refcount为零),因此该函数被释放。由于原始的getter函数已经发布,因此Python可以自由地将完全相同的内存地址重用于另一个对象/函数,在这种情况下就是这种情况。
如果您修改my_property以保留对原始getter方法的引用,例如:
class my_property:
def __init__(self, getter):
print("__init__ getter %s:" % getter)
self.getter = getter
def setter(self, setter: FunctionType):
print("setter: %s" % setter)
您将看到函数名称(Bx)仍然相同(没关系,因为python不使用函数名称来唯一标识一个函数),但是两个函数的内存地址不同:
__init__ getter <function B.x at 0x7f9870d60048>
setter: <function B.x at 0x7f9870d600d0>
装饰器与用户装饰器的处理方式不同吗?
不,属性只是一个普通的装饰器。但是,如果您想重新实现属性装饰器,您可能会对descriptor protocol感兴趣(该页面中有@property的纯python重新实现)。