Why can't a Python class definition assign itself a closure variable?

Why doesn't it work in Python?

def make_class(a):
    class A(object):
        a=a
    return A

      

+2


source to share


4 answers


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 statement global

or nonlocal

mean the assigned name is local to the current scope. This happens not only in functions, but also in class definitions.



This means that you cannot use the same name for a global and a local variable and use both of them. 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

      

+6


source


works great:

>>> def make_class(a):
    class A(object):
        _a=a
    return A

>>> make_class('df')
<class '__main__.A'>
>>> make_class('df')._a
'df'

      



btw is function

not a reserved keyword in Python.

+9


source


Both 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

      

+2


source


Try

def make_class(a):
    class A(object): pass
    A.a=a
    return A

      

The error you are getting ( NameError: name 'a' is not defined

) is that the name a

in the class is shadowing the a

function parameter ; so there isn't a

one defined when trying "a = a" in your code. In other words, the right side is a

not a

from def

; instead, Python looks for it in the class a

as it was a

already mentioned on the left side of the assignment.

It gets cleaner 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 option x

of a

must shade the global variable x

. b

is defined in the area where it x

is known as a parameter a

, so printing works.

If you try to call c

, you get UnboundLocalError: local variable 'x' referenced before assignment

as Python does not automatically bind global variables. To fix this, you must add global x

before assigning.

Your case looks something like this:

x = 1
def a(x):
    print 'a:',x
    x = 3
    def b():
        x = x
        print 'b:',x
    b()
a(2)

      

When printing x

in the above example, assignment does not work. This is a safety measure to make sure the variables don't leak. The solution is to use the default parameter to "copy" the variable to the scope b

:

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 need to tell the Python "to make option a

of make_class

visible in a

", and you will need to do this before you try to assign a field a

class. This is not possible in Python. If you could make it a

visible, the assignment would change the parameter, not the field, since Python has no way of distinguishing the two.

Since you cannot make it visible, there is no a

readable, hence NameError

.

See here for an explanation of name scope in Python.

+2


source







All Articles