Python 继承非抽象类并将其所有函数转换为抽象方法

Python 继承非抽象类并将其所有函数转换为抽象方法,python,inheritance,abstract-class,Python,Inheritance,Abstract Class,我得到了一个上游接口,它的所有函数都定义为非抽象的,而实际上它们应该用@abstractmethods来修饰。当调用它时,我没有实现它的一个函数时,我希望收到一个错误。为此,我将创建一个包装器类,手动遍历其定义的每个函数,并执行如下操作: from abc import ABC, abstractmethod class Foo(object): def foo(self): print("Foo") class AbstractFoo(Foo, ABC):

我得到了一个上游接口,它的所有函数都定义为非抽象的,而实际上它们应该用
@abstractmethod
s来修饰。当调用它时,我没有实现它的一个函数时,我希望收到一个错误。为此,我将创建一个包装器类,手动遍历其定义的每个函数,并执行如下操作:

from abc import ABC, abstractmethod

class Foo(object):
    def foo(self):
        print("Foo")

class AbstractFoo(Foo, ABC):
    @abstractmethod
    def foo(self):
        return super().foo()

class ConcreteFoo(AbstractFoo):
    def foo(self):
        print("Concrete Foo")
        super().foo()

f = ConcreteFoo()
f.foo()
哪些产出:

Concrete Foo
Foo
我想对Foo定义的所有函数都这样做。显然,像
\uuuu str\uuuu
\uuuu repr\uuuu
这样的继承魔法函数应该被适当地转发

有人知道一个好的,蟒蛇式的方法吗

def validate_base_class_implemntation(cls):
    base_cls_funcs = []
    for attr in cls.__bases__[0].__dict__:
        if callable(getattr(cls, attr)):
            base_cls_funcs.append(attr)

    cls_funcs = []
    for attr in cls.__dict__:
        if callable(getattr(cls, attr)):
            cls_funcs.append(attr)

    missing_funcs = [x for x in base_cls_funcs if x not in cls_funcs]

    if len(missing_funcs) > 0:
        print("Not implemented functions are: {}".format(','.join(missing_funcs)))
        raise Exception("Not implement function exception!")

    return cls


class Foo(object):
    def foo(self):
        print("Foo")

    def boo(self):
        print("Wow")


@validate_base_class_implemntation
class ConcreteFoo(Foo):
    def foo(self):
        print("Concrete Foo")
        super().foo()


f = ConcreteFoo()
f.foo()
100%不确定这是否是你的意思


这个装饰器检查被装饰的类是否实现了所有的基类函数(在您的例子中,它们没有被抽象装饰)。如果修饰类未实现某个函数,则会引发异常。

您可以修改原始类
Foo
,并将其所有方法转换为抽象方法,然后使用
metaclass=ABCMeta
定义
Foo
的空白子类,以处理检查:

from abc import ABCMeta, abstractmethod
from types import FunctionType


class AbstractFoo(Foo, metaclass=ABCMeta):
    pass


names = set()
for k, v in vars(Foo).items():
    if k.startswith('__') and k.endswith('__'):
        continue
    elif isinstance(v, FunctionType):
        names.add(k)
        v.__isabstractmethod__ = True

AbstractFoo.__abstractmethods__ = frozenset(names)

旁注:此方法依赖于abc使用的dunder属性,因此可以在不受反对的情况下中断。

m。。。我有一个使用decorator的主意,对你有效吗?意思是不在运行时感谢您的实现!在问题陈述中,我应该提到
Foo
可能没有直接继承
对象
,这意味着可能存在我不想抽象的非dunders。这将适用于所有功能。不过,我对你的答案投了赞成票!为不完整的内容道歉specification@OneRaynyDay我不太明白你的意思
vars(Foo)
只检查
Foo
的立即属性,不包括任何基类。如果
Foo
本身定义了你不想抽象的方法,那么对于任何算法,你都需要为它们提供一些规范。这对我很有用!非常感谢您的实施。我想知道是否有一种更像蟒蛇的方式来做到这一点,但这对我来说已经足够了:)干杯@每天我都会考虑it@OneRaynyDay更具pythonic:(1)对函数使用
set
而不是
list
,然后使用
missing_funcs=base_cls_funcs-cls_funcs
,(2)检查
如果missing_funcs
就足够了,(3)使用
cls.mro()[1]
而不是
cls.[0]
,(4)使用
vars(…)
而不是
,(5)对
循环使用理解而不是两个
,(6)提出
类型错误而不是
异常
可调用的
将包括非函数对象,因此
isinstance(…,types.FunctionType)
更合适。