2012-03-15 2 views
2

У меня небольшая проблема с локальными переменными и python (2.7).python и UnboundLocalError

У меня есть немного кода:

def foo(a): 
    def bar(): 
     print a 
    return bar() 

>>>foo(5) 
5 

Ну, это работает, но если хотите изменить, например:

def foo(a): 
    def bar(): 
     a -= 1 
    return bar() 
>>>foo(5) 
UnboundLocalError: local variable 'a' referenced before assignment 

Так что я должен влиять на «а» другой переменной.

Но я не понимаю этот аспект. Это потому, что когда есть назначение, python смотрит в переменные locals() и не находит его?

Спасибо.

+1

Почему вы звоните 'бар()' 'внутри бара()' в вашем втором примере? Он должен останавливаться с 'RuntimeError: максимальная глубина рекурсии ', как только вы пройдете линию с назначением. –

+0

http://docs.python.org/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value | http://eli.thegreenplace.net/2011/05/15/understanding-unboundlocalerror-in-python – georg

+1

В вашем втором примере вы возвращаете bar() в bar(), это то, что вы хотите или ошибка с отступом/копией ? Потому что у вас его нет в первом примере –

ответ

8

Вы нашли что-то, что раньше было проблемой в Python! Короткий ответ заключается в том, что вы не можете сделать это в Python 2.x (хотя вы можете simulate), но вы можете в 3.x использовать ключевое слово nonlocal.

См PEP 3104:

Before version 2.1, Python's treatment of scopes resembled that of standard C: within a file there were only two levels of scope, global and local. In C, this is a natural consequence of the fact that function definitions cannot be nested. But in Python, though functions are usually defined at the top level, a function definition can be executed anywhere. This gave Python the syntactic appearance of nested scoping without the semantics, and yielded inconsistencies that were surprising to some programmers -- for example, a recursive function that worked at the top level would cease to work when moved inside another function, because the recursive function's own name would no longer be visible in its body's scope. This violates the intuition that a function should behave consistently when placed in different contexts. Here's an example:

def enclosing_function(): 
    def factorial(n): 
     if n < 2: 
      return 1 
     return n * factorial(n - 1) # fails with NameError 
    print factorial(5) 

Python 2.1 moved closer to static nested scoping by making visible the names bound in all enclosing scopes (see PEP 227). This change makes the above code example work as expected. However, because any assignment to a name implicitly declares that name to be local, it is impossible to rebind a name in an outer scope (except when a global declaration forces the name to be global). Thus, the following code, intended to display a number that can be incremented and decremented by clicking buttons, doesn't work as someone familiar with lexical scoping might expect:

def make_scoreboard(frame, score=0): 
    label = Label(frame) 
    label.pack() 
    for i in [-10, -1, 1, 10]: 
     def increment(step=i): 
      score = score + step # fails with UnboundLocalError 
      label['text'] = score 
     button = Button(frame, text='%+d' % i, command=increment) 
     button.pack() 
    return label 

Python syntax doesn't provide a way to indicate that the name score mentioned in increment refers to the variable score bound in make_scoreboard, not a local variable in increment. Users and developers of Python have expressed an interest in removing this limitation so that Python can have the full flexibility of the Algol-style scoping model that is now standard in many programming languages, including JavaScript, Perl, Ruby, Scheme, Smalltalk, C with GNU extensions, and C# 2.0.

+0

Хорошо, спасибо большое! – lundiAuSoleil

2

Причина, данная Константиниусом, верна. Другой способ борьбы с ним (без использования глобальных переменных) будет

def foo(a): 
    def bar(a): 
     a -= 1 
     return a 
    return bar(a) 
>>> print foo(5) 
4 
Смежные вопросы