【问题标题】:Why can't a Python class definition assign a closure variable to itself?为什么 Python 类定义不能为自己分配闭包变量?
【发布时间】:2009-09-18 15:17:37
【问题描述】:

为什么以下在 Python 中不起作用?

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

【问题讨论】:

    标签: python closures


    【解决方案1】:

    工作得很好:

    >>> def make_class(a):
        class A(object):
            _a=a
        return A
    
    >>> make_class('df')
    <class '__main__.A'>
    >>> make_class('df')._a
    'df'
    

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

    【讨论】:

    • 我的错。老实说,我知道 Python!
    【解决方案2】:

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

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

    这会失败,因为 python 中的赋值,没有伴随的 globalnonlocal 语句,意味着分配的名称是当前作用域的本地名称。这不仅发生在函数中,还发生在类定义中。

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

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

    【讨论】:

      【解决方案3】:

      两者似乎都可以正常工作(至少在 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
      

      【讨论】:

      • 我试图在类中执行 a=a,就像在默认函数参数中一样,但这不起作用。
      【解决方案4】:

      试试

      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 必须遮蔽全局变量xb 是在x 被称为a 的参数的范围内定义的,因此打印工作正常。

      但是,如果您尝试调用 c,则会得到 UnboundLocalError: local variable 'x' referenced before assignment,因为 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“使 make_class 的参数 aA 中可见”,您需要在尝试分配字段 a 之前执行此操作班级。这在 Python 中是不可能的。如果您可以使a 可见,则赋值将更改参数,而不是字段,因为 Python 无法区分两者。

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

      请参阅here,了解 Python 中名称范围的说明。

      【讨论】:

      • -1 您将收到该代码的语法错误,因为您打开类 A 并且没有缩进以下行。输入一个缩进的通过线,你会没事的。
      • 糟糕。添加了缺少的“通行证”。
      猜你喜欢
      • 2021-05-15
      • 2015-07-30
      • 1970-01-01
      • 2018-02-05
      • 2014-03-24
      • 2017-08-16
      • 1970-01-01
      • 2019-09-07
      • 2021-03-03
      相关资源
      最近更新 更多