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

问题描述

我试图让我意识到我不需要一直使用所有方法装饰器 @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

运行不会出错。