Python 2.6、3抽象基类的误解 [英] Python 2.6, 3 abstract base class misunderstanding

查看:104
本文介绍了Python 2.6、3抽象基类的误解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我使用ABCMeta和abstractmethod时,我没有看到期望的结果。

I'm not seeing what I expect when I use ABCMeta and abstractmethod.

在python3中可以正常工作:

This works fine in python3:

from abc import ABCMeta, abstractmethod

class Super(metaclass=ABCMeta):
    @abstractmethod
    def method(self):
        pass

a = Super()
TypeError: Can't instantiate abstract class Super ...

并且在2.6中:

class Super():
    __metaclass__ = ABCMeta
    @abstractmethod
    def method(self):
         pass

a = Super()
TypeError: Can't instantiate abstract class Super ...

如果我从对象派生Super,它们也都可以正常工作(我得到了预期的例外),除了ABCMeta。

They both also work fine (I get the expected exception) if I derive Super from object, in addition to ABCMeta.

如果我从列表中派生Super,它们都会失败(没有例外)。

They both "fail" (no exception raised) if I derive Super from list.

我希望抽象基类是列表,但抽象,并且具体在子类中。

I want an abstract base class to be a list but abstract, and concrete in sub classes.

我做错了,还是不应该在python中这样做?

Am I doing it wrong, or should I not want this in python?

推荐答案

使用 Super 的构建方式与您的工作摘要相同,当您执行 Super()时所调用的是:

With Super build as in your working snippets, what you're calling when you do Super() is:

>>> Super.__init__
<slot wrapper '__init__' of 'object' objects>

如果 Super 继承自 list ,称为 Superlist

>>> Superlist.__init__
<slot wrapper '__init__' of 'list' objects>

现在,抽象基类可以用作 mixin 类,可以与具体类一起从(以获取ABC可能提供的模板方法设计模式功能)一起继承(而不使生成的子孙抽象)。因此请考虑:

Now, abstract base classes are meant to be usable as mixin classes, to be multiply inherited from (to gain the "Template Method" design pattern features that an ABC may offer) together with a concrete class, without making the resulting descendant abstract. So consider:

>>> class Listsuper(Super, list): pass
... 
>>> Listsuper.__init__
<slot wrapper '__init__' of 'list' objects>

看到问题了吗?根据多重继承的规则,调用 Listsuper()(由于存在悬空的抽象方法而不允许不允许失败)运行的代码与调用 Superlist()(您要失败)。实际上,该代码( list .__ init __ )不会反对悬挂抽象方法-仅 object .__ init__ 可以。并修复该问题可能会破坏依赖于当前行为的代码。

See the problem? By the rules of multiple inheritance calling Listsuper() (which is not allowed to fail just because there's a dangling abstract method) runs the same code as calling Superlist() (which you'd like to fail). That code, in practice (list.__init__), does not object to dangling abstract methods -- only object.__init__ does. And fixing that would probably break code that relies on the current behavior.

建议的解决方法是:如果要使用抽象基类,则所有基类都必须是抽象的。因此,与其在基础中没有具体的列表,而是将其用作基础集合。MutableSequence,添加一个 __ init __ 产生 ._ list 属性,并实现 MutableSequence 的摘要直接委派给 self._list 的方法。不完美,但也不是那么痛苦。

The suggested workaround is: if you want an abstract base class, all its bases must be abstract. So, instead of having concrete list among your bases, use as a base collections.MutableSequence, add an __init__ that makes a ._list attribute, and implement MutableSequence's abstract methods by direct delegation to self._list. Not perfect, but not all that painful either.

这篇关于Python 2.6、3抽象基类的误解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