Why doesn't the following work in Python?
def make_class(a):
class A(object):
a=a
return A
Why doesn't the following work in Python?
def make_class(a):
class A(object):
a=a
return A
Both appear to work fine (in Python 2.5, at least):
>>> def make_class(a):
... class A(object):
... _a = a
... return A
...
>>> make_class(10)._a
10
>>> def make_class(b):
... class B(object):
... def get_b(self):
... return b
... return B
...
>>> make_class(10)().get_b()
10
works just fine:
>>> def make_class(a):
class A(object):
_a=a
return A
>>> make_class('df')
<class '__main__.A'>
>>> make_class('df')._a
'df'
btw, function
is not a reserved keyword in Python.
Try
def make_class(a):
class A(object): pass
A.a=a
return A
The error you get (NameError: name 'a' is not defined
) is because the name a
in the class shadows the parameter a
of the function; hence there is no a
defined when you try "a=a" in your code. In other words, the right side a
is not the a
from the def
; instead Python looks for it in the class A
since a
was already mentioned on the left side of the assignment.
This becomes more clean with functions:
x = 1
def a(x):
print 'a:',x
x = 3
def b():
print 'b:',x
b()
a(2)
def c():
x = x
Obviously, the first print should print 2, not 1, so the parameter x
of a
must shadow the global variable x
. b
is defined in a scope where x
is known as a parameter of a
, so the print works.
If you try to call c
, however, you get UnboundLocalError: local variable 'x' referenced before assignment
since Python doesn't bind global variables automatically. To fix this, you must add global x
before the assignment.
Your case looks more like this:
x = 1
def a(x):
print 'a:',x
x = 3
def b():
x = x
print 'b:',x
b()
a(2)
While printing x
worked in the example above, assignment doesn't work. This is a safety measure to make sure that variables don't leak. The solution is to use a default parameter to "copy" the variable into b
's scope:
x = 1
def a(x):
print 'a:',x
x = 3
def b(x=x):
x = x
print 'b:',x
b()
a(2)
To solve your problem, you would need to tell Python "make the parameter a
of make_class
visible in A
" and you would need to do that before you try to assign the field a
of the class. This is not possible in Python. If you could make a
visible, the assignment would change the parameter, not the field, since Python has no way to distinguish the two.
Since you can't make it visible, there is no a
to read from, hence the NameError
.
See here for an explanation of the scope of a name in Python.
Let's use a simpler example for the same problem:
a = 'something'
def boo():
a = a
boo()
This fails because assignments in python, without an accompanying global
or nonlocal
statement, means that the assigned name is local to the current scope. This happens not just in functions but also in class definitions.
This means that you can't use the same name for a global and local variable and use them both. You can use the workaround from Aaron Digulia's answer, or use a different name:
def make_class(_a):
class A(object):
a = _a
return A