如何重写抽象属性方法而又不忘记在子类中添加属性装饰器?

问题描述

如果我重写一个抽象属性方法,我希望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,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)

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

,

您可以将运行时检查放入父级的__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字符串,直接的布尔值或==!=等式比较,它们并不关心它不是字符串。

圆筒的意思是:

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