nested function scopes

Discussion in 'Python' started by Nils Grimsmo, Dec 11, 2003.

  1. Nils Grimsmo

    Nils Grimsmo Guest

    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 <>
    "why is this thus? what is the reason of this thusness"
    - artemus ward
     
    Nils Grimsmo, Dec 11, 2003
    #1
    1. Advertising

  2. Nils Grimsmo

    Terry Reedy Guest

    "Nils Grimsmo" <> wrote in message
    news:3fd83270$...
    > 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
     
    Terry Reedy, Dec 11, 2003
    #2
    1. Advertising

  3. 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
     
    Scott David Daniels, Dec 12, 2003
    #3
  4. 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
     
    Emile van Sebille, Dec 14, 2003
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Miki Tebeka

    Question about nested scopes

    Miki Tebeka, Oct 8, 2003, in forum: Python
    Replies:
    3
    Views:
    297
    Miki Tebeka
    Oct 9, 2003
  2. Fernando Rodriguez
    Replies:
    2
    Views:
    285
    Alexander Schmolck
    Nov 21, 2003
  3. Dave Benjamin

    Nested scopes and class variables

    Dave Benjamin, Jan 31, 2005, in forum: Python
    Replies:
    7
    Views:
    398
    Steven Bethard
    Feb 3, 2005
  4. Tim N. van der Leeuw

    Nested scopes, and augmented assignment

    Tim N. van der Leeuw, Jul 4, 2006, in forum: Python
    Replies:
    39
    Views:
    797
    Piet van Oostrum
    Jul 10, 2006
  5. Michael Sparks

    Nested Scopes unintended behaviour ?

    Michael Sparks, Mar 17, 2010, in forum: Python
    Replies:
    4
    Views:
    281
    Terry Reedy
    Mar 18, 2010
Loading...

Share This Page