【问题标题】:Class variable in `for`...`if` expression fails in python [duplicate]`for` ...`if`表达式中的类变量在python中失败[重复]
【发布时间】:2019-09-30 18:24:05
【问题描述】:

拿这个简单的代码:

class A(object):
  numbers = [1, 2, 3]
  numberscopy = numbers[:]
  print(*(a for a in numberscopy))
  print(*(a for a in numberscopy if a in numbers))

我在类中定义了numbers 变量。然后我可以用它来做其他事情,比如制作副本、迭代它并打印它的内容。

但最后一行,for-if 语句,以NameError: global name 'numbers' is not defined 失败。不是numberscopy,只是numbers

我在 python 2.7.14+(导入了print_function)和 3.7.0 上都试过了,结果相同。

为什么会这样?它打算以这种方式工作吗?

【问题讨论】:

  • 我得到了同样的错误——没有缩进问题。我可以打印numbersnumberscopy,但是当我将if 添加到理解中时会引发错误。这可以正常工作:print(*(a for a in numberscopy if a in A.numbers))
  • @ToothpickAnemone 仅作为示例。在实际案例中,我想根据涉及先前变量的for if 语句定义其他类变量。
  • 对不起,我以为是函数。但这是一堂课。它是重复的

标签: python scope class-variables


【解决方案1】:

类体内的代码在 Python 中有些混乱。这与其说是一个错误,不如说是一个“奇怪的实现问题”。

问题在于:代码通常在模块级别或函数内部运行 - 当在函数内部时,有明确定义的“局部”变量。

类主体内的代码也以“本地”范围运行 - 但如果创建在处理类主体时运行的函数,则这些函数不会 “看到”外部变量。还有生成器表达式,就像推导式一样(在 Python 3 中,Python 2 是另一种语言,它即将淘汰,我们不要让事情复杂化)。用于在生成器内部创建指向for 的迭代器的表达式在它“看到”外部变量的范围内运行。主表达式和 if 表达式本身在生成器内部,无法“看到”这些变量。

因此,如果在类体内需要理解,则一种解决方法是在类体内有一个中间函数,只是为了生成您需要的值和变量,并有行来调用它并使用该内部函数的本地命名空间更新类自己的变量:

class A:
   def create_vals():
       numbers = [1, 2, 3]
       numbers_copy = numbers[:]
       values = list(a for a in numbers if a in numbers_copy)
       return locals()
   locals().update(create_vals())
   del create_vals

所以,在临时 create_vals 函数内部(它不是一个方法),通常适用范围嵌套规则 - 在最后两行中,我们将创建的变量复制到类本身,并删除临时函数。

【讨论】:

  • 那么,stackoverflow.com/questions/13905741/… 中的问题和答案有什么区别?为什么当 Martijn 的答案很出色时重新打开?
  • 不能保证像这样使用本地人。它碰巧在这种情况下工作,但documentation 警告不要依赖对返回的dict 的修改。最好简单地return 所需的值,或者更好的是,如果它让你做这样的事情就不要使用列表推导
  • 它不适用于函数范围,但它可以在类体内工作,其中 locals 只是一个普通字典,或者元类 __prepare__ 返回的另一个映射 - 但实际上,我没有认为它在任何规范中都固定在默认情况下,类的本地人是一个普通的字典。
  • 至于重新打开问题,我已经输入了我的答案并准备发布 - 当问题在答案中关闭时,以前可以发布您的作品而不会丢失它。我认为这足够简洁,可以留在那里 - 如果他们需要更多细节,蚂蚁人可以转发到副本。
  • @juanpa.arrivillaga - 在类范围内更新 locals 时,我刚刚遇到了官方文档(在阅读 PEP 558 时) - 事实上,它只是在函数范围内很棘手。 """在类范围内,它 [locals()] 返回将传递给元类构造函数的命名空间。""" - cf. python.org/dev/peps/pep-0558
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-16
  • 2014-02-01
  • 2011-08-19
  • 2013-06-17
  • 1970-01-01
  • 1970-01-01
  • 2010-12-05
相关资源
最近更新 更多