我有一个带有abstractmethod和子类的基类来实现这个方法。如何在运行时确定对象(不检查对象类型或调用方法)该方法是否抽象?
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
答案 0 :(得分:7)
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__
冻结集添加到你的类中继承自:
BaseClass.__abstractmethods__ = frozenset(
name for name, attr in vars(BaseClass).items()
if getattr(attr, '__isabstractmethod__', False))
class DerivedClass(BaseClass, metaclass=abc.ABCMeta):
# ...
现在DerivedClass
是一个正确的ABC派生类,可以正确跟踪和处理任何抽象方法。
答案 1 :(得分:4)
您在这里没有正确使用abc
(因为它至少不打算使用)。您的Base
类应该使用abc.ABCMeta
作为元类,这将阻止实现不实现abstractmethods的子类的实例化。否则只使用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