根据参数类型

时间:2018-06-06 19:26:21

标签: python performance set

为什么会这个问题?

我试图回答这个问题:Check if All Values Exist as Keys in Dictionary比生成器理解更好地提供给all(python循环,即使在理解中,与某些函数执行的隐式循环相比,减慢了执行速度) :

all(i in bar for i in foo)

其中bar是字典,foo是使用set.issubset(转换为set foo能够使用{的foo.issubset(bar)列表{1}}),并没有成功击败all解决方案的时间(除非两个容器都转换为set s。)

我的问题:

来自set的文档:

  

注意,union(),intersection(),difference()和symmetric_difference(),issubset()和issuperset()方法的非运算符版本将接受任何可迭代的参数。相比之下,他们基于运营商的同行要求他们的论点是集合。这排除了容易出错的结构,例如set(' abc')& ' CBS'支持更具可读性的集合(' abc')。交叉点(' cbs')。

好的,但性能实际上取决于参数的类型,即使复杂性没有(The complextiy of Python issubset()):

import timeit
foo = {i for i in range(1, 10000, 2)}
bar = foo - {400}
n=10000
x = timeit.timeit(setup="foo = {str(i) for i in range(1, 10000, 2)};bar = foo - {'400'}",stmt="bar.issubset(foo)",number=n)
print("issubset(set)",x)
x = timeit.timeit(setup="foo = {str(i) for i in range(1, 10000, 2)};bar = foo - {'400'};foo=list(foo)",stmt="bar.issubset(foo)",number=n)
print("issubset(list)",x)
x = timeit.timeit(setup="foo = {str(i):i for i in range(1, 10000, 2)};bar = set(foo) - {'400'}",stmt="bar.issubset(foo)",number=n)
print("issubset(dict)",x)
x = timeit.timeit(setup="foo = {str(i):i for i in range(1, 10000, 2)}.keys();bar = set(foo) - {'400'}",stmt="bar.issubset(foo)",number=n)
print("issubset(dict_keys)",x)

我的结果(Python 3.4):

issubset(set) 1.6141405847648826
issubset(list) 3.698748032058883
issubset(dict) 3.6300025109004244
issubset(dict_keys) 4.224299651223102

因此,如果将set作为参数传递,则结果非常快。

使用list要慢得多。我发现这是因为必须在字符串上进行散列是很昂贵的。所以我用这样的整数改变了我的测试输入:

foo = {i for i in range(1, 10000, 2)}
bar = foo - {400}

结果全球速度更快,但仍然存在巨大的时差:

issubset(set) 0.5981848205989139
issubset(list) 1.7991591232742143
issubset(dict) 1.889119736960271
issubset(dict_keys) 2.2531574114632678

我还尝试将dict更改为dict.keys(),因为在python 3中,密钥被称为(https://www.python.org/dev/peps/pep-3106/)"类似集合或无序的容器对象&#34 ;

但在这种情况下,结果甚至比使用dictlist更糟糕。

那么为什么传递set次传递listdictdict_keys对象?我不知道看到文档中提到的有关此内容的任何内容。

1 个答案:

答案 0 :(得分:3)

set.issubset algorithm需要使用一个集合(frozensets和子类计数);如果你传递了别的东西,它就会成一套。它基本上是all(elem in other for elem in self),它需要知道elem in other是有效的,并且意味着它对集合意味着什么。它知道如何保证这一点的唯一方法是确保other是一个集合。制作套装很贵。

(我已经掩盖了一些细节。如果你想确切地知道发生了什么,特别是如果你有一个奇怪的集子类,请阅读链接中的源代码。)