Понимание нелокальности в Python 3

Я пытаюсь понять область видимости переменных Python 3 и nonlocal,

Рассмотрим следующую функцию (это всего лишь пример):

def build_property(something):

    def deco(func):

        def getter(self):
            return getattr(self, something)

        def setter(self, value):
            setattr(self, something, value)

        return property(getter, setter)

    return deco

Это прекрасно работает без nonlocal, Но если сейчас я хочу условно создавать геттеры и сеттеры в зависимости от something Мне нужен нелокальный.

def build_property(something):

    def deco(func):

        nonlocal something # This is needed

        if something.startswith('A'):
            getter = None
        else:
            def getter(self):
                return getattr(self, something)

        if something.startswith('B'):
            setter = None
        else:
            def setter(self, value):
                setattr(self, something, value)

        return property(getter, setter)

    return deco

Почему nonlocal нужен в одном случае, а не в другом? Другими словами, почему something если правильно найдено в первом случае (без nonlocal), но во втором я получаю: "UnboundLocalError: локальная переменная" что-то ", на которое ссылаются до назначения", если nonlocal нету?

2 ответа

Первый: nonlocal не обязательно в написанном вами коде. Вы не меняете объект, который something указывает на.

Второе: есть случаи, когда вам нужно будет использовать nonlocal, Ниже приведен код где nonlocal является необходимым. Обратите внимание, что все утверждения верны (то есть они не вызывают ошибку AssertionError).

def main():
    variable = 1

    def function():
        variable = 2
    function()
    assert variable == 1

    def function():
        nonlocal variable
        variable = 2
    function()
    assert variable == 2

if __name__ == '__main__':
    main()

Третье: код, который вы представили, не выдает ошибку, о которой вы заявляете. Если я удалю nonlocal линии, и вызовите следующие функции, я не получаю ошибок.

build_property('A')(lambda: True)
build_property('B')(lambda: True)
build_property('C')(lambda: True)
def A(d):
    outer = object()
    d["outer"] = outer
    def B():
        print locals()
        assert d["outer"] is outer #This fails and never reaches
        inner = object()
        d=dict()                   #this line.
        print locals()
    def C():
        print locals()
        assert d["outer"] is outer #This goes on fine.
        inner = object()
        print locals()
    return B,C

=> b,c = A(dict())
=> c()
-snip, AOK-
=> b()
UnboundLocalError: local variable 'd' referenced before assignment

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

Но это удивительно. Я всегда думал о Python(2.x) как о языке без предвидения, оценивая все в последний момент...

Извините за то, что сейчас не по теме.

Другие вопросы по тегам