UnboundLocalError при использовании += в списке. Почему здесь необходим нелокальный режим, когда прямой вызов __iadd__ работает нормально?
Рассмотрим этот код:
def main():
l = []
def func():
l += [1]
func()
print(l)
if __name__ == '__main__':
main()
Это произведет:
Traceback (most recent call last):
File "/Users/tahsmith/Library/Preferences/PyCharm2017.1/scratches/scratch_21.py", line 14, in <module>
main()
File "/Users/tahsmith/Library/Preferences/PyCharm2017.1/scratches/scratch_21.py", line 11, in main
func()
File "/Users/tahsmith/Library/Preferences/PyCharm2017.1/scratches/scratch_21.py", line 9, in func
l += [1]
UnboundLocalError: local variable 'l' referenced before assignment
Это само по себе можно исправить, используя nonlocal l
в начале func
или используя __iadd__
прямо вместо +=
,
Вопрос: почему nonlocal
нужен здесь?
Это очень удивительно для меня.
2 ответа
+=
является оператором расширенного присваивания; это примерно означает:
def func():
l = l + [1]
Если бы вы должны были заменить l += [1]
с призывом к object.__iadd__()
, вы не можете игнорировать возвращаемое значение этого вызова, если вы используете его правильно:
def func():
l = l.__iadd__([1])
Оба этих перевода также нуждаются в nonlocal
заявление, потому что оба доступа l
и назначить обратно l
,
Вы можете избежать игнорирования возвращаемого значения object.__iadd__
потому что объекты списка изменчивы; список видоизменен на месте. Но тогда вы можете также использовать list.extend()
позвоните в этом случае:
def func():
l.extend([1])
list.__iadd__()
под прикрытием звонков list.extend()
перед возвращением self
,
Потому что под одеялом l += [1]
приводит к:
l = l + [1]
который ссылается на имя l
до того, как это назначено; вот почему вы получите UnboundLocalError
,
l.__iadd__
с другой стороны, это простой вызов функции; он не выполняет назначение, тем самым сводя на нет необходимость nonlocal
чтобы помочь в том, где искать имя l
,