matinal:python 部分内置函数详解

2023-10-14 14:11:17 浏览数 (3)

eval与exec

evalexec都是python内置的可以执行python代码的函数,但它们之间有所区别。

  • eval(expression[, globals[, locals]]) expression:需要执行的python表达式 globals:需要注入的全局变量,必须为字典 locals:需要注入的局部对象 需要注意的是对于闭包中的嵌套作用域无法获取 eval会返回表达式的执行结果
代码语言:javascript复制
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代码执行
代码语言:javascript复制
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() 的第二种形式的应用之一是构建块读取器。 例如,从二进制数据库文件中读取固定宽度的块,直至到达文件的末尾:
代码语言:javascript复制
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''

代码语言:javascript复制
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流,以及读取文件等

代码语言:javascript复制
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停止迭代。

0 人点赞