473,735 Members | 2,125 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Nested function scope problem

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:
ls.append(tok)
tok = ''

ls = []
tok = ''
splitters = '?()&|:~,'
whitespace = ' \t\n\r'

for c in s:
if c in splitters:
addTok()
ls.append(c)
elif c in whitespace:
addTok()
else:
tok = tok + c

addTok()

return ls

#some tests to make sure it works
print breakLine('caro lina(Prada):cat (X,Y)')
print breakLine('trou ble :bird (X ) &cat ( Y )')
print breakLine('?tro uble')

Jul 22 '06 #1
78 4957
On 2006-07-21 21:05:22, Josiah Manson wrote:
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.
I'm no Python specialist, so here's just some guesses... I don't know how
to make variables known inside the inner function. It seems just using the
names there overrides the outside names. It also seems that local variables
are in some kind of dictionary; so maybe you can access them through that
somehow.

One other solution (a bit ugly) would be to make this a class with two
static methods (breakLine and _addTok) and two static attributes (_ls and
_tok).

Still another (also ugly) would be to pass both tok and ls to addTok() and
pass tok back out again. (I think ls doesn't have to be passed back,
because it is a list and so its data gets modified. tok's data doesn't get
modified, so local changes don't propagate to the outside.)

Gerhard

Jul 22 '06 #2
Gerhard Fiedler wrote:
On 2006-07-21 21:05:22, Josiah Manson wrote:
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.

I'm no Python specialist, so here's just some guesses... I don't know how
to make variables known inside the inner function. It seems just using the
names there overrides the outside names. It also seems that local variables
are in some kind of dictionary; so maybe you can access them through that
somehow.

One other solution (a bit ugly) would be to make this a class with two
static methods (breakLine and _addTok) and two static attributes (_ls and
_tok).

Still another (also ugly) would be to pass both tok and ls to addTok() and
pass tok back out again. (I think ls doesn't have to be passed back,
because it is a list and so its data gets modified. tok's data doesn't get
modified, so local changes don't propagate to the outside.)

Gerhard
That third option seems to work fine.

def breakLine(s):
"""Break a string into a list of words and symbols.
"""

def addTok(tok, ls):
if len(tok) 0:
ls.append(tok)
tok = ''
return tok

ls = []
tok = ''
splitters = '?()&|:~,'
whitespace = ' \t\n\r'

for c in s:
if c in splitters:
tok = addTok(tok, ls)
ls.append(c)
elif c in whitespace:
tok = addTok(tok, ls)
else:
tok = tok + c

tok = addTok(tok, ls)

return ls

#some tests to make sure it works
print breakLine('caro lina(Prada):cat (X,Y)')
print breakLine('trou ble :bird (X ) &cat ( Y )')
print breakLine('?tro uble')

# Prints:
['carolina', '(', 'Prada', ')', ':', 'cat', '(', 'X', ',', 'Y', ')']
['trouble', ':', 'bird', '(', 'X', ')', '&', 'cat', '(', 'Y', ')']
['?', 'trouble']

Jul 22 '06 #3
Simon Forman wrote:
That third option seems to work fine.
Well it does, but there are still many things wrong with it

if len(tok) 0:
should be written as
if(tok):

tok = ''
tok = toc + c
should be written as
tok = []
tok.append(c)
and later
''.join(toc)

anyway, the entire thing should be replaced with something like this:
import re
def breakLine(s):
splitters = '?()&|:~,'
chars = '^ \t\n\r\f\v%s' % splitters
regex = '''(
(?:[%s])
|
(?:[%s]+))''' % (splitters, chars)
return re.findall(rege x, s,re.VERBOSE)

That should be able to be simplified even more if one were to use the
character lists built into the regex standard.

--
- Justin

Jul 22 '06 #4
In message <11************ **********@m79g 2000cwm.googleg roups.com>, Justin
Azoff wrote:
Simon Forman wrote:
>That third option seems to work fine.

Well it does, but there are still many things wrong with it

if len(tok) 0:
should be written as
if(tok):
I prefer the first way. Besides, your way is sub-optimal.
Jul 22 '06 #5
Thank you for your corrections to the previous code. Your regex
solution is definitely much cleaner. Referring to your other
suggestions, is the advantage of using a list of chars instead of
adding to a string just a bow to big-O complexity, or are there other
considerations? First I had tried appending to the string, but it seems
they are immutable. It seems that using a list for a string isn't a
very clear way to represent a mutable string.

Although I gladly accept that using a regex is the best solution to
this problem, I am still interested in knowing how to access the
variables in a containing function. It seems that there should be some
keyword akin to global that would expose them, or some other method. I
have read that python uses nested scopes (or at least was planning to
in 2.2), so I wonder what I am missing.

Jul 22 '06 #6
I just did some timings, and found that using a list instead of a
string for tok is significantly slower (it takes 1.5x longer). Using a
regex is slightly faster for long strings, and slightly slower for
short ones. So, regex wins in both berevity and speed!

Jul 22 '06 #7
Josiah Manson wrote:
I just did some timings, and found that using a list instead of a
string for tok is significantly slower (it takes 1.5x longer). Using a
regex is slightly faster for long strings, and slightly slower for
short ones. So, regex wins in both berevity and speed!
I think the list.append method of building strings may only give you
speed improvements when you are adding bigger chunks of strings
together instead of 1 character at a time. also:

http://docs.python.org/whatsnew/node...00000000000000

"""String concatenations in statements of the form s = s + "abc" and s
+= "abc" are now performed more efficiently in certain circumstances.
This optimization won't be present in other Python implementations such
as Jython, so you shouldn't rely on it; using the join() method of
strings is still recommended when you want to efficiently glue a large
number of strings together. (Contributed by Armin Rigo.)"""

I tested both, and these are my results for fairly large strings:

justin@latitude :/tmp$ python /usr/lib/python2.4/timeit.py -s'import
foo' 'foo.test(foo.b reakLine)'
10 loops, best of 3: 914 msec per loop

justin@latitude :/tmp$ python /usr/lib/python2.4/timeit.py -s'import
foo' 'foo.test(foo.b reakLineRE)'
10 loops, best of 3: 289 msec per loop

--
- Justin

Jul 22 '06 #8
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 = ''
First point: the nested function only have access to names that exists
in the enclosing namespace at the time it's defined.

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.

Third point : functions modifying their environment this way are usually
considered bad form.

Here's a possible solution - but note that there are probably much
better ways to get the same result...

def breakline(line) :
"""Break a string into a list of words and symbols."""
class TokenList(list) :
def append(self, token):
if token:
list.append(sel f, token)
return ''

tokens = TokenList()
token = ''
splitters = '?()&|:~,'
whitespace = ' \t\n\r'
specials = splitters + whitespace

for char in line:
if char in specials:
token = tokens.append(t oken)
if char in splitters:
tokens.append(c har)
else:
token += char

tokens.append(t oken)
return list(tokens)

(snip)
Jul 22 '06 #9
Justin Azoff a écrit :
Simon Forman wrote:
>>That third option seems to work fine.


Well it does, but there are still many things wrong with it
(snip)
tok = ''
tok = toc + c
should be written as
tok = []
tok.append(c)
and later
''.join(toc)
IIRC, string concatenation slowness has been fixed a few versions ago -
at least in CPython - , so there's no more reason to use this idiom.

(snip)
Jul 22 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
2567
by: Andy Baker | last post by:
Hi there, I'm learning Python at the moment and trying to grok the thinking behind it's scoping and nesting rules. I was googling for nested functions and found this Guido quote: (http://www.python.org/search/hypermail/python-1993/0343.html) "This is because nested function definitions don't have access to the local variables of the surrounding block -- only to the globals of the
3
1828
by: jena | last post by:
Hi I have code # BEGIN CODE def test(): def x(): print a a=2 # *** a=1
10
15097
by: Phil Reardon | last post by:
Ive been away from programming for a few years and am having difficulty accessing a function from a math/engineering library that I want to use . I thought that double foo(double); inserted in the calling routine would let me say x=foo(y); But I get a warning from the compilation that says "warning: nested extern declaration of 'foo'. Thanks for any suggestions
9
2490
by: Javaman59 | last post by:
Using local declarations within a block often makes code more readable, but is it less efficient? eg... void P() { while (...) { int i = ...; bool b = ...; .... } }
37
2785
by: Tim N. van der Leeuw | last post by:
Hi, The following might be documented somewhere, but it hit me unexpectedly and I couldn't exactly find this in the manual either. Problem is, that I cannot use augmented assignment operators in a nested scope, on variables from the outer scope: PythonWin 2.4.3 (#69, Mar 29 2006, 17:35:34) on win32. Portions Copyright 1994-2004 Mark Hammond (mhammond@skippinet.com.au) -
7
1305
by: biner.sebastien | last post by:
I have a problem understanding the scope of variable in nested function. I think I got it nailed to the following example copied from Learning Python 2nd edition page 205. Here is the code. def f1() : x=88 f2() def f2() : print 'x=',x f1()
4
2315
by: Wolfgang Draxinger | last post by:
If you know languages like Python or D you know, that nested functions can be really handy. Though some compilers (looking at GCC) provide the extension of nested functions, I wonder, how one could implement an equivalent behaviour with plain C (in this case I'm thinking of the language I'm developing, which shall be converted into C for target compilation). So far I didn't touch the topic "nested functions", since I just don't see an...
0
200
by: Maric Michaud | last post by:
Le Tuesday 12 August 2008 11:29:18 Cousson, Benoit, vous avez écrit : This is a language limitation. This is because nested scope is implemented for python function only since 2.3 allow late binding of free variables. the scope in class statment is not a closure, so there is only two possible scope in it : local and global. When "class C2(C1):" statment is interpreted, it is in the scope of class B for which a name C1 exists, but it...
0
154
by: Cousson, Benoit | last post by:
This is a language limitation. That was my understanding as well, but I think it is a pity to have that limitation. Don't you think that the same improvement that was done for method nested scope could be done as well for nested class? I can easily fix my current issue by doing the binding after the class declaration. My concern is more about the lack of symmetry of that approach; meaning that if both classes are in the global scope, one...
0
8964
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8786
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9466
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9327
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
4564
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4823
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3277
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2740
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2190
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.