基于用户定义的类创建动态 ABC 类

Woj*_*ilo 5 python abstract-class introspection python-3.x

我正在编写一个插件框架,我希望能够编写一个装饰器interface,它将用户类转换为 ABC 类并用抽象方法替换所有方法。我无法让它工作,我想问题与错误的 mro 有关,但我可能是错的。

我基本上需要写:

@interface
class X:
    def test(self):
        pass

x = X() # should fail, because test will be abstract method.
Run Code Online (Sandbox Code Playgroud)

用它们的抽象版本替换方法很简单(你必须迭代 func 并将它们替换为abc.abstractmethod(func)),但是我在创建动态类型时遇到了问题,这将是一个ABCmeta元类。

现在我有类似的东西:

from abc import ABCMeta

class Interface(metaclass=ABCMeta):
    pass

def interface(cls):
    newcls = type(cls.__name__, (Interface, cls), {})
    # substitute all methods with abstract ones
    for name, func in inspect.getmembers(newcls, predicate=inspect.isfunction):
        setattr(newcls, name, abstractmethod(func))
    return newcls
Run Code Online (Sandbox Code Playgroud)

但它不起作用 - 我可以毫无错误地初始化类 X。

使用 Python 中 ABC 的标准用法,我们可以这样写:

class X(metaclass=ABCMeta):
    @abstractmethod
    def test(self):
        pass

x = X() # it will fail
Run Code Online (Sandbox Code Playgroud)

如何在 Python3 中创建动态类型,它的行为就像它有元类一样,并将ABCmeta用抽象函数替换所有函数?

Dav*_*son 5

诀窍是不使用setattr重置每个属性,但代替的那些修改的属性传递给type功能作为字典:

import inspect
from abc import ABCMeta, abstractmethod

class Interface(metaclass=ABCMeta):
    pass

def interface(cls):
    attrs = {n: abstractmethod(f)
             for n, f in inspect.getmembers(cls, predicate=inspect.isfunction)}

    return type(cls.__name__, (Interface, cls), attrs)

@interface
class X(metaclass=ABCMeta):
    def test(self):
        pass

x = X()
# does fail:
# Traceback (most recent call last):
#   File "test.py", line 19, in <module>
#     x = X() # should fail, because test will be abstract method.
# TypeError: Can't instantiate abstract class X with abstract methods test
Run Code Online (Sandbox Code Playgroud)