Free Python variables. Why is this failing?

The following code prints 123:

>>> a = 123 >>> def f(): ... print a ... >>> f() 123 >>> 

But the following is true:

 >>> a = 123 >>> def f(): ... print a ... a = 456 ... print a ... >>> f() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in f UnboundLocalError: local variable 'a' referenced before assignment >>> 

I would expect this to print:

 123 456 

What am I missing here?

PS I am using Python 2.6.6 if that matters.

+6
source share
4 answers

If a function reads only a variable, it is considered global. If a function ever writes to it, it is considered local. In your second function, a is written to, so it is considered local. Then the line above (where it is read) is invalid.

Here's a link to the Python FAQ: http://docs.python.org/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

+7
source

What you use is called closure : you take a variable from the appearance area and wrap it in a function block.

Your code is fine and works in javascript.

Unfortunately, in Python, closure is read-only.

And the error is always UnboundLocalError: local variable 'var_name' referenced before assignment , which is completely misleading.

En short,, it's not you, this language restriction has combined a bad error message .

EDIT:

I see several people advocating the use of global , which has dangerous side effects : you will get access to variables with the same name in several areas above the current one, which is not what you want with closure.

The solution was added in Python 3 with the nonlocal , which does just that: rebuild a variable from the outer scope into the inner scope.

There is a way to simulate a non-local value for python 2.x , but in fact, you better not just assign something to your variable: copy values, return values, change only mutable types in place, and everything will be fine.

+5
source

This means that Python automatically acts like a variable is global unless you define or try to change it in a function. Try adding global a to your code.

 >>> a = 123 >>> def f(): ... global a ... print a ... a = 456 ... print a ... >>> f() 123 456 >>> a 456 

In the first example, you did not define or modify, so it was global. But if you want, for example, to add 20 to a, you should also use global a .

Also keep in mind that the function a in f is global and its value will differ after the function f is run.

If you want to create a local variable, remember that this declaration always goes before reading, so print a cannot be executed before a = 456 .

EDIT: Good, although we are talking about closures and are dangerous to take advantage of the global opportunity for others.

 >>> a = 123 >>> def f(): ... b = a ... print b ... b = 456 ... print b ... >>> f() 123 456 >>> a 123 >>> 

Here we use the read-only ability to make a copy and modify this copy without changing the external variable a AS LONG AS IT INTEGER. Remember that b contains a link to a . If a is, for example, a list and operation f similar to b.append(3) , then both a and b will be accessible and changed out of scope.

The choice of method is different due to needs.

+4
source

The comment space is too small to fit the quotation marks below, so I am posting a new answer here.

I think this is a variable scope problem. The Python Document Execution Model says:

If the name binding operation occurs anywhere inside the code block, all use of the name inside the block is considered as a reference to the current block. This can lead to errors when the name is used in before binding it. This rule is subtle. Python lacks a declaration and allows you to perform name binding operations anywhere inside the code block. The local variables of the code block can be determined by scanning the entire text of the block to bind the name of the operation.

0
source

Source: https://habr.com/ru/post/904743/


All Articles