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

时间:2018-08-05 01:41:50

标签: python python-3.x function class variables

我为自己的代码麻烦而感到有趣。

...
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
    ...

ATMOSPHERE_GASES_MOLAR_MASS提供错误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

2 个答案:

答案 0 :(得分:2)

您可以在课堂上定义bar,然后执行__init__,如下所示:

self

另请参阅:Python __init__ and self what do they do?

答案 1 :(得分:2)

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

实际的问题是列表理解,它试图将ATMOSPHERE_GASES作为全局变量进行访问。要了解原因,您需要更多地了解解释器构建的类。要找到问题,我们首先需要使用ast。这将允许获取抽象语法树,它是一种数据结构。然后,我们将能够使用内置的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.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是一个全局变量,然后在模块的全局范围内找不到它。最好将这种计算超出类的定义,移到全局范围内。