4行程序的Python代码优化



我目前有一个工作程序如下:

from math import sqrt
def list_squared(m, n):
#sum of the squared divisors of a number
def D(x):return sum([i**2 for i in range(1,x+1) if not x%i])
#returns array of arrays containing each num and D(num) from m to n if D(num) is square 
return [[i,D(i)] for i in range(m,n) if sqrt(D(i)).is_integer()]

但是,该程序的执行速度不够快,服务器无法将其视为工作解决方案。我以前从未从事过优化代码的工作,并且可以在如何使其执行得更快方面获得一些帮助。

该程序是以下问题的解决方案:

42 的除数是:1, 2, 3, 6, 7, 14, 21, 42。 这些除数的平方是:1, 4, 9, 36, 49, 196, 441, 1764. 除数的平方和是 2500,即 50 * 50,一个平方! 给定两个整数 m, n (1 <= m <= n(,我们希望找到 m 和 n 之间的所有整数,其平方除数之和本身就是一个平方。42就是这样一个数字。 结果将是一个数组数组,每个子数组有两个元素,首先是平方除数为正方形的数字,然后是平方除数之和。

#Examples
list_squared(1, 250) --> [[1, 1], [42, 2500], [246, 84100]]
list_squared(42, 250) --> [[42, 2500], [246, 84100]]

这可能不是这个问题的最佳答案,但这就是我优化此特定代码的方式。 这与其说是最终结果,不如说是一个开始,但是..井。。。事情是这样的:

import time
from math import sqrt

ITERATIONS = 10000

def timer(func, *args, **kwargs):
start = time.time()
for _ in range(ITERATIONS):
func(*args)
print("%s at %s iterations took %s" % (func.__name__, ITERATIONS, time.time() - start))

def list_squared(m, n):
# base function
#sum of the squared divisors of a number
def D(x):return sum([i**2 for i in range(1, x+1) if not x % i])
#returns array of arrays containing each num and D(num) from m to n if D(num) is square
return [[i, D(i)] for i in range(m, n) if sqrt(D(i)).is_integer()]

def D(x):
return sum([i**2 for i in range(1, x + 1) if not x % i])

def list_squared_opt1(m, n):
# reduce the amount of function overhead
ret_list = list()
for i in range(m, n):
tmp = D(i)
if sqrt(tmp).is_integer():
ret_list.append([i, tmp])
return ret_list

def list_squared_opt2(m, n):
# further reduce the amount of function overhead
ret_list = list()
for i in range(m, n):
tmp = sum([x**2 for x in range(1, i + 1) if not i % x])
if sqrt(tmp).is_integer():
ret_list.append([i, tmp])
return ret_list

def list_squared_opt3(m, n):
# Improve the math overhead to not check for impossible divisors
ret_list = list()
for i in range(m, n):
tmp = sum([x ** 2 for x in range(1, int(i / 2 + 1)) if not i % x]) + i ** 2
if sqrt(tmp).is_integer():
ret_list.append([i, tmp])
return ret_list
def list_squared_opt4(m, n):
# Further reduce function overhead
ret_list = list()
for i in range(m, n):
a = int()
for x in range(1, int(i / 2 + 1)):
if not i % x:
a += x ** 2
a += i ** 2
if sqrt(a).is_integer():
ret_list.append([i, a])
return ret_list
print("Timing results for various functions, then executing them once to validate the results")
timer(list_squared, 42, 250)
print("Results are: %s" % list_squared(42, 250))
timer(list_squared_opt1, 42, 250)
print("Results are: %s" % list_squared_opt1(42, 250))
timer(list_squared_opt2, 42, 250)
print("Results are: %s" % list_squared_opt2(42, 250))
timer(list_squared_opt3, 42, 250)
print("Results are: %s" % list_squared_opt3(42, 250))
timer(list_squared_opt4, 42, 250)
print("Results are: %s" % list_squared_opt4(42, 250))

这输出:

/usr/test/venv/bin/python /usr/test/blah.py
Timing results for various functions, then executing them once to validate the results
list_squared at 10000 iterations took 16.172016859054565
Results are: [[42, 2500], [246, 84100]]
list_squared_opt1 at 10000 iterations took 15.923789834976196
Results are: [[42, 2500], [246, 84100]]
list_squared_opt2 at 10000 iterations took 15.620330572128296
Results are: [[42, 2500], [246, 84100]]
list_squared_opt3 at 10000 iterations took 11.640689611434937
Results are: [[42, 2500], [246, 84100]]
list_squared_opt4 at 10000 iterations took 10.224685668945312
Results are: [[42, 2500], [246, 84100]]
Process finished with exit code 0

现在做一些解释。 我试图展示的是一种采用迭代方法进行代码优化的方法。 在前几个修改的函数中,我们测试了一些相当简单的东西,修改代码结构以限制函数调用的数量,这在理论上应该可以节省一些时间,尽管它似乎可以忽略不计。到目前为止,最大的影响是优化函数中的数学。 我会尝试更多方法:

  • 使用踩踏或多处理来更好地考虑可用的系统资源(这是当前单线程应用程序(
  • 寻找更有效的方法来查找除数(可能是numpy或一些底层的C lib(
  • 进一步优化数学...我没有花很多时间在这上面,但似乎仍然有可能
  • 测试更快的数据结构,也许返回列表中的元组会更快(取决于结果的数量(等

希望这有帮助...

最新更新