intricated functions: how to share a variable

T

TP

Hi everybody,

See the following example:

#########
def tutu():

def toto():

print a
a = 4
print a

a=2
toto()

tutu()
##########

I obtain the following error:
"UnboundLocalError: local variable 'a' referenced before assignment"

This is because Python looks in the local context before looking in the
global context.

The use of "global a" in toto() does not help because global allows to force
Python to look for the variable at the module level.

So, how to share a variable between intricated functions?

Thanks a lot

Julien
--
python -c "print ''.join([chr(154 - ord(c)) for c in '*9(9&(18%.\
9&1+,\'Z4(55l4('])"

"When a distinguished but elderly scientist states that something is
possible, he is almost certainly right. When he states that something is
impossible, he is very probably wrong." (first law of AC Clarke)
 
D

Diez B. Roggisch

TP said:
Hi everybody,

See the following example:

#########
def tutu():

def toto():

print a
a = 4
print a

a=2
toto()

tutu()
##########

I obtain the following error:
"UnboundLocalError: local variable 'a' referenced before assignment"

This is because Python looks in the local context before looking in the
global context.

The use of "global a" in toto() does not help because global allows to
force Python to look for the variable at the module level.

So, how to share a variable between intricated functions?

You could use a class :)

Another often used trick is to have a mutable container-object, like this:

def tutu():
a = [2]

def toto():
a[0] = 4

toto()

Diez
 
C

Chris Rebert

Hi everybody,

See the following example:

#########
def tutu():

   def toto():

nonlocal a #note: this requires a rather recent version of python
       print a
       a = 4
       print a

   a=2
   toto()

tutu()
##########

I obtain the following error:
"UnboundLocalError: local variable 'a' referenced before assignment"

This is because Python looks in the local context before looking in the
global context.

The use of "global a" in toto() does not help because global allows to force
Python to look for the variable at the module level.

So, how to share a variable between intricated functions?

Details: http://www.python.org/dev/peps/pep-3104/

Cheers,
Chris
 
P

Peter Otten

TP said:
Hi everybody,

See the following example:

#########
def tutu():

def toto():

print a
a = 4
print a

a=2
toto()

tutu()
##########

I obtain the following error:
"UnboundLocalError: local variable 'a' referenced before assignment"

This is because Python looks in the local context before looking in the
global context.

The use of "global a" in toto() does not help because global allows to
force Python to look for the variable at the module level.

So, how to share a variable between intricated functions?

This limitation is removed in Python 3 with the 'nonlocal' statement:
.... def inner():
.... nonlocal a
.... print(a)
.... a = 4
.... print(a)
.... a = 2
.... inner()
.... print(a)
....2
4
4

Peter
 
B

Bearophile

TP:
def tutu():

    def toto():

        print a
        a = 4
        print a

    a=2
    toto()

tutu()
##########

I obtain the following error:
"UnboundLocalError: local variable 'a' referenced before assignment"

This is because Python looks in the local context before looking in the
global context.

The use of "global a" in toto() does not help because global allows to force
Python to look for the variable at the module level.

So, how to share a variable between intricated functions?

Generally your purpose as a programmer is to write the least intricate
code. Because the less tricky it is, the more readable it becomes and
also the bug count decreases.

So probably a better solution is to just use the normal function
semantics: you pass them an argument and you take an argument as
return value. Such return value will be the new version of the value
you talk about.

Python3+ has the "nonlocal" statement that may do what you ask for.
But as many other things in Python it must be used with judgment, to
avoid writing intricate code.

Bye,
bearophile
 
T

TP

Bearophile said:
So probably a better solution is to just use the normal function
semantics: you pass them an argument and you take an argument as
return value. Such return value will be the new version of the value
you talk about.

Thanks for your answer.
Yes, it is better like this. My problem is that I cannot get the return
values of the function and affect it to some variable, because the function
is called via a "signal-slot" connection of PyQt4, not by an explicit
inline function call.

For example:
#########
def tutu():

def toto():

print a
a = 4
print a

a=2

# ...
# definition of some graphical QPushButton "button"
# ...
# ...

self.connect( button, SIGNAL( "clicked" ), toto )

tutu()
##########

Then, as advised Diez, perhaps the best solution is to have "true" global
variables by using a class and defining the variable a as a member self.a
of the class. By doing like this, a will be known everywhere.

Julien
--
python -c "print ''.join([chr(154 - ord(c)) for c in '*9(9&(18%.\
9&1+,\'Z4(55l4('])"

"When a distinguished but elderly scientist states that something is
possible, he is almost certainly right. When he states that something is
impossible, he is very probably wrong." (first law of AC Clarke)
 
A

alex23

TP said:
Then, as advised Diez, perhaps the best solution is to have "true" global
variables by using a class and defining the variable a as a member self.a
of the class. By doing like this, a will be known everywhere.

Or, as Bearophile suggested, you could use the standard way of passing
arguments into a function:
.... a = 2
.... def toto(a=a):
.... print 'toto', a
.... a = 4
.... print 'toto', a
.... print 'tutu', a
.... toto()
.... print 'tutu', a
....tutu 2
toto 2
toto 4
tutu 2

You could also just do 'toto(a)', but as you're trying to create a
closure here, binding the external scope 'a' to toto via the default
argument will (probably) do what you need.
 
J

Jason Tackaberry

Another often used trick is to have a mutable container-object, like this:

def tutu():
a = [2]

def toto():
a[0] = 4

toto()

When you need a writable bound variable inside a closure, I prefer this
idiom:

def foo():
def bar():
print bar.a
bar.a = 4
print bar.a
bar.a = 2
bar()

Python 3's nonlocal is obviously much more elegant.

Cheers,
Jason.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,078
Latest member
MakersCBDBlood

Latest Threads

Top