通常我有一个偏移量和数据长度,我想从 str 或 bytes 中提取数据。
我最常看到的方式是:
mystr[ offset: offset+length ]
改为执行以下操作(这似乎更容易理解)效率会降低多少?
mystr[ offset: ][ :length ]
如果数据实际上被复制了两次,并且为每个副本分配了内存,那么效率会非常低。但如果它是用指针和引用计数魔法完成的,也许效率不会低很多?它甚至可以被优化。
这也引出了更长的切片操作组合的效率问题,尽管到目前为止我还没有发现需要更多。
TLDR
绳子越长,越吸
与mystr[ offset: ][ :length ]
相比mystr[ offset: offset+length ]
背景:
你可以
timeit
如果你喜欢并且结果是戏剧性的(至少对于香草蟒蛇和莎士比亚全集),
mystr[ offset: offset+length ]
比mystr[ offset: ][ :length ]
快几个数量级。
import timeit
setup = """
offset = 1000
length = 1000
with open("shakespeare.txt", "r", encoding="utf-8") as file_in:
mystr = file_in.read()
def test1(mystr):
return mystr[ offset: offset+length ]
def test2(mystr):
return mystr[ offset: ][ :length ]
"""
print(f"Test1: {timeit.timeit('test1(mystr)', setup=setup, number=1000)}")
print(f"Test2: {timeit.timeit('test2(mystr)', setup=setup, number=1000)}")
在装有莎士比亚全集的笔记本电脑上,我得到如下结果:
Test1: 0.00045
Test2: 2.98909
请注意,所讨论的文本相当长,文本较短,结果并没有那么糟糕。
import timeit
setup = """
offset = 1000
length = 1000
with open("shakespeare.txt", "r", encoding="utf-8") as file_in:
mystr = file_in.read()[:3000]
def test1(mystr):
return mystr[ offset: offset+length ]
def test2(mystr):
return mystr[ offset: ][ :length ]
"""
print(f"Test1: {timeit.timeit('test1(mystr)', setup=setup, number=1000)}")
print(f"Test2: {timeit.timeit('test2(mystr)', setup=setup, number=1000)}")
用那个较短的字符串我得到:
Test1: 0.00045
Test2: 0.00081
请注意,
test1()
的时间并没有随着文本的长度而变化,而文本越长,test2()
变得越慢。