Dave Benjamin <[EMAIL PROTECTED]> 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 UnboundLocalError: 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 -- http://mail.python.org/mailman/listinfo/python-list