使用Python Timeit来计时你的代码
在本教程中,你将学习如何使用python的timeit模块中的timeit函数。你将学会如何计时python中的简单表达式和函数。
计时你的代码可以帮助你估计代码的执行时间,并找出需要优化的代码部分。
我们将首先学习python的timeit函数的语法。然后我们将编写示例代码,了解如何使用它来计时代码块和函数。让我们开始吧。
如何使用python的timeit函数
timeit模块是python标准库的一部分,你可以导入它:
import timeit
使用timeit模块中的timeit函数的语法如下:
timeit.timeit(stmt, setup, number)
这里:
- stmt是要测量执行时间的代码块。你可以将其指定为简单的python字符串或多行字符串,或者传递可调用对象的名称。
- 正如其名称所示,setup是只需要运行一次的代码块,通常作为stmt运行的一部分。例如,假设您正在计算创建numpy数组的执行时间。在这种情况下,导入numpy是setup代码,而实际的数组创建是要计时的语句。
- number参数表示运行stmt的次数。number的默认值是100万(1000000),但你也可以将此参数设置为其他任意值。
现在我们已经学会了使用timeit()函数的语法,让我们开始编写一些示例代码。
计时简单的python表达式
在本节中,我们将尝试使用timeit测量简单python表达式的执行时间。
启动python repl并运行以下代码示例。在这里,我们计算了指数和整除运算符在10000次和100000次运行中的执行时间。
请注意,我们将要计时的语句作为python字符串传递,并使用分号分隔语句中的不同表达式。
>>> import timeit
>>> timeit.timeit('3**4;3//4',number=10000)
0.0004020999999738706
>>> timeit.timeit('3**4;3//4',number=100000)
0.0013780000000451764
在命令行中运行python timeit
你也可以在命令行中使用timeit。以下是timeit函数调用的命令行等价形式:
$ python -m timeit -n [number] -s [setup] [stmt]
python -m timeit
表示我们将timeit作为主模块运行。n
是一个命令行选项,表示代码应该运行的次数。这相当于timeit()函数调用中的number参数。- 你可以使用选项-s来定义setup代码。
下面,我们使用命令行等价形式重写了前面的示例:
在这个例子中,我们计算内置的len()
函数的执行时间。字符串的初始化是使用s
选项传递的设置代码。
$ python -m timeit -n 100000 '3**4;3//4'
100000 loops, best of 5: 35.8 nsec per loop
在输出中,注意到我们得到了5次中的最佳运行时间。这是什么意思?当你在命令行上运行timeit
时,repeat
选项r
被设置为默认值5。这意味着对指定次数的stmt
的执行将重复五次,并返回最佳的执行时间。
使用timeit进行字符串反转方法的分析
在使用python字符串时,你可能想要对其进行反转。字符串反转的两种常见方法如下:
- 使用字符串切片
- 使用
reversed()
函数和join()
方法
使用字符串切片反转python字符串
让我们了解一下字符串切片的工作原理,以及如何使用它来反转python字符串。使用语法some-string[start:stop]
返回从索引start
开始并延伸到索引stop-1
的字符串切片。让我们举个例子。
考虑以下字符串'python'。字符串的长度为6,索引列表为0、1、2直到5。
>>> string_1 = 'python'
当你同时指定start
和stop
值时,你会得到一个字符串切片,它从start
到stop-1
扩展。因此,string_1[1:4]
返回'yth'。
>>> string_1 = 'python'
>>> string_1[1:4]
'yth'
当你不指定start
值时,将使用默认的start
值为零,切片从索引零开始,延伸到stop - 1
。
这里,stop
值为3,所以切片从索引0开始,延伸到索引2。
>>> string_1[:3]
'pyt'
当你不包括stop
索引时,你会看到切片从start
索引(1)开始,延伸到字符串的末尾。
>>> string_1[1:]
'ython'
忽略start
和stop
值都返回整个字符串的切片。
>>> string_1[::]
'python'
让我们创建一个带有step
值的切片。将start
、stop
和step
值分别设置为1、5和2。我们得到一个从1开始延伸到4(不包括结束点5)的字符串切片,其中包含每隔一个字符的字符。
>>> string_1[1:5:2]
'yh'
当你使用负步长时,可以从字符串的末尾开始切片。设置步长为-2,string_1[5:2:-2]
得到以下切片:
>>> string_1[5:2:-2]
'nh'
所以,为了得到字符串的反向副本,我们跳过start
和stop
值,并将步长设为-1,如下所示:
>>> string_1[::-1]
'nohtyp'
总结一下:
string[::-1]
返回一个字符串的反向副本。
使用内置函数和字符串方法来反转字符串
python中内置的reversed()
函数会返回一个字符串元素的反向迭代器。
>>> string_1 = 'python'
>>> reversed(string_1)
所以你可以使用for循环
遍历反向迭代器:
for char in reversed(string_1):
print(char)
并以反向顺序访问字符串的元素。
# 输出
n
o
h
t
y
p
接下来,你可以在反向迭代器上调用join()
方法,其语法为:.join(reversed(some-string))
。
下面的代码段展示了一些示例,其中分隔符分别为连字符和空格。
>>> '-'.join(reversed(string1))
'n-o-h-t-y-p'
>>> ' '.join(reversed(string1))
'n o h t y p'
在这里,我们不想要任何分隔符;所以将分隔符设置为空字符串,以获得字符串的反向副本:
>>> ''.join(reversed(string1))
'nohtyp'
使用
''.join(reversed(some-string))
返回一个字符串的反向副本。
使用timeit比较执行时间
到目前为止,我们已经学习了两种反转python字符串的方法。但是哪一种更快呢?让我们来看看。
在之前的一个示例中,我们计时了简单的python表达式,没有任何setup
代码。在这里,我们正在反转python字符串。虽然字符串反转操作按照number
指定的次数运行,但setup
代码是字符串的初始化,只运行一次。
>>> import timeit
>>> timeit.timeit(stmt = 'string_1[::-1]', setup = "string_1 = 'python'", number = 100000)
0.04951830000001678
>>> timeit.timeit(stmt = "''.join(reversed(string_1))", setup = "string_1 = 'python'", number = 100000)
0.12858760000000302
对于相同次数的字符串反转,字符串切片的方法比使用join()
方法和reversed()
函数更快。
你也可以阅读如何在python中反转列表以逆时针旋转它。
使用timeit计时python函数
在本节中,让我们学习如何使用timeit函数计时python函数。给定一个字符串列表,下面的函数hasdigit
返回至少包含一个数字的字符串列表。
def hasdigit(somelist):
str_with_digit = []
for string in somelist:
check_char = [char.isdigit() for char in string]
if any(check_char):
str_with_digit.append(string)
return str_with_digit
现在我们想要使用timeit
来测量这个python函数hasdigit()
的执行时间。
首先,让我们确定需要计时的语句(stmt
)。它是调用函数hasdigit()
并将一个字符串列表作为参数的语句。接下来,让我们定义setup代码。你能猜到setup
代码应该是什么吗?
为了使函数调用成功运行,setup
代码应包括以下内容:
- 函数
hasdigit()
的定义 - 字符串列表参数的初始化
让我们在下面的setup
字符串中定义setup
代码:
setup = """
def hasdigit(somelist):
str_with_digit = []
for string in somelist:
check_char = [char.isdigit() for char in string]
if any(check_char):
str_with_digit.append(string)
return str_with_digit
thislist=['puffin3','7frost','blue']
"""
接下来,我们可以使用timeit
函数并获得hasdigit()
函数在100,000次运行中的执行时间。
import timeit
timeit.timeit('hasdigit(thislist)',setup=setup,number=100000)
# 输出
0.2810094920000097
结论
你已经学会了如何使用python的timeit函数来计时表达式、函数和其他可调用对象。这可以帮助你对代码进行基准测试,比较不同实现的相同函数的执行时间等。
让我们回顾一下在本教程中学到的内容。你可以使用语法timeit.timeit(stmt=...,setup=...,number=...)
来使用timeit()
函数。另外,你还可以在命令行上运行timeit来计时短的代码片段。
作为下一步,你可以探索如何使用其他python性能分析包,如line-profiler和memprofiler,来分析你的代码的时间和内存使用情况。
接下来,学习如何在python中calculate time difference
。