exec()方法執(zhí)行動態(tài)創(chuàng)建的程序,該程序可以是字符串,也可以是代碼對象。
exec()的語法;
exec(object, globals, locals)
exec()采用三個(gè)參數(shù):
object -字符串或代碼對象
globals (可選)-字典
locals(可選)-映射對象。字典是Python中常用的標(biāo)準(zhǔn)映射類型。
稍后將在本文中討論全局變量(globals) 和 (locals)本地變量的使用。
exec()不返回任何值,它返回None。
program = 'a = 5\nb=10\nprint("Sum =", a+b)' exec(program)
運(yùn)行該程序時(shí),輸出為:
Sum = 15
在這里,字符串對象程序被傳遞給執(zhí)行該程序的exec()。在本示例中省略了全局變量(globals) 和 (locals)局部變量。
program = input('輸入程序:') exec(program)
運(yùn)行該程序時(shí),輸出為:
輸入程序: [print(item) for item in [1, 2, 3]] 1 2 3
如果要從允許多行代碼的用戶處獲取Python代碼(使用'\n'),則可以在使用exec()之前使用compile()方法。
了解有關(guān)Python中的compile()方法更多信息。
考慮一種情況,您正在使用Unix系統(tǒng)(macOS,Linux等),并且已導(dǎo)入os模塊。os模塊提供了使用操作系統(tǒng)功能的便攜式方法,例如:讀取或?qū)懭胛募?/p>
如果允許用戶使用來輸入值exec(input()),則用戶可以發(fā)出命令來更改文件,甚至可以使用command刪除所有文件os.system('rm -rf *')。
如果exec(input())在代碼中使用,最好檢查用戶可以使用哪些變量和方法。您可以使用dir()方法查看可用的變量和方法。
from math import * exec('print(dir())')
運(yùn)行該程序時(shí),輸出為:
['In', 'Out', '_', '__', '___', '__builtin__', '__builtins__', '__name__', '_dh', '_i', '_i1', '_i2', '_ih', '_ii', '_iii', '_oh', '_sh', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exit', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'get_ipython', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'quit', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
通常,不需要使用exec()中所有可用的方法和變量,甚至可能有安全漏洞。您可以通過將可選的globals和locals參數(shù)(字典)傳遞給exec()方法來限制這些變量和方法的使用。
如果兩個(gè)參數(shù)都省略(如我們前面的示例),則exec()預(yù)期要執(zhí)行的代碼將在當(dāng)前范圍內(nèi)執(zhí)行。您可以使用以下代碼檢查可用的變量和方法:
exec('print(dir())')
(globals) 和 (locals)參數(shù)(字典),分別用于全局和局部變量。如果省略了locals字典,則默認(rèn)為globals字典。這意味著,全局變量(globals)將用于全局變量和局部變量。
注意:您可以分別使用globals()和locals()內(nèi)置方法在Python中檢查當(dāng)前的全局字典和局部字典。
from math import * exec('print(dir())', {}) # 此代碼將引發(fā)異常 # exec('print(sqrt(9))', {})
如果將空字典作為globals傳遞,則僅__builtins__可供object(exec()的第一個(gè)參數(shù))使用。即使我們在上述程序中導(dǎo)入了math模塊,嘗試訪問math模塊提供的任何函數(shù)也會引發(fā)異常。
運(yùn)行該程序時(shí),輸出為:
['__builtins__']
from math import * exec('print(dir())', {'sqrt': sqrt, 'pow': pow}) # 對象可以有sqrt()模塊 exec('print(sqrt(9))', {'sqrt': sqrt, 'pow': pow})
在這里,由exec()執(zhí)行的代碼也可以具有sqrt()和pow()方法以及__builtins__。
可以根據(jù)您的意愿更改方法的名稱。
from math import * exec('print(dir())', {'squareRoot': sqrt, 'pow': pow}) # 對象可以具有squareRoot()模塊 exec('print(squareRoot(9))', {'squareRoot': sqrt, 'pow': pow})
在上述程序中,squareRoot()計(jì)算平方根(類似的功能,如sqrt())。但是,嘗試使用sqrt()將引發(fā)異常。
您可以通過在globals字典中為__builtins__賦值None,來限制__builtins__的使用。
exec(object, {'__builtins__': None})
您可以通過傳遞本地(locals)字典來使所需的函數(shù)和變量可用。例如:
from math import * globalsParameter = {'__builtins__' : None} localsParameter = {'print': print, 'dir': dir} exec('print(dir())', globalsParameter, localsParameter)
運(yùn)行該程序時(shí),輸出為:
['dir', 'print']
在這里,exec()方法只能執(zhí)行兩個(gè)內(nèi)置方法print()和dir()。
需要特別注意的是,exec()執(zhí)行代碼,并且不返回任何值(返回None)。因此,您不能在函數(shù)定義之外使用return和yield語句。