473,729 Members | 2,164 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Nested scopes and class variables

I ran into an odd little edge case while experimenting with functions that
create classes on the fly (don't ask me why):
def f(x): ... class C(object):
... x = x
... print C.x
... f(5) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in f
File "<stdin>", line 3, in C
NameError: name 'x' is not defined

"x" clearly is defined, but apparently Python is not looking at the nested
variable scope to find it. What's stranger is that if I rename the parameter
"x" to "y", the error goes away:
def f(y): ... class C(object):
... x = y
... print C.x
... f(5) 5

So, it's not like nested scopes aren't supported in the class block. Rather,
when it sees "x = x", it seems like Python is determining at that point that
"x" is a class variable, and refuses to search any further.

At the top-level, it works as expected:
x = 5
class C(object): ... x = x
... C.x

5

Any implementation gurus have some insight into what's going on here?

--
.:[ dave benjamin: ramen/[sp00] -:- spoomusic.com -:- ramenfest.com ]:.
"talking about music is like dancing about architecture."
Jul 18 '05 #1
5 1805
To me it seems you should do it something like this:
-def f(x):
- class C(object):
- def __init__(self, x):
- self.x = x # here you set the attribute for class C
- c = C(x) # instantiate a C object
- print c.x

-f(5)

Jul 18 '05 #2
Dave Benjamin wrote:
I ran into an odd little edge case while experimenting with functions that
create classes on the fly (don't ask me why):


It gets even kookier:
Py> x = 5
Py> def f(y):
.... class C(object):
.... x = x
.... print C.x
....
Py> f(5) # OK with x bound at global
5

Py> def f(x):
.... class C(object):
.... x = x
.... print C.x
....
Py> f(6) # Oops, ignores the argument!
5

Py> def f(y):
.... class C(object):
.... x = y
.... print C.x
....
Py> f(6) # OK with a different name
6
Py> y = 5
Py> def f(y):
.... class C(object):
.... x = y
.... print C.x
....
Py> f(6) # Correctly use the nearest scope
6

That second case is the disturbing one - the class definition has silently
picked up the *global* binding of x, whereas the programmer presumably meant the
function argument.

With a nested function definition (instead of a class definition), notice that
*both* of the first two cases will generate an UnboundLocalErr or.

Anyway, the Python builtin disassembler is very handy when looking at behaviour
like this (I've truncated the dis output below after the interesting section):

Py> import dis
Py> def f1(x):
.... class C(object):
.... x = x
.... print C.x
....
Py> def f2(y):
.... class C(object):
.... x = y
.... print C.x
....

Py> dis.dis(f1)
2 0 LOAD_CONST 1 ('C')
3 LOAD_GLOBAL 0 (object)
6 BUILD_TUPLE 1
9 LOAD_CONST 2 (<code object C at 00B3E3E0, file "<s
tdin>", line 2>)
[...]

Py> dis.dis(f2)
2 0 LOAD_CONST 1 ('C')
3 LOAD_GLOBAL 0 (object)
6 BUILD_TUPLE 1
9 LOAD_CLOSURE 0 (y)
12 LOAD_CONST 2 (<code object C at 00B3E020, file "<s
tdin>", line 2>)
[...]

Notice the extra LOAD_CLOSURE call in the second version of the code. What if we
define a function instead of a class?:

Py> def f3(x):
.... def f():
.... x = x
.... print x
.... f()
....

Py> def f4(y):
.... def f():
.... x = y
.... print x
.... f()
....

Py> dis.dis(f3)
2 0 LOAD_CONST 1 (<code object f at 00B3EA60, file "<s
tdin>", line 2>)
[...]

Py> dis.dis(f4)
2 0 LOAD_CLOSURE 0 (y)
3 LOAD_CONST 1 (<code object f at 00B3EC60, file "<s
tdin>", line 2>)
[...]

Again, we have the extra load closure call. So why does the function version
give us an unbound local error, while the class version doesn't?. Again, we look
at the bytecode - this time of the corresponding internal code objects:

Py> dis.dis(f1.func _code.co_consts[2])
2 0 LOAD_GLOBAL 0 (__name__)
3 STORE_NAME 1 (__module__)

3 6 LOAD_NAME 2 (x)
9 STORE_NAME 2 (x)
12 LOAD_LOCALS
13 RETURN_VALUE

Py> dis.dis(f3.func _code.co_consts[1])
3 0 LOAD_FAST 0 (x)
3 STORE_FAST 0 (x)

4 6 LOAD_FAST 0 (x)
9 PRINT_ITEM
10 PRINT_NEWLINE
11 LOAD_CONST 0 (None)
14 RETURN_VALUE

In this case, it's the LOAD_FAST opcode that blows up, while the LOAD_NAME falls
back on the globals and then the builtins. Looking at the class based version
that works also lets us see why:

Py> dis.dis(f2.func _code.co_consts[2])
2 0 LOAD_GLOBAL 0 (__name__)
3 STORE_NAME 1 (__module__)

3 6 LOAD_DEREF 0 (y)
9 STORE_NAME 3 (x)
12 LOAD_LOCALS
13 RETURN_VALUE

Here we can see the "LOAD_DEREF " instead of the "LOAD_NAME" that was present in
the version where the same name is reused. The dereference presumably picks up
the closure noted earlier.

I vote bug. If the assignment is going to be allowed, it should respect the
nested scopes.

Cheers,
Nick.

--
Nick Coghlan | nc******@email. com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #3
wi******@hotmai l.com wrote:
To me it seems you should do it something like this:
-def f(x):
- class C(object):
- def __init__(self, x):
- self.x = x # here you set the attribute for class C
- c = C(x) # instantiate a C object
- print c.x

-f(5)


That does something different - in this case, x is an instance variable, not a
class variable.

You do raise an interesting questions though:

Py> def f(x):
.... class C(object):
.... x = None
.... def __init__(self):
.... if C.x is None:
.... C.x = x
.... C()
.... print C.x
....
Py> x = 5
Py> f(6)
6

So, the real problem here is the interaction between the ability to write
"<name> = <name>" in a class definition with the reference on the RHS being
resolved in the global namespace and nested scopes (since that first lookup does
NOT respect nested scopes).

Functions don't have the problem, since they don't allow that initial lookup to
be made from the outer scope.

Cheers,
Nick.

--
Nick Coghlan | nc******@email. com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #4
Dave Benjamin <ra***@lackingt alent.com> wrote:
I ran into an odd little edge case while experimenting with functions that
create classes on the fly (don't ask me why):
"Why not?". But classes have little to do with it, in my view.

>>> def f(x): ... class C(object):
... x = x


You bind x, so x is local (to the class), not free. Videat, classless:
def f(x): .... def g():
.... x=x
.... return x
.... return g
.... z=f(23)
z() Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in g
UnboundLocalErr or: local variable 'x' referenced before assignment

In this example the error is discovered when the body of g executes; in
your case, the body of C executes as part of the class statement, i.e.
when f is called, so the error is discovered earlier.
"x" clearly is defined, but apparently Python is not looking at the nested
variable scope to find it. What's stranger is that if I rename the parameter
"x" to "y", the error goes away:
Why is this strange? There's no name conflict then.
So, it's not like nested scopes aren't supported in the class block. Rather,
when it sees "x = x", it seems like Python is determining at that point that
"x" is a class variable, and refuses to search any further.
That's like saying that nested scopes aren't supported in a function...
when Python sees "x = x", etc etc.
At the top-level, it works as expected:
>>> x = 5
>>> class C(object): ... x = x
... >>> C.x

5

Any implementation gurus have some insight into what's going on here?


Class bodies and function bodies are compiled slightly differently,
leading to a "handy specialcasing" of globals in the latter example
which is probably what's confusing you. OK, let's try digging into more
detail:
def f(x): .... class C:
.... x = x
.... return C
.... dis.dis(f) 2 0 LOAD_CONST 1 ('C')
3 BUILD_TUPLE 0
6 LOAD_CONST 2 (<code object C at 0x389860,
file "<stdin>", line 2>)
9 MAKE_FUNCTION 0
12 CALL_FUNCTION 0
15 BUILD_CLASS
16 STORE_FAST 1 (C)

4 19 LOAD_FAST 1 (C)
22 RETURN_VALUE

this shows you where the codeobject for C's body is kept -- constant
number two among f's constants. OK then:
dis.dis(f.func_ code.co_consts[2]) 2 0 LOAD_GLOBAL 0 (__name__)
3 STORE_NAME 1 (__module__)

3 6 LOAD_NAME 2 (x)
9 STORE_NAME 2 (x)
12 LOAD_LOCALS
13 RETURN_VALUE

Compare with:
def f(x): .... def g():
.... x = x
.... return x
.... return g
.... dis.dis(f) 2 0 LOAD_CONST 1 (<code object g at 0x389620,
file "<stdin>", line 2>)
3 MAKE_FUNCTION 0
6 STORE_FAST 1 (g)

5 9 LOAD_FAST 1 (g)
12 RETURN_VALUE
and:
dis.dis(f.func_ code.co_consts[1])

3 0 LOAD_FAST 0 (x)
3 STORE_FAST 0 (x)

4 6 LOAD_FAST 0 (x)
9 RETURN_VALUE
See the difference? In a function, the 'x = x' compiles into LOAD_FAST,
STORE_FAST, which only looks at locals and nowhere else. In a
classbody, it compiles to LOAD_NAME, STORE_NAME, which looks at locals
AND globals -- but still not at closure cells...
Alex
Jul 18 '05 #5
Alex Martelli wrote:
def f(x):
... class C:
... x = x
... return C
...
[snip]def f(x):

... def g():
... x = x
... return x
... return g
...

[snip]
See the difference? In a function, the 'x = x' compiles into LOAD_FAST,
STORE_FAST, which only looks at locals and nowhere else. In a
classbody, it compiles to LOAD_NAME, STORE_NAME, which looks at locals
AND globals -- but still not at closure cells...


Is there a reason why the class body doesn't look at closure cells?
That is, are there cases where this lookup scheme is preferred to one
that checks locals, closure cells and globals?

Steve

P.S. Question disclaimer:
My questions here are founded in a curiosity about language design, and
are not intended as an attack on Python. =)
Jul 18 '05 #6

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

Similar topics

12
1406
by: Tim Daneliuk | last post by:
I am a bit confused. I was under the impression that: class foo(object): x = 0 y = 1 means that x and y are variables shared by all instances of a class. But when I run this against two instances of foo, and set the values of x and y, they are indeed unique to the *instance* rather than the class.
6
312
by: Nick Dreyer | last post by:
In VB.NET I would like to not have to create property get/set procedures for every class variable I want to expose to Excel VBA projects in COM builds. Can anyone tell me if that is possible, or refer me to some documents that will make me understand why this apparent limitation of VB.NET COM builds is acceptable, i.e. why in "good" object code programs I should expect to never have to create large numbers of public class variables that...
12
1790
by: Andrew Jaffe | last post by:
Hi, I have a class with various class-level variables which are used to store global state information for all instances of a class. These are set by a classmethod as in the following (in reality the setcvar method is more complicated than this!): class sup(object): cvar1 = None cvar2 = None
4
2497
by: Nick Dreyer | last post by:
Is it possible to see public class variables of a COM addin in Excel 97 VBA? I have successfully created the (Visual Basic 2003 .NET) COM and referenced it in an Excel 97 VBA project. The VBA object browser sees - and the project otherwise successfully interacts with - all the COM addin methods and properties, but none of the public variables - target, init and size in the code below - can be accessed. When I reference the exact same...
9
3138
by: Lonewolf | last post by:
Hi everyone.. I was trying to implement callback fucntions in native codes in my VC8 class, and referred to some online codes which use native class nested within managed class. basically of the form, __gc class CManagedClass { __nogc CNativeClass {
37
2784
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) -
9
2215
by: Rory Campbell-Lange | last post by:
We have a set of classes using static methods to retain reference variables between operations. The problem is that the static variables are not reset between operations when used through mod_python. Although it is possible to reset the class variables between invocations of the system, this has the potential of 'wiping out' these variables when another user is using the system. Is there a way of getting the equivalent of 'local class...
9
1965
by: Adam Nielsen | last post by:
Hi all, I'm a bit confused about the syntax used to access a nested template class. Essentially I have a bunch of class types to represent different types of records in a database, and I want to store some cache data for each datatype. The simplified code below demonstrates my issue - I think I understand why it doesn't work as is (the structure only declares the storage, I need to instantiate it for each template type) but I'm not...
2
1751
by: puzzlecracker | last post by:
How will this actually work: public class Foo<T> { public class Bar<T> { private T t; }
0
8764
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
9289
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...
1
9210
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8159
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6026
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
4798
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3242
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
2694
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2166
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.