python怎么重复执行某语句_Python:加速重复执行的eval语句的方法?

在我的代码中,我使用eval来计算用户给定的字符串表达式。是否有方法编译或以其他方式加速此语句?

import math

import random

result_count = 100000

expression ="math.sin(v['x']) * v['y']"

variable = dict()

variable['x'] = [random.random() for _ in xrange(result_count)]

variable['y'] = [random.random() for _ in xrange(result_count)]

# optimize anything below this line

result = [0] * result_count

print 'Evaluating %d instances of the given expression:' % result_count

print expression

v = dict()

for index in xrange(result_count):

for name in variable.keys():

v[name] = variable[name][index]

result[index] = eval(expression) #

#result[index] = math.sin(v['x']) * v['y'] #

对于快速比较选项,一个在我的机器上需要2.019秒,而选项二只需要0.218秒。当然,Python有一种在不硬编码表达式的情况下实现这一点的方法。

在这个post stackoverflow.com/questions/1832940中查看一些eval的替代方法,以及一些远离它的好理由。

如果用户键入import os;os.system("rm -rf /"),会怎么样?您需要编写一个解析器来解释输入字符串,并且只识别您期望的内容:sin、cos、log等。如果输入的内容不起作用,则抛出一个错误。如果你不这样做可能会很糟糕。

如果用户想要"rm-rf/"或":()::&":"他可以在shell中而不是在python中执行。

您还可以使用python:

expression ="math.sin(v['x']) * v['y']"

exp_as_func = eval('lambda: ' + expression)

然后像这样使用:

exp_as_func()

速度测试:

In [17]: %timeit eval(expression)

10000 loops, best of 3: 25.8 us per loop

In [18]: %timeit exp_as_func()

1000000 loops, best of 3: 541 ns per loop

附带说明,如果v不是全局的,您可以这样创建lambda:

exp_as_func = eval('lambda v: ' + expression)

并称之为:

exp_as_func(my_v)

与F.J.的反应相比,这是一个显著的速度提升,而这已经是一个巨大的速度提升。

我猜这个技巧相当于在评估之前使用compile,因为当你运行它时,你会得到The slowest run took 17.90 times longer than the fastest. This could mean that an intermediate result is being cached。

通过使用compiler.compile()for python 2或compile()for python 3预先编译表达式,可以避免开销:

In [1]: import math, compiler

In [2]: v = {'x': 2, 'y': 4}

In [3]: expression ="math.sin(v['x']) * v['y']"

In [4]: %timeit eval(expression)

10000 loops, best of 3: 19.5 us per loop

In [5]: compiled = compiler.compile(expression, '', 'eval')

In [6]: %timeit eval(compiled)

1000000 loops, best of 3: 823 ns per loop

只需确保只编译一次(在循环之外)。正如注释中所提到的,当对用户提交的字符串使用eval时,请确保对您接受的内容非常小心。

这是一个相当大的收获…

compiler.compile在python3中编译

我认为你在优化错误的结局。如果要对许多数字执行相同的操作,应考虑使用numpy:

import numpy

import time

import math

import random

result_count = 100000

expression ="sin(x) * y"

namespace = dict(

x=numpy.array(

[random.random() for _ in xrange(result_count)]),

y=numpy.array(

[random.random() for _ in xrange(result_count)]),

sin=numpy.sin,

)

print ('Evaluating %d instances '

'of the given expression:') % result_count

print expression

start = time.time()

result = eval(expression, namespace)

numpy_time = time.time() - start

print"With numpy:", numpy_time

assert len(result) == result_count

assert all(math.sin(a) * b == c for a, b, c in

zip(namespace["x"], namespace["y"], result))

为了让您了解可能获得的收益,我添加了一个使用通用python和lambda技巧的变体:

from math import sin

from itertools import izip

start = time.time()

f = eval("lambda:" + expression)

result = [f() for x, y in izip(namespace["x"], namespace["y"])]

generic_time = time.time() - start

print"Generic python:", generic_time

print"Ratio:", (generic_time / numpy_time)

以下是我的老化机的结果:

$ python speedup_eval.py

Evaluating 100000 instances of the given expression:

sin(x) * y

With numpy: 0.006098985672

Generic python: 0.270224094391

Ratio: 44.3063992807

速度没有我预期的那么快,但仍然很重要。

我不能在这里访问numpy。但我同意,这可能会加快速度。如果没有第三方图书馆,我一般不会依赖它。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ast.literal_eval是一个函数,可以将字符串转换为对应的Python对象,例如将字符串'123'转换为整数123,将字符串'[1, 2, 3]'转换为列表[1, 2, 3]。它可以安全地解析一些简单的Python表达式,但不支持所有Python语法。使用时需要注意安全性,避免执行恶意代码。 ### 回答2: ast.literal_evalPython内置的一个函数,它用于安全地评估一个字符串类型的Python表达式,并返回表达式的值。 使用ast.literal_eval可以避免使用内置函数eval()可能引发的安全问题。eval()函数会将传入的字符串当作Python代码进行评估,如果字符串来自不可信的来源,可能会导致执行恶意代码。而ast.literal_eval执行更严格的评估,只会允许对字面值表达式的评估,不会执行任何函数调用或表达式语句。 ast.literal_eval的使用非常简单,只需将一个合法的字符串表达式作为参数传入即可。如果字符串的语法不正确, ast.literal_eval会抛出一个值错误(SyntaxError);如果字符串包含的表达式不是有效的Python字面值,会抛出一个值错误(ValueError)。如果表达式的评估成功,ast.literal_eval会返回表达式的值。 例如,假设有一个字符串'1 + 2',如果直接用eval()函数进行评估,会抛出一个错误,因为'1 + 2'不是一个有效的Python表达式。但如果使用ast.literal_eval('1 + 2'),会抛出一个值错误,提示无效的字面值。只有当传入合法的字面值表达式时,ast.literal_eval才能正确评估并返回其值。 总之,ast.literal_eval是一个非常有用的函数,它提供了一种安全且简便的方法来评估字符串类型的Python表达式,帮助我们在处理可信和不可信的Python代码时,减少潜在的安全风险。 ### 回答3: ast.literal_eval是一个Python内置模块ast中的函数,用于将字符串形式的字面值转换为对应的Python对象。它类似于内置函数eval,但有一些重要差异。 使用ast.literal_eval时,传入的参数必须是合法的Python字面值表达式,例如数字、字符串、元组、列表、字典、布尔值和None值等,否则会引发SyntaxError异常。 相比于eval函数,ast.literal_eval更加安全。因为它仅仅被用于求值字面量表达式,不会执行任何表达式中的函数或变量,因此可以避免恶意代码的执行。这使得ast.literal_eval成为处理不可信输入时的一个很好的选择。 ast.literal_eval的返回值是根据传入的参数的类型而变化的,如果是字面值表达式,返回值将是对应的Python对象。例如,传入的字符串是"[1, 2, 3]",则返回一个列表 [1, 2, 3]。如果传入的字符串无法解析成合法的Python字面值,将会引发ValueError异常。 ast.literal_eval的应用场景广泛。例如,当从文件中读取字符串表示的数据时,可以使用ast.literal_eval将其转换为相应的数据结构。此外,它还常用于处理JSON数据,因为JSON的数据类型与Python的数据类型非常相似,可以使用ast.literal_eval将JSON字符串转换为Python对象。 总而言之,ast.literal_eval是一个安全且高效的函数,用于将字符串形式的字面值转换为Python对象。在处理不可信输入和解析字符串数据时,ast.literal_eval可以帮助我们避免潜在的安全问题,并提供更好的代码性能和可读性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值