By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,988 Members | 1,367 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,988 IT Pros & Developers. It's quick & easy.

nested function scopes

P: n/a
hi,

i'm having some trouble nesting functions. consider the following:
def h():
x = 1
def g():
print x # ok, x is taken from h
g()

def f():
x = 1
def g():
print x # this is not ok
x = 2 # this implies that x is local to g
g()

h() # ok
f() # UnboundLocalError: local variable 'x' referenced before assignment
when i run this code i get:
1
Traceback (most recent call last):
File "test.py", line 15, in ?
f() # UnboundLocalError: local variable 'x' referenced before assignment
File "test.py", line 12, in f
g()
File "test.py", line 10, in g
print x # this is not ok
UnboundLocalError: local variable 'x' referenced before assignment
how do i declare that x belongs to the parent function, so that i can do
assignments to it? do i have to put it into a compound object?

it would be very handy to be able to do this if i have nested functions
that use a lot of varables. only passing the variables you assign to as
packed compound parameters is a bit ugly, since what subset of all
variables this is might change.

i cannot say i like the python scope rules yet. they probably are
practical, but they seem complicated an unstructured to me.

take for example
class C:
y = 0
def f(self):
print y
which does not work unless y is a global. i understand and agree too why
y is not taken from the instance (self), because of the way classes and
instances relate in python. what i do not understand, is why y is not
taken from C, but from global, when nothing is specified. in the
previous example, with the functions h() and g(), g() took x from h().
why should not f() take y from C?

klem fra nils

--
nils grimsmo <ni*****@idi.ntnu.no>
"why is this thus? what is the reason of this thusness"
- artemus ward
Jul 18 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
Nils Grimsmo wrote:
i'm having some trouble nesting functions. consider the following:
You understand the rules, I think. You just don't like them. The
appropriate koan is "explicit is better than implicit".

I'd use something like this:

class Struct(object):
pass
...
def outer():
shared = Struct()
shared.counter = 1
def inner():
print 'inner says:', shared.counter
shared.counter += 1
inner()
inner()
print 'outer says:', shared.counter
it would be very handy to be able to do this if i have nested
functions that use a lot of variables. only passing the variables
you assign to as packed compound parameters is a bit ugly,
since what subset of all variables this is might change.
Python's goal is to make code more easy to _read_, not _write_.
I find it easier to read the outer function when I know
what might change on me. As my example shows, you needn't
thread all calls with the list of values.

There is another python idea here you haven't yet caught:
You speak of variables, but python only has associations of
names with values. When you think in terms of names and
associations, you may find 'inner's ability to see what 'outer'
is talking about without being able to affect 'outer's
associations reasonable.
i cannot say i like the python scope rules yet. they probably are
practical, but they seem complicated an unstructured to me. Give it time. They are simple when you twist your head just right,
then they will seem completely simple.
class C:
y = 0
def f(self):
print y
Again, "explicit is better than implicit".

Either:
class D(object):
y = "D's y"
def f(self):
print self.y
Or:
class E(object):
y = "E's y"
def f(self):
print E.y

behave as you wish. Bindings first look to the instance and
then the class. Python is quite dynamic. There is, by the way,
a difference between the two above. Ponder the following two
subclasses:

class F(D):
y = "F(D)'s y"

class G(E):
y = "G(E)'s y"

F().f() prints F(D)'s y
G().f() prints E's y

to work in the same was as the two above, but you'd be wrong.
In the previous example, with the functions h() and g(), g()
why should not f() take y from C?

but which class should it choose in my examples? The instance's
exact class? The class in which the method was defined? You
could mean either, and be without a way to specify the other.

Further, you could do this:
y = "global"
class C:
def f(self):
print y

o = C()
o.f()
C.y = "classs variable"
o.f()

Should the second call to o.f() print something different than
the first one?

Anyhow, this is really too long already. I'll just include the
Struct definition I actually use when coding. It uses too much
magic to be clear, but it prints nicely in interactive mode.

This in my "toys.py":

class Struct(object):
def __init__(self, **kw):
self.__dict__.update(kw)
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__,
', '.join(['%s=%r' % name_val for
name_val in self.__dict__.items()]))

Then (when I want data types):
import toys
class Holder(toys.Struct): pass # just to give a name

And my example becomes:

def outer():
shared = Holder(counter=1, name='Fred')
def inner():
print 'inner says:', shared
shared.counter += 1
inner()
inner()
print 'outer says:', shared
-Scott David Daniels
Sc***********@Acm.Org
Jul 18 '05 #2

P: n/a

"Nils Grimsmo" <ni*****@idi.ntnu.no> wrote in message
news:3f********@news.broadpark.no...
hi,

i'm having some trouble nesting functions. consider the following:
def h():
x = 1
def g():
print x # ok, x is taken from h
g()

def f():
x = 1
def g():
print x # this is not ok
x = 2 # this implies that x is local to g
g()

h() # ok
f() # UnboundLocalError: local variable 'x' referenced before assignment .... how do i declare that x belongs to the parent function, so that i can do
assignments to it?
Currently you cannot. As you probably know, 'global' declares that x
belongs to the module so you can assign to as well read it. This fall,
there was an extended discussion on pydev (at least 30 posts, I am sure) on
the subject of extending the idea of global to allow assignment to
intermediate scopes. Would such be desireable? If so, what syntax? See
python.org for B. Cannon's summaries or link to archives. Current bottom
line: no change.
do i have to put it into a compound object?
If compound = mutable collection, yes. Your example revised:

def f():
x = [1]
def g():
print x[0]
x[0] = 2
g()

The ease of doing this and the ugliness or other problems with proposed
alternatives inhibits change.
it would be very handy to be able to do this if i have nested functions
that use a lot of varables. only passing the variables you assign to as
packed compound parameters is a bit ugly, since what subset of all
variables this is might change.
You do not have to 'pass' the compound since you have read access to mutate
it.
i cannot say i like the python scope rules yet. they probably are
practical, but they seem complicated an unstructured to me.
They were simpler before nested scopes were introduced ;-). You can program
without them if you wish.
take for example

class C:
y = 0
def f(self):
print y which does not work unless y is a global. i understand and agree too why
y is not taken from the instance (self), because of the way classes and
instances relate in python. what i do not understand, is why y is not
taken from C, but from global, when nothing is specified. in the
previous example, with the functions h() and g(), g() took x from h().
why should not f() take y from C?


This is a different kettle of fish. Classes, though callable, are not
functions and methods are not nested functions. Neither class nor instance
methods can be called during class construction because neither the class
nor instances thereof even exist. In any case, there is already a mechanism
for accessing class attributes: C.y in this case. Use it.

Terry J. Reedy

Jul 18 '05 #3

P: n/a

Terry Reedy:

Nils Grimsmo:
i'm having some trouble nesting functions. consider the following: [snip] def f():
x = 1
def g():
print x # this is not ok
x = 2 # this implies that x is local to g [snip] how do i declare that x belongs to the parent function, so that i can do assignments to it?


Currently you cannot.


Why not use the old method of passing variables to nested functions:
def f()
x = 1
def g(x=x):
print x
x = 2

Emile van Sebille
em***@fenx.com

Jul 18 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.