<p>到了2018年,我们应该得到更好的解决方案:</p>
<pre><code>from better_abc import ABCMeta, abstract_attribute # see below
class AbstractFoo(metaclass=ABCMeta):
@abstract_attribute
def bar(self):
pass
class Foo(AbstractFoo):
def __init__(self):
self.bar = 3
class BadFoo(AbstractFoo):
def __init__(self):
pass
</code></pre>
<p>它的行为如下:</p>
<pre><code>Foo() # ok
BadFoo() # will raise: NotImplementedError: Can't instantiate abstract class BadFoo
# with abstract attributes: bar
</code></pre>
<p>这个答案使用与公认答案相同的方法,但与内置的ABC很好地集成,不需要<code>check_bar()</code>helpers的样板。</p>
<p>以下是<code>better_abc.py</code>内容:</p>
<pre><code>from abc import ABCMeta as NativeABCMeta
class DummyAttribute:
pass
def abstract_attribute(obj=None):
if obj is None:
obj = DummyAttribute()
obj.__is_abstract_attribute__ = True
return obj
class ABCMeta(NativeABCMeta):
def __call__(cls, *args, **kwargs):
instance = NativeABCMeta.__call__(cls, *args, **kwargs)
abstract_attributes = {
name
for name in dir(instance)
if getattr(getattr(instance, name), '__is_abstract_attribute__', False)
}
if abstract_attributes:
raise NotImplementedError(
"Can't instantiate abstract class {} with"
" abstract attributes: {}".format(
cls.__name__,
', '.join(abstract_attributes)
)
)
return instance
</code></pre>
<p>好在你可以做到:</p>
<pre><code>class AbstractFoo(metaclass=ABCMeta):
bar = abstract_attribute()
</code></pre>
<p>工作原理同上。</p>
<p>也可以使用:</p>
<pre><code>class ABC(ABCMeta):
pass
</code></pre>
<p>定义自定义ABC助手。另外,我认为这个代码是CC0。</p>
<p>这可以通过使用AST解析器通过扫描<code>__init__</code>代码来提高早期(在类声明上)的性能,但目前看来这是一个过度的牺牲(除非有人愿意实现)。</p>