classes and cell variables question
to my understanding of the object model, the code of snippet 1
and snippet 2 should be equivalent. a class is just a "special function"
that returns its locals automatically and passes them to the metaclass
constructor:
--- snippet 1 ---
class foo(object):
x = 5
def f(self):
print "f", x
--- snippet 2 ---
def bar():
x = 5
def g(self):
print "g", x
return locals()
barcls = type("barcls", (object,), bar())
but there's one big difference. classes don't create cell variables
to hold bound external variables. the "bar" version works, because
"x" is a bound cell variable, but the "foo" version fails, as it attempts
to access "x" as a global.
.>>> barcls().g()
g 5
.>>> foo().f()
f
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in f
NameError: global name 'x' is not defined
for reference, i attached the code of all four functions below.
my question is, how come classes don't create cell variables, like
normal functions? was this done on purpose? does it have to
do with inheritance? if so, what's wrong with my "bar" version?
[1]
# code of class foo
############################################################
# 2 0 LOAD_NAME 0 (__name__)
# 3 STORE_NAME 1 (__module__)
# 3 6 LOAD_CONST 0 (5)
# 9 STORE_NAME 2 (x)
#
# 4 12 LOAD_CONST 1 ()
# 15 MAKE_FUNCTION 0
# 18 STORE_NAME 3 (f)
# 21 LOAD_LOCALS
# 22 RETURN_VALUE
[2]
# code of foo.f:
############################################################
# 5 0 LOAD_CONST 1 ('f')
# 3 PRINT_ITEM
# 4 LOAD_GLOBAL 0 (x)
# 7 PRINT_ITEM
# 8 PRINT_NEWLINE
# 9 LOAD_CONST 0 (None)
# 12 RETURN_VALUE
[3]
# code of bar:
############################################################
# 2 0 LOAD_CONST 1 (5)
# 3 STORE_DEREF 0 (x)
#
# 3 6 LOAD_CLOSURE 0 (x)
# 9 BUILD_TUPLE 1
# 12 LOAD_CONST 2 (
)
# 15 MAKE_CLOSURE 0
# 18 STORE_FAST 0 (g)
#
# 5 21 LOAD_GLOBAL 0 (locals)
# 24 CALL_FUNCTION 0
# 27 RETURN_VALUE
[4]
# code of bar.g:
############################################################
# 4 0 LOAD_CONST 1 ('g')
# 3 PRINT_ITEM
# 4 LOAD_DEREF 0 (x)
# 7 PRINT_ITEM
# 8 PRINT_NEWLINE
# 9 LOAD_CONST 0 (None)
# 12 RETURN_VALUE
On 12/19/06, tomer filiba
to my understanding of the object model, the code of snippet 1 and snippet 2 should be equivalent. a class is just a "special function" that returns its locals automatically and passes them to the metaclass constructor:
--- snippet 1 --- class foo(object): x = 5 def f(self): print "f", x
--- snippet 2 --- def bar(): x = 5 def g(self): print "g", x return locals() barcls = type("barcls", (object,), bar())
but there's one big difference. classes don't create cell variables to hold bound external variables. the "bar" version works, because "x" is a bound cell variable, but the "foo" version fails, as it attempts to access "x" as a global.
.>>> barcls().g() g 5
.>>> foo().f() f Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in f NameError: global name 'x' is not defined
for reference, i attached the code of all four functions below.
my question is, how come classes don't create cell variables, like normal functions? was this done on purpose? does it have to do with inheritance? if so, what's wrong with my "bar" version?
I did this very much on purpose, although I have to think a bit to remember the reason. I think I didn't want "accidental Java code" where one would define a class variable and reference it from a method without prefixing it with self or the class name and it would accidentally work, but it would be very unpythonic. So I rigged it so that it wouldn't work.
[1] # code of class foo ############################################################ # 2 0 LOAD_NAME 0 (__name__) # 3 STORE_NAME 1 (__module__) # 3 6 LOAD_CONST 0 (5) # 9 STORE_NAME 2 (x) # # 4 12 LOAD_CONST 1 (
) # 15 MAKE_FUNCTION 0 # 18 STORE_NAME 3 (f) # 21 LOAD_LOCALS # 22 RETURN_VALUE
[2] # code of foo.f: ############################################################ # 5 0 LOAD_CONST 1 ('f') # 3 PRINT_ITEM # 4 LOAD_GLOBAL 0 (x) # 7 PRINT_ITEM # 8 PRINT_NEWLINE # 9 LOAD_CONST 0 (None) # 12 RETURN_VALUE
[3] # code of bar: ############################################################ # 2 0 LOAD_CONST 1 (5) # 3 STORE_DEREF 0 (x) # # 3 6 LOAD_CLOSURE 0 (x) # 9 BUILD_TUPLE 1 # 12 LOAD_CONST 2 (
) # 15 MAKE_CLOSURE 0 # 18 STORE_FAST 0 (g) # # 5 21 LOAD_GLOBAL 0 (locals) # 24 CALL_FUNCTION 0 # 27 RETURN_VALUE
[4] # code of bar.g: ############################################################ # 4 0 LOAD_CONST 1 ('g') # 3 PRINT_ITEM # 4 LOAD_DEREF 0 (x) # 7 PRINT_ITEM # 8 PRINT_NEWLINE # 9 LOAD_CONST 0 (None) # 12 RETURN_VALUE _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
tomer filiba schrieb:
my question is, how come classes don't create cell variables, like normal functions?
Not sure what you mean by "how come"? Why is the implementation reacting as it is? Because the body of class is compiled as a global code fragment, not as a nested one. Or why is the implementation the way it is? For several reasons, one being that classes predate nested functions.
was this done on purpose?
Yes. Attributes defined inside a class are assumed to be accessed through attribute access *only*. So you write self.foo() to invoke a method, instead of invoking foo() Python treats methods and data attributes uniformly, so the same applies to data variables.
does it have to do with inheritance? if so, what's wrong with my "bar" version?
It also has to do with inheritance. If you do self.foo, it looks 1. in the object itself 2. in the class of the object 3. in the bases of the class of the object (recursively) It would be counter-intuitive if some things (i.e. things defined in the class itself) could be accessed directly, whereas other things (ie. attributes of the object itself, and things in the base classes) would need to be accessed through qualification. It would also be counter-intuitive if you find methods in an unqualified manner, but then can't call them because you didn't give a self argument. If you don't follow this reasoning, please write a counter-proposal so that people have something to shoot down. Regards, Martin
If you don't follow this reasoning, please write a counter-proposal so that people have something to shoot down.
?
i just wanted to be sure it was done on purpose, and what were the
reasons for that.
-tomer
On 12/20/06, "Martin v. Löwis"
tomer filiba schrieb:
my question is, how come classes don't create cell variables, like normal functions?
Not sure what you mean by "how come"? Why is the implementation reacting as it is? Because the body of class is compiled as a global code fragment, not as a nested one. Or why is the implementation the way it is? For several reasons, one being that classes predate nested functions.
was this done on purpose?
Yes. Attributes defined inside a class are assumed to be accessed through attribute access *only*. So you write
self.foo()
to invoke a method, instead of invoking
foo()
Python treats methods and data attributes uniformly, so the same applies to data variables.
does it have to do with inheritance? if so, what's wrong with my "bar" version?
It also has to do with inheritance. If you do self.foo, it looks 1. in the object itself 2. in the class of the object 3. in the bases of the class of the object (recursively)
It would be counter-intuitive if some things (i.e. things defined in the class itself) could be accessed directly, whereas other things (ie. attributes of the object itself, and things in the base classes) would need to be accessed through qualification. It would also be counter-intuitive if you find methods in an unqualified manner, but then can't call them because you didn't give a self argument.
If you don't follow this reasoning, please write a counter-proposal so that people have something to shoot down.
Regards, Martin
tomer filiba wrote:
to my understanding of the object model, the code of snippet 1 and snippet 2 should be equivalent. a class is just a "special function" that returns its locals automatically and passes them to the metaclass constructor:
PEP 227 (Statically Nested Scopes) covers this in detail (and it echoes Guido's earlier message - the lexical scoping skips class statements because class attributes are intended to be accessed via attribute reference on the class or instance, not as a bare name). You'll probably find the resulting behaviour less surprising if you think of class creation in terms of the exec statement rather than as involving any kind of function definition: d = dict() exec <class body> in globals(), d mcl = _determine_metaclass(d, <class bases>) # Not magic, but close ;) cls = mcl(<class name>, <class bases>, d) Class bodies actually have more in common with module level code than they do with function bodies (e.g. see how far you get trying to pass a function's co_code object to the exec statement - it breaks for reasons somewhat related to what we're discussing here). To go back to your original example, the second snippet should actually look more like this: --- snippet 2a --- body = """ x = 5 def g(self): print "g", x """ d = dict() exec body in globals(), d barcls = type("barcls", (object,), d) ------ .>>> barcls().g() g Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 4, in g NameError: global name 'x' is not defined Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://www.boredomandlaziness.org
On 12/19/06, tomer filiba
to my understanding of the object model, the code of snippet 1 and snippet 2 should be equivalent. a class is just a "special function" that returns its locals automatically and passes them to the metaclass constructor:
--- snippet 1 --- class foo(object): x = 5 def f(self): print "f", x
--- snippet 2 --- def bar(): x = 5 def g(self): print "g", x return locals() barcls = type("barcls", (object,), bar())
but there's one big difference. classes don't create cell variables to hold bound external variables. the "bar" version works, because "x" is a bound cell variable, but the "foo" version fails, as it attempts to access "x" as a global.
Others have explained the rationale for this design choice, and the PEP is a good source for what we were thinking at the time. I thought it was worth adding that a) class variables can never be access as free variables, as your example foo() shows, and b) you could access a variable bound in a function scope in a method. Example of b): def spam(): x = 5 # provides the binding for the free variable x in methods of eggs class eggs(object): x = 6 # irrelevant for purposes of resolving the free variable in the method spam def spam(self): # can't have too much spam return x return eggs spam()().spam() should return 5. Jeremy
.>>> barcls().g() g 5
.>>> foo().f() f Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in f NameError: global name 'x' is not defined
for reference, i attached the code of all four functions below.
my question is, how come classes don't create cell variables, like normal functions? was this done on purpose? does it have to do with inheritance? if so, what's wrong with my "bar" version?
[1] # code of class foo ############################################################ # 2 0 LOAD_NAME 0 (__name__) # 3 STORE_NAME 1 (__module__) # 3 6 LOAD_CONST 0 (5) # 9 STORE_NAME 2 (x) # # 4 12 LOAD_CONST 1 (
) # 15 MAKE_FUNCTION 0 # 18 STORE_NAME 3 (f) # 21 LOAD_LOCALS # 22 RETURN_VALUE
[2] # code of foo.f: ############################################################ # 5 0 LOAD_CONST 1 ('f') # 3 PRINT_ITEM # 4 LOAD_GLOBAL 0 (x) # 7 PRINT_ITEM # 8 PRINT_NEWLINE # 9 LOAD_CONST 0 (None) # 12 RETURN_VALUE
[3] # code of bar: ############################################################ # 2 0 LOAD_CONST 1 (5) # 3 STORE_DEREF 0 (x) # # 3 6 LOAD_CLOSURE 0 (x) # 9 BUILD_TUPLE 1 # 12 LOAD_CONST 2 (
) # 15 MAKE_CLOSURE 0 # 18 STORE_FAST 0 (g) # # 5 21 LOAD_GLOBAL 0 (locals) # 24 CALL_FUNCTION 0 # 27 RETURN_VALUE
[4] # code of bar.g: ############################################################ # 4 0 LOAD_CONST 1 ('g') # 3 PRINT_ITEM # 4 LOAD_DEREF 0 (x) # 7 PRINT_ITEM # 8 PRINT_NEWLINE # 9 LOAD_CONST 0 (None) # 12 RETURN_VALUE _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/jeremy%40alum.mit.edu
On 12/29/06, Jeremy Hylton
def spam(): x = 5 class eggs(object): x = 6 def spam(self): return x return eggs
spam()().spam() should return 5.
the question that arises is -- is this what we wanted? if i had to read such code, where i can't (easily) tell where "x" is bound to, i wouldn't be content, to say the least. -tomer
On 12/29/06, tomer filiba
On 12/29/06, Jeremy Hylton
wrote: def spam(): x = 5 class eggs(object): x = 6 def spam(self): return x return eggs
spam()().spam() should return 5.
the question that arises is -- is this what we wanted? if i had to read such code, where i can't (easily) tell where "x" is bound to, i wouldn't be content, to say the least.
It's obfuscated code. But there is no doubt that these are the semantics that we wanted, and still want. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
participants (5)
-
"Martin v. Löwis"
-
Guido van Rossum
-
Jeremy Hylton
-
Nick Coghlan
-
tomer filiba