当前位置: 首页 > 面试题库 >

使用python3的列表生成器表达式中未定义的全局变量,可与python2一起使用,需要进行哪些更改?

陶元凯
2023-03-14
问题内容
class Some(object):
    tokens = [ ... list of strings ... ]
    untokenized = [tokens.index(a) for a in [... some other list of strings ...]]
    ... etc ...
some = Some()

这在Python2.7上很好用。但是python3说:

Traceback (most recent call last):
File "./test.py", line 17, in <module>
    class Some(object):
File "./test.py", line 42, in Some
    untokenized = [tokens.index(a) for a in [... some other list of strings ...]]
File "./test.py", line 42, in <listcomp>
    untokenized = [tokens.index(a) for a in [... some other list of strings ...]]
NameError: global name 'tokens' is not defined

尽管我可以解决该问题,但我真的很想知道Python2和Python3之间的区别。我已阅读python 2->
3更改文档,但无法识别与我的问题有关的任何描述。此外2to3工具不抱怨在我的代码什么。

顺便说一句,虽然我现在不记得这种情况了,但是我也 和python2有类似的东西(我什至没有用3尝试过),我认为这应该工作(在一个类中):

def some_method(self):
    return {a: eval("self." + a) for a in dir(self) if not a.startswith("_")}

但是它导致python2说:NameError: name 'self' is not defined
我还没有用python3尝试过这个,但是例如,这可行:

[eval("self." + a) for a in dir(self) if not a.startswith("_")]

如果我将上一个示例的相关部分更改为此示例(好的示例本身有点愚蠢,但至少显示了我的问题)。现在我很好奇,为什么self似乎没有为第一个示例定义而是为第二个示例定义?看起来像字典一样,我也有类似的问题,这是我原来的问题,但是列表生成器表达式可以工作,但在python3中却不行。嗯…

在我的python2->
3问题之后,我提到了这一点,因为所有这些似乎都与以下问题有关:根据python解释器未定义某些内容(也许我问题的第二部分是不相关的?)。我现在感到很困惑。请给我有关我的错误的启发(因为我确信我当然错过了某些事情)。


问题答案:

正如Wooble所说,问题是类没有词法范围(实际上,在Python
2
或Python
3中)。相反,它们具有不构成范围的本地 名称空间 。这意味着类定义中的表达式可以访问名称空间的内容:

class C:
    a = 2
    b = a + 2    # b = 4

但在类主体中引入的范围 无法 访问其名称空间:

class C:
    a = 2
    def foo(self):
        return a    # NameError: name 'a' is not defined, use return self.__class__.a

Python 2和Python 3之间的区别在于,在Python 2中,列表推导 不会 引入新的作用域:

[a for a in range(3)]
print a    # prints 2

而在Python 3中,它们执行以下操作:

[a for a in range(3)]
print(a)    # NameError: name 'a' is not defined

在Python 3中对此进行了更改,其原因有两个,包括使列表推导的行为与生成器表达式(genexps)相同。(a for a in range(3))在Python 2和Python 3中都有自己的作用域。

因此,在类的主体内,Python 2 genexp或Python 3 listcomp或genexp引入了新作用域,因此无法访问类定义本地名称空间。

赋予genexp / listcomp访问类定义名称空间名称的方法是使用函数或lambda引入新作用域:

class C:
    a = 2
    b = (lambda a=a: [a + i for i in range(3)])()

eval问题

您的eval示例的问题在于eval,默认情况下会在本地范围内评估其参数;因为Python
2列表理解具有共享封闭范围的上述行为,因此eval可以访问方法范围,但是genexp或Python 3
listcomp局部范围仅具有编译器可以从封闭范围中得知的内容(因为genexp / listcomp范围是一个闭包):

def bar(x):
    return list(eval('x') + x for i in range(3))
bar(5)  # returns [10, 10, 10]

def baz(x):
    return list(eval('x') for i in range(3))
baz(5)  # NameError: name 'x' is not defined

正如Martijn所说的,而不是eval您应该使用getattr



 类似资料:
  • 本文向大家介绍Python使用自定义全局变量使用eval评估表达式,包括了Python使用自定义全局变量使用eval评估表达式的使用技巧和注意事项,需要的朋友参考一下 示例 此外,此代码不能偶然引用外部定义的名称: defaultdict例如,使用可以将未定义的变量设置为零:            

  • 本文向大家介绍python列表生成式与列表生成器的使用,包括了python列表生成式与列表生成器的使用的使用技巧和注意事项,需要的朋友参考一下 列表生成式:会将所有的结果全部计算出来,把结果存放到内存中,如果列表中数据比较多,就会占用过多的内存空间,可能会导致MemoryError内存错误或者导致程序在运行时出现卡顿的情况 列表生成器:会创建一个列表生成器对象,不会一次性的把所有结果都计算出来,如

  • 问题内容: 在这里看到讨论之后:Python-产生时差,我很好奇。我最初还以为生成器比列表快,但是当涉及sorted()时我不知道。将生成器表达式发送到sorted()而不是列表有什么好处吗?生成器表达式最终是否仍要在sorted()内放入列表中? 编辑:我只能接受一个答案让我感到悲伤,因为我感到很多答复都有助于澄清这个问题。再次感谢大家。 问题答案: 首先要做的是将数据转换为列表。基本上,实现的

  • 问题内容: 是否可以使用webpack定义全局变量以产生如下所示的结果: 我看到的所有示例都使用外部文件 问题答案: 有几种方法可以处理全局变量: 1)将变量放入模块中。 Webpack仅对模块进行一次评估,因此您的实例保持全局状态,并在模块之间进行更改。 因此,如果您创建像a之类的东西并导出所有全局变量的对象,则可以读取/写入这些全局变量。您可以导入一个模块,从功能中对对象进行更改,然后导入另一

  • 问题内容: 我正在用几个打标机。 当列表()中没有条目时,我想显示一条消息。 我尝试使用with,但是它不起作用。 自定义列表布局代码: 列表适配器类: 列表解析方法: 方法: 问题答案: 这对我有用(从WilliamRemacle提出的问题中得到了解决方案)。您可能会错过的是 将创建的 对象 添加 到 布局父对象 (下面方法底部的第二行代码): 在我中,我使用以下方法为空视图获取视图: 然后在的