Strange Class definition
Peter Otten
__peter__ at web.de
Mon Sep 16 11:46:59 EDT 2019
ast wrote:
> Hello
>
> Following syntax doesn't generate any errors:
>
> >>> foo=0
> >>> Class Foo:
> foo
>
> But class Foo seems empty
>
> Is it equivalent to ?
>
> >>> class Foo:
> pass
The resulting class is equivalent, but the expression `foo` is actually
evaluated during class creation. You can easily see this when you replace
foo with a print call, say:
>>> for foo in "first", "second":
... class A: print(foo)
...
first
second
If you compare the byte code you may note a small difference to def f(): foo
>>> import dis
>>> c = compile("class A: foo", "<nofile", "exec")
>>> dis.dis(c)
1 0 LOAD_BUILD_CLASS
1 LOAD_CONST 0 (<code object A at
0x7f9cce602ae0, file "<nofile", line 1>)
4 LOAD_CONST 1 ('A')
7 MAKE_FUNCTION 0
10 LOAD_CONST 1 ('A')
13 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
16 STORE_NAME 0 (A)
19 LOAD_CONST 2 (None)
22 RETURN_VALUE
>>> c.co_consts[0]
<code object A at 0x7f9cce602ae0, file "<nofile", line 1>
>>> dis.dis(c.co_consts[0])
1 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
6 LOAD_CONST 0 ('A')
9 STORE_NAME 2 (__qualname__)
The relevant instruction:
12 LOAD_NAME 3 (foo)
15 POP_TOP
16 LOAD_CONST 1 (None)
19 RETURN_VALUE
For comparison a function:
>>> def f(): foo
...
>>> dis.dis(f)
1 0 LOAD_GLOBAL 0 (foo)
3 POP_TOP
4 LOAD_CONST 0 (None)
7 RETURN_VALUE
In the class body LOAD_NAME is used instead of LOAD_GLOBAL. This allows
dynamical scoping
>>> foo = "outer"
>>> class A:
... print(foo)
... foo = "inner"
... print(foo)
...
outer
inner
>>> A.foo
'inner'
whereas in the function you get an error:
>>> def f():
... print(foo)
... foo = "inner"
... print(foo)
...
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
UnboundLocalError: local variable 'foo' referenced before assignment
More information about the Python-list
mailing list