Учитывая объект A, который содержит вызываемый объект B, существует ли способ определить «A» изнутри B.__call__()
?Доступ к объекту, содержащему инъецируемый объект?
Это предназначено для использования в тестовой инъекции, где 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()
, использовать как «это» (строка с надписью «###»)?
Естественно, что код немного сложнее (вызовы могут быть настроены на произвольный порядок, могут быть установлены значения возврата и т. Д.), Но это минимальный пример, который я мог бы предложить, который демонстрирует как проблема и большинство ограничений.
Outer.func
Outer.func
Невозможно ввести функцию с аргументом по умолчанию вместо того, компаратор/валидатор).
Теоретически, я мог издеваться над «Outer» полностью для своего вызывающего абонента. Однако, создавая ожидания, вероятно, будет больше кода, а не повторное использование в другом месте. Любой подобный случай/проект также должен был бы переопределить «Outer» (или его эквивалент) как макет.
Вы правы, это не инъекция зависимостей, а вот выбивание. Во всяком случае, мне кажется, это так сложно, как я боялся. Мне нужно будет заменить метод * и *, необходимо заменить '__init__', чтобы снова заменить метод при создании экземпляра, на этот раз с помощью метода проксирования, который передал бы содержащий объект объект' B' ... выполнимый, но не поддерживаемый , так что лучше всего оставить в качестве Gedankenexperiment. – Gabe