给定一个包含可调用对象B的对象A,有没有办法从B.__call__()
内部确定“A”?
这适用于测试注入,其中A.B最初是一种方法。
代码是这样的:
# Class to be tested.
class Outer(object):
def __init__(self, arg):
self.arg = arg
def func(self, *args, **kwargs):
print ('Outer self: %r' % (self,))
# Framework-provided:
class Injected(object):
def __init__(self):
self._replay = False
self._calls = []
def replay(self):
self._replay = True
self._calls.reverse()
def __call__(self, *args, **kwargs):
if not self._replay:
expected = (args[0], args[1:], kwargs)
self._calls.append(expected)
else:
expected_s, expected_a, expected_k = self._calls.pop()
ok = True
# verify args, similar for expected_k == kwargs
ok = reduce(lambda x, comp: x and comp[0](comp[1]),
zip(expected_a, args),
ok)
# what to do for expected_s == self?
# ok = ok and expected_s(this) ### <= need "this". ###
if not ok:
raise Exception('Expectations not matched.')
# Inject:
setattr(Outer, 'func', Injected())
# Set expectations:
# - One object, initialised with "3", must pass "here" as 2nd arg.
# - One object, initialised with "4", must pass "whatever" as 1st arg.
Outer.func(lambda x: x.arg == 3, lambda x: True, lambda x: x=='here')
Outer.func(lambda x: x.arg == 4, lambda x: x=='whatever', lambda x: True)
Outer.func.replay()
# Invoke other code, which ends up doing:
o = Outer(3)
p = Outer(5)
o.func('something', 'here')
p.func('whatever', 'next') # <- This should fail, 5 != 4
问题是:在Injected.__call__()
内是否有办法(黑魔法可以)访问非自覆Outer.func()
中的“自我” ,用作“this”(标有“###”的行)?
当然,代码有点复杂(可以将调用配置为任意顺序,可以设置返回值等),但这是我能想出的最小例子,证明了这两个问题和大多数约束。
我无法使用默认参数而不是Outer.func
注入一个函数 - 它会中断记录(如果注入了一个函数,它将是一个未绑定的方法,并且需要一个“Outer”实例作为其第一个参数,而不是比较器/验证器)。
理论上,我可以完全为其来电者嘲笑“外面”。然而,设置期望可能会有更多代码,而不是其他地方可重复使用 - 任何类似的案例/项目也必须重新实现“外部”(或其等价物)作为模拟。
答案 0 :(得分:2)
给定一个对象A,其中包含一个 可调用对象B,有没有办法 从内部确定“A” B.的呼叫强>()?
不是一般情况下,即在本文中您需要无限的通用性 - 除非B
以某种方式保留对A
的引用,否则Python肯定不会保留它B
代表。
对于您的预期用例,情况更糟:即使B
本身 保持对A
的引用,它也无济于事(作为方法对象会它的类),因为你在B
没有追索setattr
的情况下践踏Outer
,这相当于一项任务。在课程func
中没有任何痕迹,在更快乐的时候,它有setattr
属性具有某些特征:该属性不再被{{1}}删除。
这不是真正的依赖注入(一种需要从注入对象进行合作的设计模式),它是猴子修补,我的一个宠儿小便,以及它的破坏性,不可恢复的性质(你现在正在努力)是为什么我对此感到愤怒的一部分。
答案 1 :(得分:0)