摘要:最近在使用exec函数时发现exec这个东西十分神奇。

exec的变量作用域

函数的定义(查看python文档):

exec(object[, globals[, locals]])

这个函数支持动态执行 Python 代码。object 必须是字符串或者代码对象。如果是字符串,那么该字符串将被解析为一系列 Python 语句并执行(除非发生语法错误)。1 如果是代码对象,它将被直接执行。在任何情况下,被执行的代码都需要和文件输入一样是有效的(见参考手册中关于文件输入的章节)。请注意即使在传递给 exec() 函数的代码的上下文中,return 和 yield 语句也不能在函数定义之外使用。该函数返回值是 None 。

无论哪种情况,如果省略了可选项,代码将在当前作用域内执行。 如果只提供了 globals,则它必须是一个字典(不能是字典的子类),该字典将同时被用于全局和局部变量。 如果同时提供了 globals 和 locals,它们会分别被用于全局和局部变量。 如果提供了 locals,则它可以是任何映射对象。 请记住在模块层级上,globals 和 locals 是同一个字典。 如果 exec 得到两个单独对象作为 globals 和 locals,则代码将如同嵌入类定义的情况一样执行。

如果 globals 字典不包含 __builtins__ 键值,则将为该键插入对内建 builtins 模块字典的引用。因此,在将执行的代码传递给 exec() 之前,可以通过将自己的 __builtins__ 字典插入到 globals 中来控制可以使用哪些内置代码。

这两个参数可以用来指定执行代码时可以使用的全局变量和局部变量, 以及收集执行代码后的全局变量和局部变量。

  • globals 默认为 globals()
  • locals 默认为 本地局部变量 locals的值。

    exec变量作用域1.jpg

下面将举例说明指定 globals 和 locals 变量时的效果。
(1)当未设置globals 和 locals时,使用默认作用域

  • 当未指定a为global变量时a=a+1会在exec内创建一个,名叫"a"的局部变量。可以用id(a)查看。

    exec变量作用域2.jpg

  • 当指定a为global变量时a=a+1会使用全局变量。

    exec变量作用域3.jpg

  • 字典等因为是引用,所以会影响外面的值

    exec变量作用域4.jpg

(2)当设置globals 时,locals的值默认为globals的值

  • 当设置globals 时,locals的值默认为globals的值,此时exec内只能使用globals字典内部的变量。对变量的修改也会反映到globals字典里,不会影响到外界。

    exec变量作用域5.jpg

  • 可以看到locals的值默认为globals的值

    exec变量作用域6.jpg

(3)当同时设置了globals和locals的值时

exec变量作用域7.jpg

此时先检测变量是否在locals中存在,如果在locals中不存在就创建一个。可以看到locals中创建一个键名叫a的值。

(4)遇到一个神奇的问题

下面的代码不能正常运行:

import requests
res = requests.get('http://031zwzm.com')
类别 = ["aa","cc","bb"]
aalist1 = ['学生','2','2','3']
bblist1 = ['1','AV','2','4']
cclist1 = []
网页 = res.text
resultslist = []

def zeze(网页内容):
    loc = locals()
    for key in range(0, len(类别)):
        results = []
        exec('results = [i for i in ' + 类别[key] + 'list1 if i in 网页内容]')
        print(loc['results'])
        resultslist.append(len(loc['results']))
    print(resultslist)

zeze(网页)

而下面的代码能运行:

import requests
res = requests.get('http://031zwzm.com')
类别 = ["aa","cc","bb"]
aalist1 = ['学生','2','2','3']
bblist1 = ['1','AV','2','4']
cclist1 = []
网页 = res.text
resultslist = []

def zeze():
    loc = locals()
    for key in range(0, len(类别)):
        results = []
        exec('results = [i for i in ' + 类别[key] + 'list1 if i in 网页]')
        print(loc['results'])
        resultslist.append(len(loc['results']))
    print(resultslist)

zeze()

问题出在

 exec('results = [i for i in ' + 类别[key] + 'list1 if i in 网页]')

这一行代码上具体问题还是查不出来。

解决办法:

import requests
res = requests.get('http://031zwzm.com')
类别 = ["aa","cc","bb"]
aalist1 = ['学生','2','2','3']
bblist1 = ['1','AV','2','4']
cclist1 = []
网页 = res.text
resultslist = []

def zezezeze(网页):
    loc = locals()
    for key in range(0, len(类别)):
        code = '''
result=[]
for i in ''' + 类别[key] + '''list1:
    if i in 网页:
        result.append(i)
'''
        exec(code)
        resultslist.append(len(loc['result']))
    print(resultslist)

zezezeze(网页)