Python and private variables

Take a look at this code:

def closure(): value = False def method_1(): value = True def method_2(): print 'value is:', value method_1() method_2() closure() 

I expect it to print "Value: True", but it is not. Why is this and what is the solution?

+6
source share
5 answers

This is because method_1 gets its own local scope where it can declare variables. Python sees value = True and thinks that you are creating a new variable called value local to method_1 .

The reason Python does this is to avoid polluting the locales of the external visibility with variables from the internal function. (You do not want assignments in regular modular functions to produce global variables!)

If you do not assign a value , then Python searches for outside areas that look for the variable (so reading the variable works as expected, as shown in method_2 ).

One way around this is to use a mutable object instead of a link:

 result = { 'value': False } def method_1(): result['value'] = True 

In Python 3, a nonlocal (see also docs ) was added specifically for this scenario:

 def method_1(): nonlocal value value = True # Works as expected -- assigns to `value` from outer scope 
+16
source

In method_1 , Python assumes (quite reasonably!) That value is a local variable. Whenever you assign a name to a variable inside a function, it is assumed that this variable name is a new local variable. If you want it to be global, you must declare it as global , and if you want it to be "nonlocal" in Python 3 you can declare it nonlocal , but in Python 2 you need to do something uglier: save the value in the container. This avoids reassigning the variable name and, thus, avoiding the uncertainty of uncertainty.

 def method_1_global(): global value value = True def method_1_nonlocal_P3(): nonlocal value value = True value = [False] def method_1_nonlocal_P2(): value[0] = True 
+2
source

When you assign a variable, it assumes that the variable has a local scope. So value in method_1 not value in closure .

If you want this to work in Python 3, add a line to method_1 : nonlocal value .

In Python 2,

 def closure(): value = [False] def method_1(): value[0] = True def method_2(): print 'value is:', value method_1() method_2() closure() 

- one of the possible workarounds.

+2
source

This is because, in fact, you did not modify the private variable - you are masking it with a new one that has the same name. There is no easy way around this in python 2.x, so the nonlocal keyword was added in python 3.

This can be circumvented, however, using mutable types such as list and dictionary. This answer is.

+2
source

To avoid this, you can use a list.

 value = [False] def method_1(): value[0] = True 

Python now searches at higher levels of the region, since the value is not available in local variables. Since the value is a list, and Python refers to it as a global variable relative to * method_1 *, you can consider the value as it is, a list.

+1
source

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


All Articles