eval与exec
eval
和exec
都是python内置的可以执行python代码的函数,但它们之间有所区别。
- eval(expression[, globals[, locals]])
expression:需要执行的python表达式
globals:需要注入的全局变量,必须为字典
locals:需要注入的局部对象
需要注意的是对于闭包中的嵌套作用域无法获取
eval会
返回表达式的执行结果
a = 1
command = "a > 2"
print(eval(command))
print(eval("b 1", {"b": 1}))
代码语言:javascript复制False
2
需要注意的是eval可能存在类似于SQL注入的风险,下面将对其进行描述
代码语言:javascript复制while True:
string_data = input("请输入一段文字:")
print(eval(string_data))
上述代码含义就是输出用户输入的内容并使用eval返回相应结果。
正常情况下,输入相应内容会输出相应结果,
异常情况,当输入__import__("os").system("dir")
时,我们可以看到eval执行了相应的结果,返回了对应的结果,上述指令的含义为执行相应的指令,因此当我们将命令换成删除等动作时将会造成无法挽回的后果,类似于SQL注入,因此对于进行eval执行表达式获取结果时需要注意此类问题。
- exec(object[, globals[, locals]])
object:需要执行的python代码,可以是代码对象
globals:需要注入的全局变量,必须为字典
locals:需要注入的局部对象
exec支持
动态执行python代码
,如果是字符串则解析称python代码执行
command = "a = 2"
print(exec(command))
print(a)
print(globals())
print(locals())
代码语言:javascript复制None
2
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000027E90174A30>, '__spec__': None, '__annotations__': {}, '__builtins__': <module
'builtins' (built-in)>, '__file__': 'd:\python_study\study\2022_7_25\test.py', '__cached__': None, 'a': 2, 'command': 'a = 2'}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000027E90174A30>, '__spec__': None, '__annotations__': {}, '__builtins__': <module
'builtins' (built-in)>, '__file__': 'd:\python_study\study\2022_7_25\test.py', '__cached__': None, 'a': 2, 'command': 'a = 2'}
globals()
和locals()
分别是查看全局命名空间和局部命名空间的内置函数。
由于exec与eval类似并且可以执行任意合法代码,因此也会存在注入问题,与上述eval执行相应命令类似,执行相应命令时会存在风险。
区别 | eval | exec |
---|---|---|
执行内容 | 只能是表达式之类的,无法使用赋值、声明变量等 | 任意合法的python代码即可 |
返回值 | 返回的是表达式的执行结果 | 返回均为None |
声明的globals外界是否可用 | 不可用,只能在eval内部使用 | 不可用,只能在exec内部使用 |
iter(object[, sentinel])
返回一个迭代器
- object:需要操作的对象,对象要求跟随是否存在第二个参数来决定
- sentinel:需要标记的返回值,正常都是设置为
b''
1.当不存在第二个参数时,object
必须时可迭代对象(包含__iter__方法)或者必须支持序列协议(有__getitem__
() 方法,且数字参数从 0 开始, 2.当存在第二个参数时,每次迭代调用它的__next__
() 方法时都会不带实参地调用 object;如果返回的结果是 sentinel 则触发 StopIteration,否则返回调用结果。 3.适合iter()
的第二种形式的应用之一是构建块读取器。 例如,从二进制数据库文件中读取固定宽度的块,直至到达文件的末尾:
from functools import partial
with open('mydata.db', 'rb') as f:
for block in iter(partial(f.read, 64), b''):
process_block(block)
当iter有了第二个参数后,可以将方法函数等转变为迭代器,正常第二个参数改变b''
def fun(number):
return number 1
from typing import Iterator
fun2 = lambda: fun(1)
print(type(fun2))
data = iter(fun2, b'')
print(type(data))
print(isinstance(data, Iterator))
代码语言:javascript复制<class 'function'>
<class 'callable_iterator'>
True
iter
可以替代while的无限循环,例如读取socket的io流,以及读取文件等
from pathlib import Path
from functools import partial
file_path = Path(__file__).parent.joinpath("05使用语法.py")
with open(file_path, "r", encoding="utf-8") as f:
while True:
line = f.readline()
print(line)
if not line:
break
with open(file_path, "r", encoding="utf-8") as f:
for line in iter(lambda: f.readline(), b''):
print(line)
if not line:
break
当设置了__sentinel
之后,将会在迭代过程中遇到__sentinel
将会自动触发stopIteration停止迭代。