Python文档(3.8版):
上面的示例定义了只读属性;您还可以通过适当地将一个或多个基础方法标记为抽象来定义读写抽象属性:
class C(ABC):
@property
def x(self):
...
@x.setter
@abstractmethod
def x(self, val):
...
如果仅某些组件是抽象的,则仅需要更新那些组件以在子类中创建具体属性:
from abc import ABC, abstractmethod
class C(ABC):
@property
def x(self):
...
@x.setter
@abstractmethod
def x(self, val):
...
class D(C):
@property
def x(self):
pass
d = D()
预期行为:由于存在未定义的抽象方法而无法实例化
实际行为:实例化而没有错误
为什么这不能实例化?我如何编写此代码,以便在派生类中未实现任何setter的情况下也无法实例化。该文档似乎表明这应该是abstractmethod
的用例。该文档还提供了一个示例,其中getter和setter都是抽象方法,这正是我的目标。
参考:https://docs.python.org/3.8/library/abc.html#abc.abstractproperty
根本上,问题在于,getter和setter只是同一单个类属性的一部分。在@property
x
中,您有fget
,fset
和fdel
组成了获取,设置和删除器(不一定全部设置)。这些可能是抽象的并且阻止了初始化,或者根本不存在。
在class D
中创建一个新的@property
,它会完全覆盖父级@property
,因此不再有任何抽象设置器来阻止初始化该类。
from abc import ABC, abstractmethod
class C(ABC):
@property
def x(self):
pass
@x.setter
@abstractmethod
def x(self, val):
pass
class D(C):
@property
def x(self):
pass
def examine_property(p):
print('get', p.fget, getattr(p.fget, '__isabstractmethod__', False) if p.fget is not None else None)
print('set', p.fset, getattr(p.fset, '__isabstractmethod__', False) if p.fset is not None else None)
print('del', p.fdel, getattr(p.fdel, '__isabstractmethod__', False) if p.fdel is not None else None)
print("C.x:")
examine_property(C.x)
print("D.x:")
examine_property(D.x)
输出:
C.x:
get <function C.x at 0x101ac4550> False
set <function C.x at 0x101ac45e0> True
del None None
D.x:
get <function D.x at 0x101ac4670> False
set None None
del None None
因此,如果要覆盖吸气剂,则需要使用@C.x.getter
对其进行非常详细的说明:
class D(C):
@C.x.getter
def x(self):
print("non-abstract getter")
输出:
C.x:
get <function C.x at 0x1022fb550> False
set <function C.x at 0x1022fb5e0> True
del None None
D.x:
get <function D.x at 0x1022fb670> False
set <function C.x at 0x1022fb5e0> True
del None None
这样,您就不会覆盖整个property
,只是它的特定功能。
我不会混合制作新的properties
和压倒父母,我在测试中看到了这种挑剔的行为:
class D(C):
@property
def x(self):
pass
@C.x.setter
def x(self, val):
pass
print("D.x:")
examine_property(D.x)
输出:
D.x:
get <function C.x at 0x10cdd74c0> False
set <function D.x at 0x10cdd7670> False
del None None
# Our new override property is gone
重新排序的类定义:
class D(C):
@C.x.setter
def x(self, val):
pass
@property
def x(self):
pass
输出:
D.x:
get <function D.x at 0x105048670> False
set None None
del None None
# We entirely lost the `setter`