我正在尝试理解 Python 中的元类黑魔法。 AFAIK,例如,可以使用元类来确保在派生类中实现某些方法,但我有一个问题孙子。看来我需要显式实现所有所需的派生方法,即使没有理由(?)这样做。
看看这个:
~ $ ipython
Python 3.6.5 (default, Apr 14 2018, 13:17:30)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.3.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: class Meta(type):
...: def __new__(cls, name, bases, body):
...: if 'some_method' not in body:
...: raise AttributeError('some_method should be implemented')
...: return super().__new__(cls, name, bases, body)
...:
...: class Base(metaclass=Meta):
...: def some_method(self):
...: print('Yay')
...:
...: class Derived(Base):
...: pass
...:
...:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-1-51c072cc7909> in <module>()
9 print('Yay')
10
---> 11 class Derived(Base):
12 pass
<ipython-input-1-51c072cc7909> in __new__(cls, name, bases, body)
2 def __new__(cls, name, bases, body):
3 if 'some_method' not in body:
----> 4 raise AttributeError('some_method should be implemented')
5 return super().__new__(cls, name, bases, body)
6
AttributeError: some_method should be implemented
据我了解,这不应该发生,因为 some_method
应该从 Base
类派生,如下所示:
In [3]: class Base:
...: def some_method(self):
...: print('Yay')
...:
...: class Derived(Base):
...: pass
...:
...:
In [4]: Derived().some_method()
Yay
这是预期的吗?如果是,您能给我一些如何修复此行为的提示,这样我就不需要重新实现方法吗?
最佳答案
您似乎正在尝试重新发明轮子,即 abc
模块及其 @abstractmethod
装饰器。我不确定你为什么要这样做,但如果你这样做,你应该看看 its source (从文档链接)。
您的解决方案检查所需名称是否已在类主体中实现。对于继承的方法则不然,但您似乎知道这一点,所以我不会解释。您想知道的是:您可以做什么?您需要显式检查继承的方法。
abc
的实现方式非常简单:在检查是否所有抽象方法都已实现之前,它会在每个 base
上调用 getattr
。 (毕竟,模拟 getattr
对类执行的操作的最佳方法是调用 getattr
。)在那里找到的任何内容都不需要出现在正文中。
您的用例(使用静态的单个必需方法,而不是必须从装饰器的输出中获取的动态方法集)甚至更简单:
if (not any(hasattr(base, 'some_method') for base in bases)
and 'some_method' not in body):
关于python - 元类 : why method is not inherited from Base class?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50320293/