Python 2.7 结合 abc.abstractmethod 和 classmethod [英] Python 2.7 Combine abc.abstractmethod and classmethod

查看:31
本文介绍了Python 2.7 结合 abc.abstractmethod 和 classmethod的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在 Python 2.7 中为抽象类方法创建装饰器?

是的,这类似于这个问题,除了我想结合abc.abstractmethodclassmethod,而不是staticmethod.此外,看起来 abc.abstractclassmethod在 Python 3 中添加的(我认为?),但我使用的是 Google App Engine,所以我目前只能使用 Python 2.7

提前致谢.

解决方案

以下是从 Python 3.3 的 abc 模块中的源代码派生的工作示例:

from abc import ABCMeta类抽象类方法(类方法):__isabstractmethod__ = 真def __init__(self, callable):callable.__isabstractmethod__ = Truesuper(abstractclassmethod, self).__init__(callable)类DemoABC:__元类__ = ABCMeta@抽象类方法def from_int(cls, n):返回 cls()类DemoConcrete(DemoABC):@类方法def from_int(cls, n):返回 cls(2*n)def __init__(self, n):打印 '初始化为', n

这是运行时的样子:

<预><代码>>>>d = DemoConcrete(5) # 通过调用具体的 __init__() 成功初始化为 5>>>d = DemoConcrete.from_int(5) # 通过调用一个具体的 from_int() 成功初始化为 10>>>DemoABC() # 失败,因为 from_int() 是抽象的回溯(最近一次调用最后一次):...类型错误:无法使用 from_int 的抽象方法实例化抽象类 DemoABC>>>DemoABC.from_int(5) # 失败,因为 from_int() 没有实现回溯(最近一次调用最后一次):...类型错误:无法使用 from_int 的抽象方法实例化抽象类 DemoABC

请注意,最后一个示例失败了,因为 cls() 不会实例化.ABCMeta 防止未定义所有必需抽象方法的类过早实例化.

在调用 from_int() 抽象类方法时触发失败的另一种方法是让它引发异常:

类DemoABC:__元类__ = ABCMeta@抽象类方法def from_int(cls, n):引发 NotImplementedError

ABCMeta 的设计并没有努力阻止任何抽象方法在未实例化的类上被调用,因此您可以通过调用 cls() 就像类方法通常所做的那样,或者通过引发 NotImplementedError.无论哪种方式,你都会得到一个不错的、干净的失败.

编写一个描述符来拦截对抽象类方法的直接调用可能很诱人,但这与ABCMeta的整体设计不一致(这完全是为了检查所需的方法在实例化之前而不是在调用方法时).

How do I create a decorator for an abstract class method in Python 2.7?

Yes, this is similar to this question, except I would like to combine abc.abstractmethod and classmethod, instead of staticmethod. Also, it looks like abc.abstractclassmethod was added in Python 3 (I think?), but I'm using Google App Engine, so I'm currently limited to Python 2.7

Thanks in advance.

解决方案

Here's a working example derived from the source code in Python 3.3's abc module:

from abc import ABCMeta

class abstractclassmethod(classmethod):

    __isabstractmethod__ = True

    def __init__(self, callable):
        callable.__isabstractmethod__ = True
        super(abstractclassmethod, self).__init__(callable)

class DemoABC:

    __metaclass__ = ABCMeta

    @abstractclassmethod
    def from_int(cls, n):
        return cls()

class DemoConcrete(DemoABC):

    @classmethod
    def from_int(cls, n):
        return cls(2*n)

    def __init__(self, n):
        print 'Initializing with', n

Here's what it looks like when running:

>>> d = DemoConcrete(5)             # Succeeds by calling a concrete __init__()
Initializing with 5

>>> d = DemoConcrete.from_int(5)    # Succeeds by calling a concrete from_int()
Initializing with 10

>>> DemoABC()                       # Fails because from_int() is abstract    
Traceback (most recent call last):
  ...
TypeError: Can't instantiate abstract class DemoABC with abstract methods from_int

>>> DemoABC.from_int(5)             # Fails because from_int() is not implemented
Traceback (most recent call last):
  ...
TypeError: Can't instantiate abstract class DemoABC with abstract methods from_int

Note that the final example fails because cls() won't instantiate. ABCMeta prevents premature instantiation of classes that haven't defined all of the required abstract methods.

Another way to trigger a failure when the from_int() abstract class method is called is to have it raise an exception:

class DemoABC:

    __metaclass__ = ABCMeta

    @abstractclassmethod
    def from_int(cls, n):
        raise NotImplementedError

The design ABCMeta makes no effort to prevent any abstract method from being called on an uninstantiated class, so it is up to you to trigger a failure by invoking cls() as classmethods usually do or by raising a NotImplementedError. Either way, you get a nice, clean failure.

It is probably tempting to write a descriptor to intercept a direct call to an abstract class method, but that would be at odds with the overall design of ABCMeta (which is all about checking for required methods prior to instantiation rather than when methods are called).

这篇关于Python 2.7 结合 abc.abstractmethod 和 classmethod的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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