这肯定不是特定于python的问题,但我正在寻找特定于python的答案 - 如果有的话。它是关于将具有大量变量的代码块放入函数中(或类似的?)。让我假设这段代码
##!/usr/bin/env python
# many variables: built in types, custom made objects, you name it.
# Let n be a 'substantial' number, say 47.
x1 = v1
x2 = v2
...
xn = vn
# several layers of flow control, for brevity only 2 loops
for i1 in range(ri1):
for i2 in range(ri2):
y1 = f1(i1,i2)
y2 = f2(i1,i2)
# Now, several lines of work
do_some_work
# involving HEAVY usage and FREQUENT (say several 10**3 times)
# access to all of x1,...xn, (and maybe y1,y2)
# One of the main points is that slowing down access to x1,...,xn
# will turn into a severe bottleneck for the performance of the code.
# now other things happen. These may or may not involve modification
# of x1,...xn
# some place later in the code, again, several layers of flow control,
# not necessarily identical to the first occur
for j1 in range(rj1):
y1 = g1(j1)
y2 = g2(j1)
# Now, again
do_some_work # <---- this is EXACTLY THE SAME code block as above
# a.s.o.
显然我想把'do_some_work'放到像函数一样的东西(或者更好的东西?)。
在python
中执行此操作的最佳方法是什么没有带有令人困惑的大量参数的函数调用
没有性能有损间接访问x1,...,xn(比如说,将它们包装到另一个列表,类或类似物中)
不使用x1,...,xn作为函数do_some_work(...)中的全局变量
我必须承认,我总是发现自己回归全局。
答案 0 :(得分:1)
全局变量明显慢于局部变量。
此外,使用大量不同的变量名称几乎总是一个坏主意。更好地使用单个数据结构,例如字典:
d = {"x1": "foo", "x2": "bar", "y1": "baz"}
等
然后你可以将d
传递给你的函数(由于只传递dict的地址,而不是整个字典,因此非常快),并从那里访问它的内容。
if d["x2"] = "eggs":
d["x1"] = "spam"
答案 1 :(得分:1)
一个简单而肮脏(可能不是最佳)的banchmark:
import timeit
def test_no_func():
(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19) = range(20)
for i1 in xrange(100):
for i2 in xrange(100):
for i3 in xrange(100):
results = [x0+x1+x2+x3+x4+x5+x6 for _ in xrange(100)]
results.extend(x7+x8+x9+x10+x11+x12+x13+x14+x15 for _ in xrange(100))
results.extend(x16+x17+x18+x19+x0 for _ in xrange(500))
for j1 in xrange(100):
for j2 in xrange(100):
for i3 in xrange(100):
results = [x0+x1+x2+x3+x4+x5+x6 for _ in xrange(100)]
results.extend(x7+x8+x9+x10+x11+x12+x13+x14+x15 for _ in xrange(100))
results.extend(x16+x17+x18+x19+x0 for _ in xrange(500))
def your_func(x_vars):
# of the number is not too big you can simply unpack.
# 150 is a bit too much for unpacking...
(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19) = x_vars
results = [x0+x1+x2+x3+x4+x5+x6 for _ in xrange(100)]
results.extend(x7+x8+x9+x10+x11+x12+x13+x14+x15 for _ in xrange(100))
results.extend(x16+x17+x18+x19+x0 for _ in xrange(500))
return results
def test_func():
(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19) = range(20)
for i1 in xrange(100):
for i2 in xrange(100):
for i3 in xrange(100):
results = your_func(val for key,val in locals().copy().iteritems() if key.startswith('x'))
for j1 in xrange(100):
for j2 in xrange(100):
for i3 in xrange(100):
results = your_func(val for key,val in locals().copy().iteritems() if key.startswith('x'))
print timeit.timeit('test_no_func()', 'from __main__ import test_no_func', number=1)
print timeit.timeit('test_func()', 'from __main__ import test_func, your_func', number=1)
结果:
214.810357094
227.490054131
传递参数的速度慢约5%。但是,你可能不会比引入100万次函数调用做得更好......
答案 2 :(得分:0)
我建议使用python cProfile模块。只需以这种方式运行脚本:
python -m cProfile your_script.py
在不同的模式下(有和没有函数包装),看看它的工作速度有多快。我不认为访问变量是一个瓶颈。通常,循环和重复操作都是。
其次,我建议考虑抽象函数,因为你使用i1,i2等
循环可以用itertools抽象:
来自itertools导入产品 equal_sums = 0 对于l in product(范围(10),repeat = 6):#而不是6个嵌套循环超出范围(10) 如果sum(l [:3])== sum(l [3:]): equal_sums + = 1