如何在不忘记在子类中添加属性装饰器的情况下重写抽象属性方法



如果我重写抽象属性方法,但忘记指定它仍然是子类中的属性方法,我希望Python解释器对我大喊大叫。

class Parent(metaclass=ABCMeta):
@property
@abstractmethod
def name(self) -> str:
pass
class Child(Parent):
@property # If I forget this, I want Python to yell at me.
def name(self) -> str:
return 'The Name'
if __name__ == '__main__':
print(Child().name)

Python真的没有内置的方法来做到这一点吗?我真的必须创建自己的装饰器来处理这种类型的行为吗?

您可以使用metaclass:

class Parent(type):
def __new__(cls, name, bases, body):
if 'name' not in body.keys() or body['name'].__class__.__name__ != 'property':
raise TypeError(f"Can't instantiate class {name} without property name")
return super().__new__(cls, name, bases, body)

class Child(metaclass=Parent):
@property # If I forget this, raise TypeError
def name(self) -> str: # also, name must be implemented
return 'The Name'
if __name__ == '__main__':
print(Child().name)

@property被注释掉时,这会引发一个TypeError: Can't instantiate class Child without property name

您可以在Parent的__init__方法中进行运行时检查,如果name是一个方法,则引发异常。

class Parent(metaclass=ABCMeta):
def __init__(self):
assert not callable(self.name)
@abstractmethod
def name(self) -> str:
pass

class GoodChild(Parent):
@property
def name(self) -> str:
return 'The Name'

class BadChild(Parent):
def name(self) -> str:
return 'Whoops, not a property'

if __name__ == '__main__':
good_child = GoodChild()
print(good_child.name)   # Prints 'The Name'
bad_child = BadChild()   # Raises an AssertionError when initialized

TLDR-在我看来,不值得这么麻烦:

在linting/mypy和单元测试之间,应该涵盖你的大部分需求和类分析/元类的小技巧可能不值得它们带来额外的认知负荷;失败";你的装饰一次,但必须阅读异国情调的脚手架代码,你想做的每一次。

细节-实际用途被标记为什么

if badchild1.name.startswith("John"):将在运行时失败,例如,我希望mypy或pylint也在分析时标记,因为它将是一个方法对象。串联也是如此。唯一真正的监督候选者是f字符串、直接布尔值或==!=相等比较,它们不在乎它不是字符串。

pylint有这样一句话:

test_171_prop.py:11 Method 'name' was expected to be 'property', found it instead as 'method' (invalid-overridden-method)

mypy没有任何问题。

然而,如果我加上这个:

child = Child()
print("name:" + child.name)

然后mypy说:

test_171_prop.py:16: error: Unsupported operand types for + ("str" and "Callable[[], str]")
Found 1 error in 1 file (checked 1 source file)

运行带有两行新行的代码会显示:

TypeError: can only concatenate str (not "method") to str

最新更新