Python关于eval函数+实战案例

 1.关于eval函数

基础概念

介绍:将字符串作为Python表达式执行,并返回表达式的计算结果(这意味着,你可以将一个包含Python代码的字符串传递给eval(),它会像直接执行那段代码一样处理这个字符串,计算出相应的值)

  • 表达式解析与执行eval() 接受一个字符串参数,这个字符串应当构成一个有效的Python表达式。这包括了算术运算、变量引用、函数调用等各种表达式形式。函数执行时,会解析该字符串,计算其表达式的值,并返回这个值。

    eval()函数如何解析并执行不同的表达式

    算术运算
    expr = "3 + 5"
    result = eval(expr)
    print(result)  # 输出: 8
    变量引用
    x = 10
    expr = "x * 2"
    result = eval(expr)
    print(result)  # 输出: 20
    函数调用
    def add(a, b):
        return a + b
    ​
    expr = "add(4, 5)"
    result = eval(expr)
    print(result)  # 输出: 9
    复合表达式
    y = 20
    expr = "(3 + 5) * y / 4"
    result = eval(expr)
    print(result)  # 输出: 20.0
    字典和列表解析

    注意,eval()也能解析字面量结构,比如列表和字典,但出于安全考虑,对于复杂数据结构的解析,推荐使用ast.literal_eval()

    expr = "[i for i in range(3)]"  # 列表推导式
    result = eval(expr)
    print(result)  # 输出: [0, 1, 2]
    ​
    expr = "{i:i**2 for i in range(3)}"  # 字典推导式
    result = eval(expr)
    print(result)  # 输出: {0: 0, 1: 1, 2: 4}

  • 命名空间:在执行字符串内的代码时,eval() 默认使用当前的全局和局部命名空间来查找变量和函数定义。也可以通过globalslocals参数自定义这些命名空间。

    使用默认命名空间

    x = 10
    expr = "x + 5"
    result = eval(expr)
    print(result)  # 输出: 15

    在这个例子中,x变量在当前全局命名空间中定义,eval()能够直接访问它。

    自定义全局命名空间

    如果你想要在没有污染当前全局命名空间的情况下执行eval(),或者想要模拟一个特定的环境,可以自定义globals参数:

    custom_globals = {'x': 20, 'addition': lambda a, b: a + b}
    expr = "x + addition(3, 4)"
    result = eval(expr, custom_globals)
    print(result)  # 输出: 27

    这里,eval()使用的xaddition函数都是从custom_globals字典中获取的。

    自定义局部命名空间

    如果你想进一步控制变量的作用域,可以同时自定义局部命名空间:

    x_global = 100
    locals_dict = {'x': 10, 'y': 5}
    expr = "x + y"
    result = eval(expr, globals(), locals_dict)
    print(result)  # 输出: 15

    尽管全局命名空间中有x_global变量,但eval()使用了locals_dict中定义的x,因为局部命名空间优先。

    通过这种方式,你可以精确控制eval()函数执行时的上下文,增强了灵活性和安全性。但再次提醒,使用eval()时务必小心,尤其是处理不可信输入时。

基本功能

功能:可实现数据类型的转换,直接将字符串形式的数字(number)、列表(list)、字典(dict)、元组(tuple)和字符串(str)之间的转换

数字转换
str_num = "123"
num = eval(str_num)
print(num)  # 输出: 123
列表转换
str_list = "[1, 2, 3]"
lst = eval(str_list)
print(lst)  # 输出: [1, 2, 3]
字典转换
str_dict = "{ 'name': 'Alice', 'age': 30 }"
dict_obj = eval(str_dict)
print(dict_obj)  # 输出: {'name': 'Alice', 'age': 30}
元组转换

尽管元组在Python中也可以通过类似列表的方式用eval()转换,但由于元组在字符串中的表示与列表相似,只是多了外层的圆括号,这种转换同样存在安全隐患。

str_tuple = "(1, 2, 3)"
tuple_obj = eval(str_tuple)
print(tuple_obj)  # 输出: (1, 2, 3)

