Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么exec()中的符号定义语句有时对本地符号表没有影响?_Python_Python 3.x_Exec_Local Variables_Symbol Table - Fatal编程技术网

Python 为什么exec()中的符号定义语句有时对本地符号表没有影响?

Python 为什么exec()中的符号定义语句有时对本地符号表没有影响?,python,python-3.x,exec,local-variables,symbol-table,Python,Python 3.x,Exec,Local Variables,Symbol Table,以下代码段按预期工作: def test(): print(f'local symbol table before exec : {locals()}') exec('a = 0') print(f'local symbol table after exec : {locals()}') test() # printed result: # local symbol table before exec : {} # local symbol table after e

以下代码段按预期工作:

def test():
    print(f'local symbol table before exec : {locals()}')
    exec('a = 0')
    print(f'local symbol table after exec  : {locals()}')

test()
# printed result:
# local symbol table before exec : {}
# local symbol table after exec  : {'a': 0}
但是,一旦我在
test
函数末尾添加了符号定义语句
a=1
,似乎
exec
语句对本地符号表没有影响:

def test():
    print(f'local symbol table before exec : {locals()}')
    exec('a = 0')
    print(f'local symbol table after exec  : {locals()}')
    a = 1

test()
# printed result:
# local symbol table before exec : {}
# local symbol table after exec  : {}
那么,为什么会发生这种情况?

我的猜测是:函数中静态定义的符号将在编译时以某种方式保留,如果已经保留了符号,则在exec函数中动态调用的任何符号定义语句都无法修改本地符号表

这是真的吗?编译期间实际发生了什么


额外测试1:将exec参数替换为
'a=0\n点(locals())'

正如我们所看到的,符号
a
exec()
执行期间成功地添加到本地符号表中,但在执行之后,随着
a=1
的存在,它立即神奇地消失了


额外测试2:在
a=1之前添加
return
语句

def test():
    print(f'local symbol table before exec : {locals()}')
    exec('a = 0\nprint(locals())')
    print(f'local symbol table after exec  : {locals()}')
    return


test()
# printed result:
# local symbol table before exec : {}
# {'a': 0}
# local symbol table after exec  : {'a': 0}
a=1
在第二个
test()
函数中不可访问,但它仍会影响
exec()
的行为

即使是
dis
模块中的
dis()
函数也无法区分这两个
test()
函数之间的区别。输出完全相同,如下所示:

  5           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('local symbol table before exec : ')
              4 LOAD_GLOBAL              1 (locals)
              6 CALL_FUNCTION            0
              8 FORMAT_VALUE             0
             10 BUILD_STRING             2
             12 CALL_FUNCTION            1
             14 POP_TOP

  6          16 LOAD_GLOBAL              2 (exec)
             18 LOAD_CONST               2 ('a = 0\nprint(locals())')
             20 CALL_FUNCTION            1
             22 POP_TOP

  7          24 LOAD_GLOBAL              0 (print)
             26 LOAD_CONST               3 ('local symbol table after exec  : ')
             28 LOAD_GLOBAL              1 (locals)
             30 CALL_FUNCTION            0
             32 FORMAT_VALUE             0
             34 BUILD_STRING             2
             36 CALL_FUNCTION            1
             38 POP_TOP

  8          40 LOAD_CONST               0 (None)
             42 RETURN_VALUE
根据报告:

注意:默认局部变量的作用如下面函数locals()所述:不应尝试修改默认局部变量字典传递一个显式局部变量 如果需要在函数exec()返回后查看代码对局部变量的影响,请使用字典。

因此,我相信这属于“意外行为”,但我想您可以转到
exec()
的实现来真正深入了解

def test():
    print(f'local symbol table before exec : {locals()}')
    exec('a = 0\nprint(locals())')
    print(f'local symbol table after exec  : {locals()}')
    return


test()
# printed result:
# local symbol table before exec : {}
# {'a': 0}
# local symbol table after exec  : {'a': 0}
def test():
    print(f'local symbol table before exec : {locals()}')
    exec('a = 0\nprint(locals())')
    print(f'local symbol table after exec  : {locals()}')
    return
    a = 1


test()
# printed result:
# local symbol table before exec : {}
# {'a': 0}
# local symbol table after exec  : {}
  5           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('local symbol table before exec : ')
              4 LOAD_GLOBAL              1 (locals)
              6 CALL_FUNCTION            0
              8 FORMAT_VALUE             0
             10 BUILD_STRING             2
             12 CALL_FUNCTION            1
             14 POP_TOP

  6          16 LOAD_GLOBAL              2 (exec)
             18 LOAD_CONST               2 ('a = 0\nprint(locals())')
             20 CALL_FUNCTION            1
             22 POP_TOP

  7          24 LOAD_GLOBAL              0 (print)
             26 LOAD_CONST               3 ('local symbol table after exec  : ')
             28 LOAD_GLOBAL              1 (locals)
             30 CALL_FUNCTION            0
             32 FORMAT_VALUE             0
             34 BUILD_STRING             2
             36 CALL_FUNCTION            1
             38 POP_TOP

  8          40 LOAD_CONST               0 (None)
             42 RETURN_VALUE