为什么 Python 类定义不能将闭包变量分配给自身?

发布于 2024-08-05 14:30:15 字数 120 浏览 2 评论 0原文

为什么以下代码在 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

把时间冻结 2024-08-12 14:30:15

工作得很好:

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

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

顺便说一句,function 不是 Python 中的保留关键字。

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.

鸢与 2024-08-12 14:30:15

让我们用一个更简单的例子来解决同样的问题:

a = 'something'
def boo():
    a = a
boo()

这会失败,因为 python 中的赋值没有附带 globalnonlocal 语句,这意味着分配的名称是当前范围的本地名称。这种情况不仅发生在函数中,也发生在类定义中。

这意味着您不能对全局变量和局部变量使用相同的名称并同时使用它们。您可以使用 Aaron Digulia 的答案中的解决方法,或使用不同的名称:

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

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
沧笙踏歌 2024-08-12 14:30:15

两者似乎都工作正常(至少在 Python 2.5 中):

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

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
撞了怀 2024-08-12 14:30:15

尝试

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

您得到的错误(NameError: name 'a' is not Defined)是因为类中的名称a遮盖了参数a功能;因此,当您在代码中尝试“a=a”时,没有定义a。换句话说,右侧a不是来自defa;相反,Python 在类 A 中查找它,因为 a 已经在赋值的左侧提到了。

通过函数,这变得更加清晰:

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

显然,第一次打印应该打印 2,而不是 1,因此 a 的参数 x 必须隐藏全局变量 x. b 是在 x 被称为 a 参数的范围内定义的,因此打印有效。

但是,如果您尝试调用 c,您会收到 UnboundLocalError:赋值前引用的局部变量 'x',因为 Python 不会自动绑定全局变量。要解决此问题,您必须在赋值之前添加 global x

您的情况看起来更像是这样:

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

虽然在上面的示例中打印 x 有效,但赋值不起作用。这是确保变量不会泄漏的安全措施。解决方案是使用默认参数将变量“复制”到 b 的作用域中:

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

要解决您的问题,您需要告诉 Python“使参数 a make_classA 中可见”,您需要在尝试分配类的字段 a 之前执行此操作。这在 Python 中是不可能的。如果您可以使 a 可见,则赋值将更改参数,而不是字段,因为 Python 无法区分这两者。

由于您无法使其可见,因此没有可读取的 a,因此出现 NameError

有关 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文