Cra*_*arB 6 python timeit python-3.x
我正在尝试使用Python中的timeit模块(编辑:我们使用的是Python 3)来决定几个不同的代码流.在我们的代码中,我们有一系列if语句来测试字符串中是否存在字符代码,如果有,则将其替换为:
if "<substring>" in str_var:
str_var = str_var.replace("<substring>", "<new_substring>")
Run Code Online (Sandbox Code Playgroud)
对于不同的子串,我们这样做了很多次.我们在这之间进行辩论并使用像这样的替换:
str_var = str_var.replace("<substring>", "<new_substring>")
Run Code Online (Sandbox Code Playgroud)
我们尝试使用timeit来确定哪一个更快.如果上面的第一个代码块是"stmt1"而第二个是"stmt2",我们的设置字符串看起来像
str_var = '<string><substring><more_string>',
Run Code Online (Sandbox Code Playgroud)
我们的timeit语句如下所示:
timeit.timeit(stmt=stmt1, setup=setup)
Run Code Online (Sandbox Code Playgroud)
和
timeit.timeit(stmt=stmt2, setup=setup)
Run Code Online (Sandbox Code Playgroud)
现在,在我们的两台笔记本电脑上运行它(相同的硬件,类似的处理负载)stmt1(带有if语句的语句)即使在多次运行后也会运行得更快(3-4个百分点,大约四分之一) stmt2的第二个).
但是,如果我们定义函数来做两件事(包括创建变量的设置),如下所示:
def foo():
str_var = '<string><substring><more_string>'
if "<substring>" in str_var:
str_var = str_var.replace("<substring>", "<new_substring>")
Run Code Online (Sandbox Code Playgroud)
和
def foo2():
str_var = '<string><substring><more_string>'
str_var = str_var.replace("<substring>", "<new_substring>")
Run Code Online (Sandbox Code Playgroud)
和运行timeit像:
timeit.timeit("foo()", setup="from __main__ import foo")
timeit.timeit("foo2()", setup="from __main__ import foo2")
Run Code Online (Sandbox Code Playgroud)
没有if语句(foo2)的语句运行得更快,与非功能结果相矛盾.
我们是否遗漏了Timeit的工作原理?或者Python如何处理这样的案例?
编辑这里是我们的实际代码:
>>> def foo():
s = "hi 1 2 3"
s = s.replace('1','5')
>>> def foo2():
s = "hi 1 2 3"
if '1' in s:
s = s.replace('1','5')
>>> timeit.timeit(foo, "from __main__ import foo")
0.4094226634183542
>>> timeit.timeit(foo2, "from __main__ import foo2")
0.4815539780738618
Run Code Online (Sandbox Code Playgroud)
vs这段代码:
>>> timeit.timeit("""s = s.replace("1","5")""", setup="s = 'hi 1 2 3'")
0.18738432400277816
>>> timeit.timeit("""if '1' in s: s = s.replace('1','5')""", setup="s = 'hi 1 2 3'")
0.02985000199987553
Run Code Online (Sandbox Code Playgroud)
我想我已经明白了.
看看这段代码:
timeit.timeit("""if '1' in s: s = s.replace('1','5')""", setup="s = 'hi 1 2 3'")
Run Code Online (Sandbox Code Playgroud)
在此代码中,setup只运行一次.这意味着它s变成了"全球化".结果,它hi 5 2 3在第一次迭代中被修改为in现在False,并且现在返回所有连续迭代.
看到这段代码:
timeit.timeit("""if '1' in s: s = s.replace('1','5'); print(s)""", setup="s = 'hi 1 2 3'")
Run Code Online (Sandbox Code Playgroud)
这将打印出hi 5 2 3一次,因为它print是if声明的一部分.对比这个,这将填满你的屏幕与吨吨hi 5 2 3:
timeit.timeit("""s = s.replace("1","5"); print(s)""", setup="s = 'hi 1 2 3'")
Run Code Online (Sandbox Code Playgroud)
所以这里的问题是带有if测试的非功能是有缺陷的并且给你错误的时间,除非对你已经处理的字符串的重复调用是你试图测试的.(如果它是你试图测试的,你的函数版本是有缺陷的.)函数的if优点不公平的原因是因为它replace在每次迭代时运行字符串的新副本.
下面的测试做什么,我相信你意,因为它不重新分配的结果replace回s,留下未修改每次迭代:
>>> timeit.timeit("""if '1' in s: s.replace('1','5')""", setup="s = 'hi 1 2 3'"
0.3221409016812231
>>> timeit.timeit("""s.replace('1','5')""", setup="s = 'hi 1 2 3'")
0.28558505721252914
Run Code Online (Sandbox Code Playgroud)
这个改变为if测试增加了很多时间,if为我增加了一些非测试时间,但我使用的是Python 2.7.但是,如果Python 3的结果是一致的,那么这些结果表明,in当字符串很少需要替换时,可以节省大量时间.如果他们通常需要更换,则需要in花费一点时间.