依稀记得在公司刚开始写代码时,大佬看到我写这种语句
if xxx in [xxx, xxx, ...]:
...
告诉我,遇到这种情况,要用元组替代列表,因为 in 操作在元组中更快,类似这样
if xxx in (xxx, xxx, ...):
...
后来在网上查资料说是两个的数据结构的不同导致元组会比列表性能更高一点,今天闲来无事,写了一个测试,没想到元组比 list 慢的多?请各位大佬赐教 代码
a = [i for i in range(100000000)]
s = time.time()
if 99999993 in a:
print('true')
e = time.time()
t = e - s
print(t) --> 1.7924060821533203
c = (i for i in range(100000000))
s = time.time()
if 99999993 in c:
print('true')
e = time.time()
t = e - s
print(t) --> 8.226477146148682
1
ruanimal 2020-11-17 15:51:42 +08:00
你这个写法不对,第二部分并不是元祖是生成器
|
2
Wincer 2020-11-17 15:55:15 +08:00 1
首先,圆括号()的表达式不生成元组,而是生成器,你需要先把生成器转成 tuple,再使用 in 来判断:
c = tuple(range(100000000)) s = time.time() if 99999993 in c: print('true') e = time.time() t = e - s print(t) 其次,想 in 操作更快,可以换成花括号(集合):{xxx, xxx, xxx} |
5
fasionchan 2020-11-17 19:11:36 +08:00
其实两者一样慢,都是 O(n)操作;而且你写的是字面量,n 本来就很小,所以差别更是微乎其微。有些 tuple 字面量可以编译成常量,这样就不用每次都创建 tuple 对象,有一丁点性能优势。另外,考虑 list 和 tuple 对象的内部结构,tuple 也有些优势。具体可以参考 Python 虚拟机内部原理,特别是内建对象部分:
https://www.imooc.com/read/76 这个例子不如这样理解:在什么场景,就用什么数据结构。如果你需要一个不需要变化的列表,那就用 tuple 对象,而不是 list 对象。这样既避免意外修改,也获得一丁点性能优势。单从性能考虑,则有些牵强。 |
6
fasionchan 2020-11-17 19:17:05 +08:00
对了,还可以观察字节码,看看不同的写法有什么差别。下面是一个可以编译成常量的 tuple 对象的例子:
``` >>> dis.dis(compile('a = ("a", "b", "c")', '', 'exec')) 1 0 LOAD_CONST 0 (('a', 'b', 'c')) 2 STORE_NAME 0 (a) 4 LOAD_CONST 1 (None) 6 RETURN_VALUE ``` 而同样的 list 对象则不能,只能即时创建(BUILD_LIST 字节码): ``` >>> dis.dis(compile('a = ["a", "b", "c"]', '', 'exec')) 1 0 LOAD_CONST 0 ('a') 2 LOAD_CONST 1 ('b') 4 LOAD_CONST 2 ('c') 6 BUILD_LIST 3 8 STORE_NAME 0 (a) 10 LOAD_CONST 3 (None) 12 RETURN_VALUE ``` 关于 Python 代码编译过程与字节码,我上面贴的链接里面同样有介绍。 |
7
yucongo 2020-11-17 21:16:14 +08:00
In [112]: tuple_ = tuple(range(100000))
In [113]: list_ = [*range(100000)] In [114]: %timeit 999 in list_ 65.2 µs ± 16.8 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) In [115]: %timeit 999 in tuple_ 60.3 µs ± 5.88 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) In [116]: %timeit 999 in tuple_ 60 µs ± 4.19 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) In [117]: %timeit 999 in list_ 54.2 µs ± 1.38 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 其实几乎没有区别 |
8
dingwen07 2020-11-17 22:25:55 +08:00 via iPhone 1
当你 print 的时候,最慢的是 io
|
9
keepwalk2020 2020-11-18 08:04:10 +08:00
如果只是判断是否包含,用 set 肯定比 tuple 和 list 都快,
如果集合成员固定的话,用 frozenset 会更快一点,毕竟 frozenset 比 set 少调用了一次源码里的 set_clear_internal 函数。 |
10
freakxx 2020-11-19 22:08:11 +08:00
|