【问题标题】:Determine if method is still abstract确定方法是否仍然是抽象的
【发布时间】:2018-02-21 23:38:42
【问题描述】:

我有一个带有抽象方法的基类和实现此方法的子类。如何在运行时确定对象中(不检查对象类型或调用方法)该方法是否抽象?

class Base:
    @abc.abstractmethod
    def someAbstractMethod(self):
        raise NotImplementedError("Not implemented yet.")


class Subclass(Base):
    def someAbstractMethod(self):
        some_operations

objects = [Base(),Subclass(),Base(),Subclass(),Subclass(),...]
for object in objects:
    #here I want check if method is still abstract or not

【问题讨论】:

    标签: python python-decorators


    【解决方案1】:

    Python 阻止为具有抽象方法的类创建实例。所以只是你有一个实例意味着你没有抽象方法。

    但是,您必须使用 ABCMeta metaclass 才能正确触发此行为:

    class Base(metaclass=abc.ABCMeta):
        @abc.abstractmethod
        def someAbstractMethod(self):
            raise NotImplementedError("Not implemented yet.")
    

    您也可以从abc.ABC 继承以通过基类获取相同的元类。

    如果您想查看一个 可能列出了哪些抽象方法,请使用__abstractmethods__ 属性;它是一组仍然抽象的所有名称:

    >>> import abc
    >>> class Base(metaclass=abc.ABCMeta):
    ...     @abc.abstractmethod
    ...     def someAbstractMethod(self):
    ...         raise NotImplementedError("Not implemented yet.")
    ...
    >>> class Subclass(Base):
    ...     def someAbstractMethod(self):
    ...         some_operations
    ...
    >>> Base.__abstractmethods__
    frozenset({'someAbstractMethod'})
    >>> Subclass.__abstractmethods__
    frozenset()
    

    @abc.abstractmethod 装饰器所做的只是在函数对象上设置一个__isabstractmethod__ 属性;然后是元类使用这些属性。

    因此,如果您挖掘得太深或正在使用忘记使用 ABCMeta 元类的第三方库,您可以测试这些属性:

    >>> class Base:    # note, no metaclass!
    ...     @abc.abstractmethod
    ...     def someAbstractMethod(self):
    ...         raise NotImplementedError("Not implemented yet.")
    ...
    >>> getattr(Base().someAbstractMethod, '__isabstractmethod__', False)
    True
    

    如果您需要“修复”此类损坏的抽象基类,您需要子类化并混入ABCMeta__abstractmethods__frozenset 添加到您继承自的类中:

    BaseClass.__abstractmethods__ = frozenset(
        name for name, attr in vars(BaseClass).items()
        if getattr(attr, '__isabstractmethod__', False))
    
    class DerivedClass(BaseClass, metaclass=abc.ABCMeta):
        # ...
    

    现在DerivedClass 是一个适当的 ABC 派生类,其中任何抽象方法都可以正确跟踪和执行。

    【讨论】:

    • 是的,这些课程不是我的。非常感谢最后一种方式。
    • @PiotrWasilewicz:您始终可以将元类添加到您自己的派生类中。
    • 我应该创建“子类”类的子类并在那里添加元类吗?
    • @PiotrWasilewicz:我添加了更多说明。
    • 谢谢!这很有帮助。
    【解决方案2】:

    您在这里没有正确使用abc(至少不是打算使用它)。您的Base 类应使用abc.ABCMeta 作为元类,这将防止子类的实例化未实现抽象方法。否则只使用 abc.abstractmethod 装饰器几乎是无用的。

    Python 2.7:

    class Base(object):
        __metaclass__ = abc.ABCMeta
    
        @abc.abstractmethod
        def someAbstractMethod(self):
            # no need to raise an exception here
            pass
    

    Python 3.x

    class Base(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
        def someAbstractMethod(self):
            # no need to raise an exception here
            pass
    

    【讨论】:

    • 我知道,我没有提到这些课程不是我的。不过谢谢。
    猜你喜欢
    • 2012-01-08
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    • 2010-12-18
    • 2020-10-02
    • 2018-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多