473,738 Members | 2,009 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Reasoning behind nested scope

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/hyperma...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
containing module. This is done so that lookup of globals doesn't
have to walk a chain of dictionaries -- as in C, there are just two
nested scopes: locals and globals (and beyond this, built-ins).
Therefore, nested functions have only a limited use. This was a
deliberate decision, based upon experience with languages allowing
arbitraries nesting such as Pascal and both Algols -- code with too
many nested scopes is about as readable as code with too many GOTOs.
And, of course, in Python, the "proper" way is to use an
object-oriented programming style"

This sounds reasonable to me although nested scope always struck me as more
natural and intuitive ('Don't be surprising')

I was wondering how the balance changed in favour of nested scope? What
changed people's minds about 'readability' vs other factors? Are nested
scopes still regarded as leading to spagetti code etc?

(On a side note is there any way to call a nested function from outside the
parent? I was kind of expecting nested functions to be addressable through
dot notation like methods are but I can see why that wouldn't be quite
right. This might be a better question for the tutor list...)

Andy Baker

Jul 18 '05 #1
6 2567
Ever since my first Fortran class some 30+ years ago
I've always liked nested scopes. If you want something
to be global, say so in your code. In Fortran we used
common blocks, in Python you use a global directive.
Making everything global can lead to many name clashes
or you must have lots of unique variable names which
lengthens code and makes reuse more difficult.

Judicious use of OOP and globals seems to be the best
approach. The more I learn/use OOP the less I seem
to require globals, but there are some times they
seem a preferable solution.

I don't believe there is any way to call nested
functions from outside their parent. If you need
something like that, make the function a class and
make the nested function a method of the class.

HTH,
Larry Bates
Syscon, Inc.
"Andy Baker" <an**@andybak.n et> wrote in message
news:ma******** *************** *************** @python.org...
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/hyperma...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
containing module. This is done so that lookup of globals doesn't
have to walk a chain of dictionaries -- as in C, there are just two
nested scopes: locals and globals (and beyond this, built-ins).
Therefore, nested functions have only a limited use. This was a
deliberate decision, based upon experience with languages allowing
arbitraries nesting such as Pascal and both Algols -- code with too
many nested scopes is about as readable as code with too many GOTOs.
And, of course, in Python, the "proper" way is to use an
object-oriented programming style"

This sounds reasonable to me although nested scope always struck me as more natural and intuitive ('Don't be surprising')

I was wondering how the balance changed in favour of nested scope? What
changed people's minds about 'readability' vs other factors? Are nested
scopes still regarded as leading to spagetti code etc?

(On a side note is there any way to call a nested function from outside the parent? I was kind of expecting nested functions to be addressable through
dot notation like methods are but I can see why that wouldn't be quite
right. This might be a better question for the tutor list...)

Andy Baker

Jul 18 '05 #2
In article <ma************ *************** ***********@pyt hon.org>,
"Andy Baker" <an**@andybak.n et> wrote:
"This is because nested function definitions don't have access to the
local variables of the surrounding block -- only to the globals of the
containing module. This is done so that lookup of globals doesn't
have to walk a chain of dictionaries -- as in C, there are just two
nested scopes: locals and globals (and beyond this, built-ins).
Therefore, nested functions have only a limited use. This was a
deliberate decision, based upon experience with languages allowing
arbitraries nesting such as Pascal and both Algols -- code with too
many nested scopes is about as readable as code with too many GOTOs.
And, of course, in Python, the "proper" way is to use an
object-oriented programming style"

This sounds reasonable to me although nested scope always struck me as more
natural and intuitive ('Don't be surprising')

I was wondering how the balance changed in favour of nested scope? What
changed people's minds about 'readability' vs other factors? Are nested
scopes still regarded as leading to spagetti code etc?
I guess a consensus built up that the power/safety
tradeoff had given too much emphasis to safety.

My own poster child for nested scopes is in some old post
on c.l.p . I wanted to build a lot of similar labelled text
controls in wxPython, following a naming convention. I
could have written a function, but pre-nested-scope, any
change I made to the information used in building the
controls would have meant changing the function parameter
list, and all the function calls. I came up with a template
string which got parameter substituted via the '%' operator,
and then `exec`ed so as code it had full access to all the
info that was in the contemporary scope.

Post nested scope, any info the function needed from the
surrounding scope could simply be read from there. The code
was much less unusual.

I believe (without proof) that any language that won't
let me shoot myself in the foot will also prevent me doing
anything useful. Debate is heating up now about write
access to enclosing scopes. We'll see how strong my faith
really is. People will be able to write function nests
instead of classes.
(On a side note is there any way to call a nested function from outside the
parent? I was kind of expecting nested functions to be addressable through
dot notation like methods are but I can see why that wouldn't be quite
right. This might be a better question for the tutor list...)


Yup.

def f1 (a):
if a:
x = 2
else:
x = 3

def f2 (y):
return y % x

return f2

import os
b = f1 (os.name.starts with ('p'))
for c in range (10):
print b (c)

Regards. Mel.
Jul 18 '05 #3
Andy Baker wrote:
(On a side note is there any way to call a nested function from outside
the parent? I was kind of expecting nested functions to be addressable
through dot notation like methods are but I can see why that wouldn't be
quite right. This might be a better question for the tutor list...)


When you are nesting functions, you don't get one function sitting inside
another function. Instead, the function creation code of the "inner"
function is executed every time to the effect that you get a new inner
function every time you call the outer one:
def make(): .... def f(): return "shoobidoo"
.... return f
.... f1 = make()
f2 = make()
f1(), f2() ('shoobidoo', 'shoobidoo') f1 is f2 False

You wouldn't do that in cases like the above, when you get nothing in return
for the extra overhead, but somtimes nesting is useful - because of the
change in the scoping rules you now get readonly-closures:
def make(s): .... def f(): return s
.... return f
.... f1 = make("now")
f2 = make("what")
f1(), f2()

('now', 'what')

Peter

Jul 18 '05 #4
Peter Otten wrote:
Andy Baker wrote:
(On a side note is there any way to call a nested function from outside
the parent? I was kind of expecting nested functions to be addressable
through dot notation like methods are but I can see why that wouldn't be
quite right. This might be a better question for the tutor list...)


When you are nesting functions, you don't get one function sitting inside
another function. Instead, the function creation code of the "inner"
function is executed every time to the effect that you get a new inner
function every time you call the outer one:
def make(): ... def f(): return "shoobidoo"
... return f
... f1 = make()
f2 = make()
f1(), f2() ('shoobidoo', 'shoobidoo') f1 is f2 False

You wouldn't do that in cases like the above, when you get nothing in
return for the extra overhead, but somtimes nesting is useful - because of
the change in the scoping rules you now get readonly-closures:
def make(s): ... def f(): return s
... return f
... f1 = make("now")
f2 = make("what")
f1(), f2()

('now', 'what')

Peter


What work is actually done when the
'nested function creation code of the "inner" function'
is executed?

Given a quick test:-
<code>
def outer():
def inner():
pass
return inner

b1 = outer()
b2 = outer()

attrs=[a for a in dir(b1) if not a.startswith('_ ')]
for a, a1, a2 in zip(attrs,
[getattr(b1,a) for a in attrs],
[getattr(b2,a) for a in attrs]):
print a, a1 is a2

</code>
<result>
func_closure True
func_code True
func_defaults True
func_dict True
func_doc True
func_globals True
func_name True
</result>

it appears that all the components of the inner function are the same, which
just leaves the binding of the code object to 'inner'.

Am I missing something, or is the overhead no worse than, say, foo=self.foo,
where self.foo is a method?
--
Nigel Rowe
A pox upon the spammers that make me write my address like..
rho (snail) swiftdsl (stop) com (stop) au
Jul 18 '05 #5
Nigel Rowe wrote:
Peter Otten wrote:
Andy Baker wrote:
(On a side note is there any way to call a nested function from outside
the parent? I was kind of expecting nested functions to be addressable
through dot notation like methods are but I can see why that wouldn't be
quite right. This might be a better question for the tutor list...)
When you are nesting functions, you don't get one function sitting inside
another function. Instead, the function creation code of the "inner"
function is executed every time to the effect that you get a new inner
function every time you call the outer one:
> def make():

... def f(): return "shoobidoo"
... return f
...
> f1 = make()
> f2 = make()
> f1(), f2()

('shoobidoo', 'shoobidoo')
> f1 is f2

False

You wouldn't do that in cases like the above, when you get nothing in
return for the extra overhead, but somtimes nesting is useful - because
of the change in the scoping rules you now get readonly-closures:
> def make(s):

... def f(): return s
... return f
...
> f1 = make("now")
> f2 = make("what")
> f1(), f2()

('now', 'what')

Peter


What work is actually done when the
'nested function creation code of the "inner" function'
is executed?

Given a quick test:-
<code>
def outer():
def inner():
pass
return inner

b1 = outer()
b2 = outer()

attrs=[a for a in dir(b1) if not a.startswith('_ ')]
for a, a1, a2 in zip(attrs,
[getattr(b1,a) for a in attrs],
[getattr(b2,a) for a in attrs]):
print a, a1 is a2

</code>
<result>
func_closure True
func_code True
func_defaults True
func_dict True
func_doc True
func_globals True
func_name True
</result>

it appears that all the components of the inner function are the same,
which just leaves the binding of the code object to 'inner'.


Not the binding, a new function object is created every time outer is run,
i. e. (faked, but I did it for real above with f1 and f2)
b1 is b2 False
Am I missing something, or is the overhead no worse than, say,
foo=self.foo, where self.foo is a method?


If it were pure Python it would rather be something like

foo = Function(func_c losure=..., func_code=..., ...)

Another perspective is to look at the byte code:
import dis
def outer(): .... def inner(): pass
.... return inner
.... dis.dis(outer) 2 0 LOAD_CONST 1 (<code object inner at
0x4028eee0, file "<stdin>", line 2>)
3 MAKE_FUNCTION 0
6 STORE_FAST 0 (inner)

3 9 LOAD_FAST 0 (inner)
12 RETURN_VALUE
13 LOAD_CONST 0 (None)
16 RETURN_VALUE def inner(): .... pass
.... def outer2(): .... return inner
.... dis.dis(outer2)

2 0 LOAD_GLOBAL 0 (inner)
3 RETURN_VALUE
4 LOAD_CONST 0 (None)
7 RETURN_VALUE

In the example you get three extra instructions, LOAD_CONST, MAKE_FUNCTION
and STORE_FAST (and earn the slight benefit that inner is now a local
instead of a global). A constant code object is used, meaning compilation
takes place at most once when the module is loaded. There is a dedicated
op-code, so function creation should be faster than "normal" creation of a
class instance.

Now this is all nice and dandy, but how do the two contenders perform?

$ timeit.py -s"def inner(): pass" -s"def outer(): return inner" "outer()"
1000000 loops, best of 3: 0.469 usec per loop
$ timeit.py -s"def outer():" -s" def inner(): pass" -s" return inner"
"outer()"
1000000 loops, best of 3: 1.12 usec per loop

i. e. nesting the two functions roughly doubles execution time.
However, creation of an inner function often will only take a small fraction
of the total time spent in the outer function - in the end it's just a
matter of style.

I use inner functions only when they depend on the local context because I
think it nicely discriminates closures from helpers. I tend to omit
implicit parameters even for helper funtions, therefore nesting them would
gain me nothing.

Peter

Jul 18 '05 #6
Peter Otten wrote:
Nigel Rowe wrote:
Peter Otten wrote:
Andy Baker wrote:

<snip>
What work is actually done when the
'nested function creation code of the "inner" function'
is executed?


< snip >

In the example you get three extra instructions, LOAD_CONST, MAKE_FUNCTION
and STORE_FAST (and earn the slight benefit that inner is now a local
instead of a global). A constant code object is used, meaning compilation
takes place at most once when the module is loaded. There is a dedicated
op-code, so function creation should be faster than "normal" creation of a
class instance.

Now this is all nice and dandy, but how do the two contenders perform?

$ timeit.py -s"def inner(): pass" -s"def outer(): return inner" "outer()"
1000000 loops, best of 3: 0.469 usec per loop
$ timeit.py -s"def outer():" -s" def inner(): pass" -s" return inner"
"outer()"
1000000 loops, best of 3: 1.12 usec per loop

i. e. nesting the two functions roughly doubles execution time.
However, creation of an inner function often will only take a small
fraction of the total time spent in the outer function - in the end it's
just a matter of style.

I use inner functions only when they depend on the local context because I
think it nicely discriminates closures from helpers. I tend to omit
implicit parameters even for helper funtions, therefore nesting them would
gain me nothing.

Peter


Thanks Peter, I didn't know about timeit.py (it's now on my $PATH).

I don't think I'm going to worry about the overhead (except in deeply nested
loops). From some quick testing it looks like the overhead is about the
same as 1.5 times
a=b[10:20] # where b="the quick brown jox jumps over the lazy dog"
and less than 1/2 of
a=math.sin(0)

So if the nested code is easier to read, in it goes.
--
Nigel Rowe
A pox upon the spammers that make me write my address like..
rho (snail) swiftdsl (stop) com (stop) au
Jul 18 '05 #7

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

Similar topics

4
4029
by: KInd | last post by:
Hello All, When is nested class more preferable that Inheritance ? I think with proper inheritance and friend class concept we can get the same flexibility as nested classes Any comments .. Best Regards KInd --
3
1829
by: jena | last post by:
Hi I have code # BEGIN CODE def test(): def x(): print a a=2 # *** a=1
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) -
78
4958
by: Josiah Manson | last post by:
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...
5
3123
by: =?Utf-8?B?QUEyZTcyRQ==?= | last post by:
Could someone give me a simple example of nested scope in C#, please? I've searched Google for this but have not come up with anything that makes it clear. I am looking at the ECMA guide and trying to understand Goto in this contect. PS: This is not homework.
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
8968
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
8787
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
9473
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
9208
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
6053
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4824
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3279
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
2744
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2193
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.