根据用户定义的类创建动态ABC类

时间:2013-01-08 15:39:10

标签: python python-3.x abstract-class introspection

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

我基本上需要写作:

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

x = X() # should fail, because test will be abstract method.

用抽象版本替换方法很简单(你必须迭代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

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

在Python中标准使用ABC,我们可以写:

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

x = X() # it will fail

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

1 个答案:

答案 0 :(得分:4)

诀窍不是使用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