问题描述
我试图让我意识到我不需要一直使用所有方法装饰器 @abstractmethod
首先,我实现了类装饰器,但这不需要任何结果:
from abc import ABC,abstractmethod
def interface(cls):
for attr in cls.__dict__:
if callable(getattr(cls,attr)):
setattr(cls,attr,abstractmethod(getattr(cls,attr)))
return cls
@interface
class A(ABC):
def foo(self):
pass
def bar(self):
pass
class B(A):
def foo(self):
pass
b = B()
其次,我尝试在类中的 __init__
方法中创建它,但它也没有给出任何结果:
class Interface(ABC):
def __init__(self):
for attr in self.__dict__:
attr_obj = getattr(self,attr)
if callable(attr_obj):
setattr(self,abstractmethod(attr_obj))
class A(Interface):
def __init__(self):
super().__init__()
def foo(self):
pass
def bar(self):
pass
class B(A):
def foo(self):
pass
b = B()
如何实现类中所有方法都用 @abstractmethod
修饰的方法?
解决方法
就像@juanpa.arrivillaga 提到的那样,在类实例化之后再装饰抽象类为时已晚,因为 ABC
使用其元类 ABCMeta
更改了其类成员。
相反,您可以子类化 ABCMeta
(如下例中的 Interface
)并在调用超类的构造函数。
由于子类在默认情况下应该实现抽象方法,并且在典型情况下不会继续声明抽象方法,因此您应该避免使用classdict
来装饰子类的方法,但由于子类会继承其元类父,您必须显式地使 abstractmethod
的构造函数返回 Interface
的对象而不是 ABCMeta
本身,以便不会继承自定义行为:
Interface
这样:
from abc import ABCMeta,abstractmethod
class Interface(ABCMeta):
def __new__(metacls,name,bases,classdict):
for attr,value in classdict.items():
if callable(value):
classdict[attr] = abstractmethod(value)
return super().__new__(ABCMeta,classdict)
会产生:
class A(metaclass=Interface):
def foo(self):
pass
def bar(self):
pass
class B(A):
def foo(self):
pass
b = B()
同时:
TypeError: Can't instantiate abstract class B with abstract method bar
运行不会出错。