注意事项

  • 安全风险:由于能够执行任意代码,使用eval()处理不可信的输入存在严重的安全隐患,可能导致代码注入攻击。因此,在实际应用中应尽量避免,或者确保输入来源可靠。

  • 性能考量:相比静态编写的代码,eval()会增加额外的解析和执行开销,可能影响程序效率。

    安全风险举例

    假设你有一个Web应用,允许用户输入数学表达式来计算结果,然后你使用eval()函数来计算这个表达式的值。

    user_input = input("请输入一个数学表达式:")
    result = eval(user_input)
    print(f"结果是:{result}")

    如果用户输入的是一个看似无害的数学表达式,如2+2,一切正常。但若用户输入的是如下内容:

    __import__('os').system('rm -rf /')

    这将尝试删除服务器上的所有文件,因为eval()执行了这条命令。这是一个极端的代码注入攻击例子,展示了恶意用户如何利用eval()破坏系统安全。

    性能考量举例

    考虑以下两种计算一个列表所有元素平方和的方法:

    使用列表推导式(静态编写的代码)
    numbers = [1, 2, 3, 4, 5]
    squared_sum = sum([x**2 for x in numbers])
    使用eval()(动态执行代码)
    expr = "sum([x**2 for x in numbers])"
    squared_sum = eval(expr)

    尽管两者都能得到相同的结果,但后者因为需要解析字符串表达式,再执行其中的代码逻辑,相比直接使用列表推导式,会引入额外的性能开销。特别是当这个过程在循环中频繁发生时,累积的性能损耗会更加明显。此外,eval()还增加了内存分配和垃圾回收的负担,进一步降低了效率。因此,除非有特别需求,通常建议直接使用Python的内置功能和数据结构来编写静态代码,以保持高性能和安全性。

2.实战案例

"""
数字形式转换 I
获得用户输入的一个正整数输入,输出该数字对应的中文字符表示。
0到9对应的中文字符分别是:零一二三四五六七八九
"""
template = "零一二三四五六七八九"
​
s = input()
for c in s:
    print(template[eval(c)], end="")
 
"""
温度转换 II
温度的刻画有两个不同体系:摄氏度(Celsius)和华氏度(Fahrenheit)。
请编写程序将用户输入华氏度转换为摄氏度,或将输入的摄氏度转换为华氏度。
转换算法如下:(C表示摄氏度、F表示华氏度)
C = ( F - 32 ) / 1.8
F = C * 1.8 + 32
要求如下:
(1) 输入输出的摄氏度采用大写字母C开头,温度可以是整数或小数,如:C12.34指摄氏度12.34度;
(2) 输入输出的华氏度采用大写字母F开头,温度可以是整数或小数,如:F87.65指华氏度87.65度;
(3) 不考虑异常输入的问题,输出保留小数点后两位;
(4) 使用input()获得测试用例输入时,不要增加提示字符串。
"""
Temple = input()
# print(Temple[1:])
if Temple[0] in ['F']:
    C = (eval(Temple[1:]) - 32) / 1.8
    print("C{:.2f}".format(C))
elif Temple[0] in ['C']:
    F = eval(Temple[1:]) * 1.8 +32
    print("F{:.2f}".format(F))
else:
    print()
"""
货币转换 I
人民币和美元是世界上通用的两种货币之一,写一个程序进行货币间币值转换,其中:
人民币和美元间汇率固定为:1美元 = 6.78人民币.
程序可以接受人民币或美元输入,转换为美元或人民币输出.人民币采用RMB表示,美元USD表示,符号和数值之间没有空格.
注意:
(1) 这是一个OJ题目,获得输入请使用input();
(2) 不提示输出格式错误,结果小数点后保留两位.
"""
a = input()
# print(a[:3])
# print(a[3:])
if a[:3] in ['RMB']:
    U = eval(a[3:]) / 6.78
    print("USD{:.2f}".format(U))
elif a[:3] in ['USD']:
    R = eval(a[3:]) * 6.78
    print("RMB{:.2f}".format(R))
else:
    print()

  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值