我正在编写一个插件框架,我希望能够编写一个装饰器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
,并用抽象函数替换所有函数?
答案 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