#python #function #exception #bug-tracking #local-variables
#python #функция #исключение #отслеживание ошибок #локальные переменные
Вопрос:
У меня есть следующий фрагмент кода:
def isolation_level(level):
def decorator(fn):
def recur(level, *args, **kwargs):
if connection.inside_block:
if connection.isolation_level < level:
raise IsolationLevelError(connection)
else:
fn(*args, **kwargs)
else:
connection.enter_block()
try:
connection.set_isolation_level(level)
fn(*args, **kwargs)
connection.commit()
except IsolationLevelError, e:
connection.rollback()
recur(e.level, *args, **kwargs)
finally:
connection.leave_block()
def newfn(*args, **kwargs):
if level is None: # <<<< ERROR MESSAGE HERE, Unbound local variable `level`
if len(args):
if hasattr(args[0], 'isolation_level'):
level = args[0].isolation_level
elif kwargs.has_key('self'):
if hasattr(kwargs['self'], 'isolation_level'):
level = kwargs.pop('self', 1)
if connection.is_dirty():
connection.commit()
recur(level, *args, **kwargs)
return newfn
return decorator
На самом деле не имеет значения, что она делает, однако я публикую ее в исходном виде, поскольку я не смог воссоздать ситуацию с помощью чего-либо более простого.
Проблема в том, что при вызове я isolation_level(1)(some_func)(some, args, here)
получаю Unbound local variable
исключение в строке 21 (отмечено в списке). Я не понимаю, почему. Я попытался воссоздать ту же структуру функций и вызовов функций, которая не содержала бы всех деталей реализации, чтобы выяснить, что не так. Однако тогда я не получаю сообщение об исключении. Например, работает следующее:
def outer(x=None):
def outer2(y):
def inner(x, *args, **kwargs):
print x
print y
print args
print kwargs
def inner2(*args, **kwargs):
if x is None:
print "I'm confused"
inner(x, *args, **kwargs)
return inner2
return outer2
outer(1)(2)(3, z=4)
С принтами:
1
2
(3,)
{'z': 4}
Чего я не понимаю??
Редактировать
Хорошо, итак, проблема в том, что в первой версии я фактически выполняю присвоение переменной. Python обнаруживает это и, следовательно, предполагает, что переменная локальна.
Комментарии:
1. Сообщение об ошибке можно воспроизвести в нескольких строках, и это легко, если знать, что его вызывает. Смотрите codepad.org/nI0vCx4L
2. @delnan: самый короткий код, который вызывает ошибку, — это использование
x = x
внутри внутренней функции 🙂3. @Sven: Изначально это было так, но я решил сделать это более похожим на код OP.
Ответ №1:
Локальные переменные определяются во время компиляции: присвоения переменной level
несколькими строками ниже строки, в которой возникает ошибка, делают эту переменную локальной для внутренней функции. Итак, строка
if level is None:
на самом деле пытается получить доступ к переменной level
во внутренней области видимости, но такая переменная еще не существует. В Python 3.x вы можете решить эту проблему, объявив
nonlocal level
в начале внутренней функции, если вы действительно хотите изменить переменную внешней функции. В противном случае вы можете просто использовать другое имя переменной во внутренней функции.
Комментарии:
1. Смотрите, я делаю то же самое в приведенном ниже списке, который я опубликовал. И это не приводит к сбою. Я не понимаю, в чем разница.
2. @julkiewicz: Нет, вы не делаете то же самое. В вашем втором фрагменте вообще нет назначений . (Присваивание представляет собой строку типа
a = 2
. Эта строка в любом месте внутри функции создастa
локальную переменную в любом месте внутри этой функции.)3. О, хорошо, значит, он определяет назначение. Я глупый. Спасибо. Я приму и добавлю еще одно редактирование. Спасибо.