【发布时间】:2013-01-08 15:39:09
【问题描述】:
我正在编写一个插件框架,我希望能够编写一个装饰器interface,它将用户类转换为 ABC 类并将所有方法替换为抽象方法。我无法让它工作,我认为问题与错误的 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 一样,并将所有函数替换为抽象函数?
【问题讨论】:
-
interface函数应该返回一些东西吗? (我收到x = X() # should fail, because test will be abstract method.)。 -
当然,抱歉打错了,
interface应该是装饰器返回新类:) - 我已经解决了问题 -
documentation 确实声明了
Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are not supported,这就解释了为什么它不起作用。我正在研究是否还有办法做到这一点。 -
但理论上我并不是要添加或修改方法的抽象状态(...)-我正在尝试基于该旧类型创建新类型-如果您在代码中执行此操作- 你创建像
class Y(X): @abstractmethod def test2(self): pass这样的东西,它可以工作,所以我应该能够使用动态代码来做到这一点(甚至将函数 dict 复制到新类型上) -
相反,您确实在创建每个函数后将其修改为抽象。您的代码首先创建
newcls类,然后 动态应用abstractmethod装饰器。 (因此我尝试颠倒顺序,首先将abstractmethod应用于cls的方法,然后创建newcls,但它也不起作用。
标签: python python-3.x abstract-class introspection