【问题标题】:python3 accessing class attributes in a generator at initialisaton [duplicate]python3在初始化时访问生成器中的类属性[重复]
【发布时间】:2018-10-18 04:20:54
【问题描述】:

我目前正在将 codebase 从 python2 切换到 python3 并遇到一个我不太明白的问题:

class MyClass:
    var1 = True
    var2 = tuple([i for i in [1, 2,] if var1])

上面的类在python2中运行得非常愉快,但是在python3中就坏了。

我改成了:

class MyClass:
    var1 = True
    var2 = tuple(i for i in [1, 2,] if var1)

因为我的理解是列表理解是多余的,不管它不起作用。经过一些调查后,list/tuple 理解的行为方式似乎是我不太理解的,当它们位于正在初始化的类的主体中时。

# Breaks in python 2 and 3
class MyClass:
    var1 = True
    var2 = tuple(i for i in [1, 2,] if var1)


# Works in python 2, breaks in 3
class MyClass:
    var1 = True
    var2 = [i for i in [1, 2,] if var1]

关于发生了什么的任何指示?

【问题讨论】:

  • 我不认为这个问题与附加的副本完全重复,但除非其他人这样做,否则我不会重新打开它。
  • @Kasramvd 你能详细说明一下吗?我认为 Martijn 的回答涵盖了 OP 可能想知道的所有内容。
  • @Aran-Fey 是的,这个答案很全面,但我的意思是这个问题不是重复的。重复基本上是为了问题。尽管有人可以争辩说,当您可以在其他不重复的问题中找到答案时,那么不重复它有什么意义。但是,当你基于一个特定的根启动一个线程时,它会导致它自己的结果,此外,对于这样的问题,因为自 3.1 以来有许多新版本的 Python 并且所有这些都有很多新特性,一个可以提出更多更新的答案。
  • @Aran-Fey 总而言之,我的意思是,像这样解决语言的一些基本问题的重要而好的问题总是值得讨论和审查。
  • @Kasramvd 我现在明白了,你说这是一个不同的问题,因为它询问列表理解和生成器表达式之间的区别。不过,我认为这还不足以成为重新提出问题的充分理由。它只是对问题 “为什么这个列表推导在 python2 中有效,但在 python3 中无效?” - 这是因为列表推导在 python2 中没有自己的范围,但生成器表达式有. “为什么列表推导式与生成器表达式不同?” 的答案实际上只是 “因为它们是不同的表达式”

标签: python python-3.x class namespaces


【解决方案1】:

关于第一种情况,您实际上是将生成器表达式传递给tuple 函数,该函数甚至不是类属性。它实际上类似于以下代码:

>>> class MyClass:
...     var1 = True
...     def func():
...         return var1
...     func()
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in MyClass
  File "<stdin>", line 4, in func
NameError: global name 'var1' is not defined

正如您再次看到的那样,在 Python-2.7 和绝对 3.X 中引发了NameError。原因是函数有自己的命名空间,并且没有明确声明该变量的状态(全局、本地、非本地)或通过类的实例进行访问(self.var1)函数无法访问外部有界命名空间.

另一方面,python-2 中的列表推导可以访问定义它们的对象的命名空间。它们不像函数,也没有函数所具有的许多特性。这实际上是一种双向的关系。这就是说,虽然您可以在列表理解中使用变量,但您在列表理解中定义的内容也可以在它之外访问。而且由于人们倾向于在列表推导中使用一次性变量,这将导致您的代码有变量泄漏。但是由于 Python-3.x 列表解析从函数中借用了私有命名空间,因此它们可以拥有自己的命名空间。

【讨论】:

  • 很有趣,谢谢!是否有一个共同的模式来执行当前损坏的代码所做的事情,或者是完全重新思考逻辑并将其移动到__init__ 或类似的情况?
  • @ptr 从 OOP 的角度来看,最好将变量移动到易于访问的 __init__ 中,并且您可以更好地控制它。除非,它的成本太高,在这种情况下不太可能。
猜你喜欢
  • 2012-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-01
  • 2015-05-07
相关资源
最近更新 更多