Nested function scope problem

Bruno Desthuilliers onurb at xiludom.gro
Mon Jul 24 05:06:30 EDT 2006


danielx wrote:
> Bruno Desthuilliers wrote:
> 
>>Josiah Manson a écrit :
>>
>>>I found that I was repeating the same couple of lines over and over in
>>>a function and decided to split those lines into a nested function
>>>after copying one too many minor changes all over. The only problem is
>>>that my little helper function doesn't work! It claims that a variable
>>>doesn't exist. If I move the variable declaration, it finds the
>>>variable, but can't change it. Declaring the variable global in the
>>>nested function doesn't work either.
>>>
>>>But, changing the variable in the containing scope is the whole purpose
>>>of this helper function.
>>>
>>>I'm new to python, so there is probably some solution I haven't
>>>encountered yet. Could you please suggest a nice clean solution? The
>>>offending code is below. Thanks.
>>>
>>>def breakLine(s):
>>>	"""Break a string into a list of words and symbols.
>>>	"""
>>>	def addTok():
>>>		if len(tok) > 0:
>>
>>                 if tok:
>>
>>An empty sequence evals to False in a boolean context.
>>
>>
>>>			ls.append(tok)
>>>			tok = ''
>>>
> 
> 
> I can't figure out why Josiah's breakLine function won't work either. I
> know Josiah has had his problem resolved, but I'd still like to know
> why his func won't work. I'd like to redirect this discussion in that
> direction, if I may.
> 
> 
>>First point: the nested function only have access to names that exists
>>in the enclosing namespace at the time it's defined.

oops - Sorry, said an obvious stupidity here (was very tired, should not
have answered at all...)

> 
> Coming from lisp, that doesn't make very much sense, and I'm not sure
> that's true. If you move the def for addTok bellow the lines that
> initialize the locals of breakLines, you still get the same problem.

of course.

> 
>>Second point: a nested function cannot rebind names from the enclosing
>>namespace. Note that in Python, rebinding a name and modifying the
>>object bound to a name are very distinct operations.
> 
> 
> I'm not sure that's the problem, because when I ran the debugger, the
> problem is with the line that says if len(tok), not the one bellow it
> which says tok = "". 

That's a side-effect of rebinding tok - it makes the name local. Even if
the rebiding is done *after* first use of the name...


> 
>>Third point : functions modifying their environment this way are usually
>>considered bad form.
> 
> 
> Again, this is coming from lisp, but I don't see anything wrong with
> that :P.



> ***
> 
> After some experimentation, I am completely baffeled as to why
> breakLine won't work. Here is an example of one of the things I did,
> which I believe exactly mimics what breakLine does:
> 
>>>>def outer():
> 
> ... 	def inner():
> ... 		if outerLocal:
> ... 			return "I hear you, 'hello world'."
> ... 		else:
> ... 			return "Come again?"
> ... 	outerLocal = "hello world"
> ... 	return inner()
> ...
> 
>>>>outer()
> 
> "I hear you, 'hello world'."
> 
> As I said, I believe the line which sets tok should break (quietly),
> but not the line which tests tok. My experiment seems to confirm
> this...

You did not rebind 'outerLocal' in your above code.

> One thing I can understand is why the line tok = "" in addTok won't
> work. This is because when Python sees that line, it should create a
> new local variable in the scope of addTok.

Yes. But this local name is referenced before assignment.

> Once addTok returns, that
> variable is lost. That's pretty deep, now that I've thought about it...
> 

(snip)

Sorry once again for the obvious stupidity I wrote as first point. Next
time I'll go to bed instead, I promise :(

-- 
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb at xiludom.gro'.split('@')])"



More information about the Python-list mailing list