第1部分
我有一个设置,我有一组要模拟的类,我的想法是,在我想这样做的情况下,我将一个mock
关键字参数传递给构造函数并__new__
拦截它,而是传回一个模拟版本那个物体。
它看起来像这样(在@mgilsons 建议之后编辑了关键字查找):
class RealObject(object):
def __new__(cls, *args, **kwargs):
if kwargs.pop('mock', None):
return MockRealObject()
return super(RealObect, cls).__new__(cls, *args, **kwargs)
def __init__(self, whatever = None):
'''
Constructor
'''
#stuff happens
然后我像这样调用构造函数:
ro = RealObject(mock = bool)
我在这里遇到的问题是,当我收到以下错误bool
时False
:
TypeError: __init__() got an unexpected keyword argument 'mock'
如果我将mock
其作为关键字参数添加,则此方法有效,__init__
但我要问的是是否可以避免这种情况。我什至mock
从kwargs
dict
.
这也是一个关于设计的问题。有一个更好的方法吗?(当然!)我想尝试这样做,而不使用工厂或超类或任何东西。但是,我应该使用另一个关键字吗?__call__
?
第 2 部分基于 jsbueno 的回答
所以我想将元类和__new__
函数提取到一个单独的模块中。我这样做了:
class Mockable(object):
def __new__(cls, *args, **kwargs):
if kwargs.pop('mock', None):
mock_cls = eval('{0}{1}'.format('Mock',cls.__name__))
return super(mock_cls, mock_cls).__new__(mock_cls)
return super(cls, cls).__new__(cls,*args, **kwargs)
class MockableMetaclass(type):
def __call__(self, *args, **kwargs):
obj = self.__new__(self, *args, **kwargs)
if "mock" in kwargs:
del kwargs["mock"]
obj.__init__(*args, **kwargs)
return obj
我已经在一个单独的模块中定义了类RealObject
和MockRealObject
. 我现在有两个问题:
- 如果
MockableMetaclass
并且Mockable
不在与RealObject
班级相同的模块中,eval
则NameError
如果我提供mock = True
. - 如果
mock = False
代码将进入一个以令人印象深刻的RuntimeError: maximum recursion depth exceeded while calling a Python objec
. 我猜这是因为RealObject
s 的超类不再是object
,而是Mockable
。
我该如何解决这些问题?我的方法不正确吗?我应该改为Mockable
装饰师吗?我试过了,但这似乎不起作用,因为__new__
一个实例似乎只是只读的。