Python: изменить локальную переменную метода внутри внутреннего метода
Я пишу тестовый метод под названием, скажем, test_foo
(используя pytest). Я проверяю поведение функции, foo
, который принимает в качестве аргумента другую функцию, get
, foo
звонки get
итеративно, условно на возвращаемое значение get
Например:
def foo(get, param):
max_num_tries = 3
curr_num_tries = 0
response = get(param)
while curr_num_tries < max_num_tries and response.status_code == BAD_STATUS_CODE:
response = get(param)
return response
Я пытаюсь переопределить get
так что он имеет доступ к тому, сколько раз он был вызван и может соответственно возвращать разные значения.
Вот упрощенная версия того, что я имею до сих пор:
def test_foo():
tries_so_far = 0
def get(arg1):
global tries_so_far
if tries_so_far < 3:
tries_so_far += 1
print("do something special here")
else:
print("do something else here")
return "some return val"
foo(get, "some arg")
Однако я получаю следующую ошибку:
NameError: global name 'tries_so_far' is not defined
Если я определю tries_so_far
вне test_foo
На уровне модуля я получаю ожидаемое поведение. Тем не менее, я хотел бы tries_so_far
быть переменной, которая является локальной для test_foo
,
Есть ли способ дать get
читать / писать в tries_so_far
используя глобалы или какую-то другую технику? Примечание: я не могу изменить параметры или вернуть значение get
,
1 ответ
В соответствии с принятым ответом на этот вопрос Почему функции в Python могут печатать переменные в закрытой области видимости, но не могут использовать их в присваивании? В Python 3 добавлен дополнительный оператор: nonlocal
это делает то, что вы хотите. Это как global
, но говорит, что нужно смотреть на объем, а не на уровень модуля. Поэтому следующая модификация должна позволять вам делать именно то, что вы хотите:
def test_foo():
tries_so_far = 0
def get(arg1):
nonlocal tries_so_far
if tries_so_far < 3:
tries_so_far += 1
print("do something special here")
else:
print("do something else here")
return "some return val"
foo(get, "some arg")
Хотя ваш вопрос не является точной копией приведенного выше, вам следует прочитать принятый ответ. Это очень хорошо и, вероятно, ответит на многие неустановленные вопросы, которые у вас есть по этому вопросу.