2014-01-11 4 views
0

Я пытаюсь понять переменную Python 3 и nonlocal.Понимание нелокальных в Python 3

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

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 нет?

+1

... и на ваш вопрос? Вы ничего не говорили о ошибках/неожиданном поведении. Если вы получаете исключение, укажите ** полный ** след в своем вопросе. Если вы видите неожиданное поведение, то вы должны * предоставить 1) поведение, которое вы ожидаете, и 2) фактический результат, который вы получите. Мы ** не ** гадалки. – Bakuriu

+0

Просто из соображений: Какой смысл для ваших декораторов? Кажется, вы не используете 'func' нигде ... – glglgl

+0

BTW, я не тестировал код, но я не понимаю, почему он должен понадобиться во втором случае, поскольку' something' никогда не назначается. .. – glglgl

ответ

-1
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) как о совершенно беззаботном языке, оценивая все в последний момент ...

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

+0

Я написал несколько глупых вещей, но это касается хранения ссылок на родительские объекты, да. –

+0

Этот ответ неверен. 'nonlocal' не является оптимизацией, необходимо правильно определить область, в которой должна создаваться переменная. Python 2 не содержит всех закрывающих локалей, только те, на которые ссылается замыкание - точно так же, как Python 3. Разница заключается в том, что Python 3 позволяет * изменять * значение закрытой переменной без создания новой переменной как побочный эффект.'nonlocal' сообщает компилятору, что, несмотря на то, что назначение выполняется во внутреннем блоке, изменяемая переменная является той, которая создана во внешнем блоке. – user4815162342

1

Первый: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) 
Смежные вопросы