为什么在类级别使用列表压缩时会引发NameError?

2024-05-29 04:03:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我对代码中的麻烦很感兴趣。你知道吗

...
class Planet:
    ATMOSPHERE_GASES = {
        'N2':(67.59, 28.0134),
        'O2':(28.04, 31.9988),
        'CO2':(0.0114, 44.00995),
        'CH4':(0.00015, 16.04303),
        'Ar':(1.105, 39.948),
        'Ne':(1.003, 20.179),
        'He':(0.719, 4.0026),
        'Kr':(0.45, 83.80),
        'H2':(0.001, 2.01594),
        'Xe':(0.23, 131.30)}
    ATMOSPHERE_GASES['Other'] = tuple([100-sum([x[0] for x in ATMOSPHERE_GASES.values()]), sum([x[1] for x in ATMOSPHERE_GASES.values()])/len(ATMOSPHERE_GASES.values())])
    ATMOSPHERE_GASES_MOLAR_MASS = sum([sum(ATMOSPHERE_GASES[x]) for x in ATMOSPHERE_GASES.keys()])/100
    ...

大气气体摩尔质量给出错误NameError("name 'ATMOSPHERE_GASES' is not defined",)我检查了缩进块、制表符等一些原因,试图重写这部分,但一无所获。但如果没有课堂,它是有效的!你知道吗

Traceback (most recent call last):
  File "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\Python\Core\ptvsd_launcher.py", line 111, in <module>
    vspd.debug(filename, port_num, debug_id, debug_options, run_as)
  File "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\Python\Core\Packages\ptvsd\debugger.py", line 36, in debug
    run(address, filename, *args, **kwargs)
  File "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\Python\Core\Packages\ptvsd\_main.py", line 47, in run_file
    run(argv, addr, **kwargs)
  File "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\Python\Core\Packages\ptvsd\_main.py", line 98, in _run
    _pydevd.main()
  File "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\Python\Core\Packages\ptvsd\pydevd\pydevd.py", line 1628, in main
    globals = debugger.run(setup['file'], None, None, is_module)
  File "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\Python\Core\Packages\ptvsd\pydevd\pydevd.py", line 1035, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\Python\Core\Packages\ptvsd\pydevd\_pydev_imps\_pydev_execfile.py", line 25, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "C:\Users\Rain0Ash\source\repos\A\A\A.py", line 57, in <module>
    class Planet:
  File "C:\Users\Rain0Ash\source\repos\A\A\A.py", line 70, in Planet
    ATMOSPHERE_GASES_MOLAR_MASS = sum([mult(ATMOSPHERE_GASES[x]) for x in ATMOSPHERE_GASES.keys()])/100
  File "C:\Users\Rain0Ash\source\repos\A\A\A.py", line 70, in <listcomp>
    ATMOSPHERE_GASES_MOLAR_MASS = sum([mult(ATMOSPHERE_GASES[x]) for x in ATMOSPHERE_GASES.keys()])/100
NameError: name 'ATMOSPHERE_GASES' is not defined

Tags: inpylinefilesprogramidex86microsoft
2条回答

您可以在类中定义__init__,然后执行self,如下所示:

class Planet:
   def __init__(self):
       self.ATMOSPHERE_GASES = {
           'N2':(67.59, 28.0134),
           'O2':(28.04, 31.9988),
           'CO2':(0.0114, 44.00995),
           'CH4':(0.00015, 16.04303),
           'Ar':(1.105, 39.948),
           'Ne':(1.003, 20.179),
           'He':(0.719, 4.0026),
           'Kr':(0.45, 83.80),
           'H2':(0.001, 2.01594),
           'Xe':(0.23, 131.30)}
       self.ATMOSPHERE_GASES['Other'] = tuple([100-sum([x[0] for x in self.ATMOSPHERE_GASES.values()]), sum([x[1] for x in self.ATMOSPHERE_GASES.values()])/len(self.ATMOSPHERE_GASES.values())])
       self.ATMOSPHERE_GASES_MOLAR_MASS = sum([sum(self.ATMOSPHERE_GASES[x]) for x in self.ATMOSPHERE_GASES.keys()])/100

另见:Python __init__ and self what do they do?

这是一个范围界定问题。Python中的类级变量总是有点奇怪,但是如果您大量使用它们,了解它的工作原理是很重要的。你知道吗

实际问题是列表理解,它试图将ATMOSPHERE_GASES作为全局变量访问。要了解原因,您需要更多地了解由解释器构建的类。要找到问题,我们首先需要使用^{}。这将允许获得抽象语法树,这是一种数据结构。然后我们就可以使用内置的compile函数将它转换成字节码对象。你知道吗

 tree = ast.parse('''
 <your code here...>
 ''')
 # You need a filename, so we will just use __name__ because it's not important for our purpose
 # The 'exec' is to tell the interpreter we want to execute a module, not evaluate an expression
 code = compile(tree, __name__, 'exec')

然后我们需要使用Python反汇编模块^{}。函数dis.dis将让您看到代码编译成什么。它输出了很多代码,但我将把它限制在与列表理解相关联的代码中(列表理解和生成器表达式有自己的代码对象,如函数和模块)。你知道吗

 >>> dis.dis(code)
 ...
 Disassembly of <code object <listcomp> at 0x00000290AA0D59C0, file "__main__", line 4>:
  4           0 BUILD_LIST               0
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                16 (to 22)
              6 STORE_FAST               1 (x)
              8 LOAD_GLOBAL              0 (sum)
             10 LOAD_GLOBAL              1 (ATMOSPHERE_GASES)
             12 LOAD_FAST                1 (x)
             14 BINARY_SUBSCR
             16 CALL_FUNCTION            1
             18 LIST_APPEND              2
             20 JUMP_ABSOLUTE            4
        >>   22 RETURN_VALUE

如果您注意索引10中的指令,您会注意到它说LOAD_GLOBAL 1 (ATMOSPHERE_GASES)。这意味着它在全局范围内寻找ATMOSPHERE_GASES,而不是类级别的范围。你知道吗

ATMOSPHERE_GASES_MOLAR_MASS = sum(sum(tup) for tup in ATMOSPHERE_GASES.values()) / 100解决方案之所以有效,是因为这样可以避免ATMOSPHERE_GASES[x]逻辑,而这正是导致问题的原因。你知道吗

TL;DR:类级别的变量很复杂,因为类如何定义变量。列表理解认为ATMOSPHERE_GASES是一个全局变量,然后在模块的全局范围内找不到它。最好将这个计算从类的定义移到全局范围之外。你知道吗

相关问题 更多 >

    热门问题