class 中所有方法的抽象方法装饰器

abstractmethod decorator to all methods in class

我试图实现我不需要一直使用所有方法装饰器的地方@abstractmethod

首先,我实现了 class 装饰器,但这不需要任何结果:

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()

其次,我尝试在 class 中使用 __init__ 方法实现它,但它也没有给出任何结果:

class Interface(ABC):
    def __init__(self):
        for attr in self.__dict__:
            attr_obj = getattr(self, attr)

            if callable(attr_obj):
                setattr(self, attr, 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()

如何实现 class 中的所有方法都用 @abstractmethod 修饰的方法?

就像@juanpa.arrivillaga提到的那样,在实例化class之后装饰抽象class已经太晚了,因为ABC改变了它的class成员它的元class, ABCMeta.

相反,您可以 subclass ABCMeta(如下例中的 Interface)并对 class 的 classdict 参数进行修改constructor before调用superclass.

的构造函数

由于child classes应该默认实现抽象方法,典型情况下不会继续声明方法abstract,所以应该避免用[=19=装饰child classes的方法],但由于子 classes 将继承父的元 class,因此您必须显式地使 Interface return 的构造函数成为 [=15] 的对象=] 而不是 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, name, bases, 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

同时:

class A(metaclass=Interface):
    def foo(self):
        pass

    def bar(self):
        pass

class B(A):
    def foo(self):
        pass

    def bar(self):
        pass

会运行没有错误。