# 推荐写法。代码耗时:20.6 秒import math
defmain(): # 定义到函数中,以减少全部变量使用
size = 10000for x inrange(size):
for y inrange(size):
z = math.sqrt(x) + math.sqrt(y)
main()
2. 避免属性访问
2.1 避免模块和函数属性访问
# 不推荐写法。代码耗时:14.5 秒import math
defcomputeSqrt(size: int):
result = []
for i inrange(size):
result.append(math.sqrt(i))
return result
defmain():
size = 10000for _ inrange(size):
result = computeSqrt(size)
main()
# 第一次优化写法。代码耗时:10.9 秒from math import sqrt
defcomputeSqrt(size: int):
result = []
for i inrange(size):
result.append(sqrt(i)) # 避免 math.sqrt 的使用return result
defmain():
size = 10000for _ inrange(size):
result = computeSqrt(size)
main()
# 推荐写法,代码耗时:0.33 秒classDemoClass:
def__init__(self, value: int):
self.value = value # 避免不必要的属性访问器defmain():
size = 1000000for i inrange(size):
demo_instance = DemoClass(size)
value = demo_instance.value
demo_instance.value = i
main()
4. 避免数据复制
4.1 避免无意义的数据复制
# 不推荐写法,代码耗时:6.5 秒defmain():
size = 10000for _ inrange(size):
value = range(size)
value_list = [x for x in value]
square_list = [x * x for x in value_list]
main()
上面的代码中 value_list 完全没有必要,这会创建不必要的数据结构或复制。
# 推荐写法,代码耗时:4.8 秒defmain():
size = 10000for _ inrange(size):
value = range(size)
square_list = [x * x for x in value] # 避免无意义的复制
main()
# 推荐写法,代码耗时:0.06 秒defmain():
size = 1000000for _ inrange(size):
a = 3
b = 5
a, b = b, a # 不借助中间变量
main()
4.3 字符串拼接用 join 而不是+
# 不推荐写法,代码耗时:2.6 秒import string
from typing importListdefconcatString(string_list: List[str]) -> str:
result = ''for str_i in string_list:
result += str_i
return result
defmain():
string_list = list(string.ascii_letters * 100)
for _ inrange(10000):
result = concatString(string_list)
main()
当使用 a + b 拼接字符串时,由于 Python 中字符串是不可变对象,其会申请一块内存空间,将 a 和 b 分别复制到该新申请的内存空间中。因此,如果要拼接 n 个字符串,会产生 n-1 个中间结果,每产生一个中间结果都需要申请和复制一次内存,严重影响运行效率。而使用 join() 拼接字符串时,会首先计算出需要申请的总的内存空间,然后一次性地申请所需内存,并将每个字符串元素复制到该内存中去。
# 推荐写法,代码耗时:0.3 秒import string
from typing importListdefconcatString(string_list: List[str]) -> str:
return''.join(string_list) # 使用 join 而不是 +defmain():
string_list = list(string.ascii_letters * 100)
for _ inrange(10000):
result = concatString(string_list)
main()
5. 利用 if 条件的短路特性
# 不推荐写法,代码耗时:0.05 秒from typing importListdefconcatString(string_list: List[str]) -> str:
abbreviations = {'cf.', 'e.g.', 'ex.', 'etc.', 'flg.', 'i.e.', 'Mr.', 'vs.'}
abbr_count = 0
result = ''for str_i in string_list:
if str_i in abbreviations:
result += str_i
return result
defmain():
for _ inrange(10000):
string_list = ['Mr.', 'Hat', 'is', 'Chasing', 'the', 'black', 'cat', '.']
result = concatString(string_list)
main()
if 条件的短路特性是指对 if a and b 这样的语句, 当 a 为 False 时将直接返回,不再计算 b;对于 if a or b 这样的语句,当 a 为 True 时将直接返回,不再计算 b。因此, 为了节约运行时间,对于 or 语句,应该将值为 True 可能性比较高的变量写在 or 前,而 and 应该推后。
# 推荐写法,代码耗时:0.03 秒from typing importListdefconcatString(string_list: List[str]) -> str:
abbreviations = {'cf.', 'e.g.', 'ex.', 'etc.', 'flg.', 'i.e.', 'Mr.', 'vs.'}
abbr_count = 0
result = ''for str_i in string_list:
if str_i[-1] == '.'and str_i in abbreviations: # 利用 if 条件的短路特性
result += str_i
return result
defmain():
for _ inrange(10000):
string_list = ['Mr.', 'Hat', 'is', 'Chasing', 'the', 'black', 'cat', '.']
result = concatString(string_list)
main()
6. 循环优化
6.1 用 for 循环代替 while 循环
# 不推荐写法。代码耗时:6.7 秒defcomputeSum(size: int) -> int:
sum_ = 0
i = 0while i < size:
sum_ += i
i += 1return sum_
defmain():
size = 10000for _ inrange(size):
sum_ = computeSum(size)
main()
Python 的 for 循环比 while 循环快不少。
# 推荐写法。代码耗时:4.3 秒defcomputeSum(size: int) -> int:
sum_ = 0for i inrange(size): # for 循环代替 while 循环
sum_ += i
return sum_
defmain():
size = 10000for _ inrange(size):
sum_ = computeSum(size)
main()
6.2 使用隐式 for 循环代替显式 for 循环
针对上面的例子,更进一步可以用隐式 for 循环来替代显式 for 循环
# 推荐写法。代码耗时:1.7 秒defcomputeSum(size: int) -> int:
returnsum(range(size)) # 隐式 for 循环代替显式 for 循环defmain():
size = 10000for _ inrange(size):
sum = computeSum(size)
main()
6.3 减少内层 for 循环的计算
# 不推荐写法。代码耗时:12.8 秒import math
defmain():
size = 10000
sqrt = math.sqrt
for x inrange(size):
for y inrange(size):
z = sqrt(x) + sqrt(y)
main()
上面的代码中 sqrt(x) 位于内侧 for 循环, 每次训练过程中都会重新计算一次,增加了时间开销。
# 推荐写法。代码耗时:7.0 秒import math
defmain():
size = 10000
sqrt = math.sqrt
for x inrange(size):
sqrt_x = sqrt(x) # 减少内层 for 循环的计算for y inrange(size):
z = sqrt_x + sqrt(y)
main()