Нелокальность Python зависит от уровня иерархии?

Этот вопрос является продолжением вопроса об области видимости переменных Python . Дополнительные вопросы q1 , q2 и , ответы , среди прочего, можно найти на SO. Официальная документация Python , и PEP 3104 должны объяснять детали, но мне они не кажутся полностью самоочевидными.

Тема, которую я пытаюсь решить, - это рефакторинг кода, содержащего нелокальный / глобальный , путем перемещения этого кода вверх / вниз на один уровень иерархии.

Я не понимаю значения этого предложения из справочника Python:

Имена, перечисленные в нелокальном операторе, в отличие от имен, перечисленных в глобальном операторе , должны относиться к ранее существовавшим привязкам во включающей области (область, в которой должна быть создана новая привязка, не может быть определена однозначно).

Учитывая следующий код в глобальной области видимости:

var = 0
def outer():
    global var                  # line A
    var = 1
    def inner():
        nonlocal var            # line B
        var = 2

        print('inner:', var)

    inner()
    print('outer:', var)

outer()
print('main:', var)

Выполнение вызывает ошибку:

SyntaxError: no binding for nonlocal 'var' found

Код работает (конечно, с другой семантикой, если любая строка A закомментирована:

inner: 2
outer: 2
main: 0

или строка B закомментирована:

inner: 2
outer: 1
main: 1

Однако в приведенном выше примере, и поскольку предполагается, что нелокальный связывает var с «охватывающей областью», я ожидал, что строка A связывает внешний / var с затем глобальная область видимости и строка B ищет внешний / var, а также повторно связывает внутренний / var с глобальным / var. Вместо этого он, кажется, не находит его вообще (из-за повторного связывания в строке A, я полагаю) и вызывает ошибку.

Желаемый результат, которого я ожидал, был:

inner: 2
outer: 2
main: 2

Это просто еще один пример сбивающего с толку состояния области видимости в Python?

Или, чтобы сделать это конструктивным вопросом:

  • Как может такой пример быть написанным таким образом, что не имеет значения, на каком уровне находится функция (необходимо заменить глобальный на нелокальный и наоборот)?
  • Если функции находятся на промежуточном уровне , и неизвестный уровень иерархии, как мог автор external () изменить код, который не должен иметь ни внешний (в данном случае глобальный) уровень, ни уровень inner () быть тронутым? -

В моем скромном понимании языка таких конструкций (зависимостей от замыканий) просто следует избегать. Другие уже предлагали использовать другие языковые функции ( классы , func attrs ) для достижения такой контекстной чувствительности.

10
задан Community 23 May 2017 в 11:46
поделиться