哪种序列类型更适合比较,为什么? (Python)
Which sequence type is better for a comparison and why? (Python)
我有一个条件可以将一个对象与其他多个对象进行比较,如下所示:
if 'a' in ('a','b','c','e'):
序列是为此目的创建的,不存在于函数的其他任何地方。考虑到它们似乎工作相同且列表很短,将其分组为元组、列表或集合的优缺点是什么?哪个是地道的?
使用集合直到你有充分的理由不使用。(然后使用列表。)
我会认为集合更加地道。它传达的意思更清楚,因为顺序无关紧要,重要的是成员身份。
要明确一点,集合是 集合 但不是 "sequence type"(即使它是可迭代的),因为它在语义上是 "unordered"。
为什么不用一套?
集合只能包含 可散列 类型。而且,这很重要,当您询问集合中是否存在不可散列的类型时,他们将引发 TypeError
而不是简单地返回 False
。如果您可能在 in
运算符的两边都得到一个不可散列的对象,那您就不走运了。有时您可以使用可哈希元素代替(例如 frozenset
而不是 set
或 tuple
而不是 list
),有时您不能。
但是元组和列表不必对它们的元素进行哈希处理。
为什么在元组上使用列表?
列表的主要优点是它们避免了一个元素的元组的句法怪癖。假设您有 ('foo', 'bar')
,后来决定删除 'bar'
。那么你有('foo')
。哎呀,看到我在那里做了什么吗?它实际上应该是 ('foo',)
。很容易忘记逗号。 in
检查仍然适用于像 ('foo')
这样的字符串,因为 in
检查子字符串。这可以巧妙地改变程序的含义。 'oo'
在 ('foo')
中,但不在 ('foo',)
中。
像 ['foo']
这样的单项列表没有这个问题。 [并作为
user2357112 指出,一个常量列表无论如何都会被编译成一个元组。]
请注意,像 {'a'}
这样的单项集也不存在该问题。一个空的 {}
是一个字典,但这不会导致 in
检查出现任何问题,因为它也是一个空集合。
但是当仅与一个元素进行比较时,可以说您应该使用 ==
而不是 in
。
为了清楚起见,就这些了。现在进行微优化。早期优化是万恶之源。在实际需要之前,不要以牺牲可读性为代价进行优化。
集合查找如果不是太小则速度更快,因为必须逐个检查元组的元素(平均而言)随着元组的大小而增长,而集合由哈希表支持(就像一个字典),它有一个小的恒定开销。如果事例的分布不均匀,这意味着元组中元素的顺序很重要。平均而言,将更常见的情况放在元组的前面将使检查速度比反向快得多。
要使集合的恒定开销很重要,集合必须多小?配置文件并查看。性能可能因许多因素而异。这不仅仅是元素的数量,还包括相等性检查需要多长时间,以及它们在内存中的位置等。
与其他集合相比,元组在内存和构造时间方面的开销应该略小。但是,如果编译器可以将其加载为保存的常量值,那么构造开销并不重要。 (当所有元素本身在编译时都是常量时,就会发生这种情况。您可以使用 dis
模块来确认这种情况。)
我有一个条件可以将一个对象与其他多个对象进行比较,如下所示:
if 'a' in ('a','b','c','e'):
序列是为此目的创建的,不存在于函数的其他任何地方。考虑到它们似乎工作相同且列表很短,将其分组为元组、列表或集合的优缺点是什么?哪个是地道的?
使用集合直到你有充分的理由不使用。(然后使用列表。)
我会认为集合更加地道。它传达的意思更清楚,因为顺序无关紧要,重要的是成员身份。
要明确一点,集合是 集合 但不是 "sequence type"(即使它是可迭代的),因为它在语义上是 "unordered"。
为什么不用一套?
集合只能包含 可散列 类型。而且,这很重要,当您询问集合中是否存在不可散列的类型时,他们将引发 TypeError
而不是简单地返回 False
。如果您可能在 in
运算符的两边都得到一个不可散列的对象,那您就不走运了。有时您可以使用可哈希元素代替(例如 frozenset
而不是 set
或 tuple
而不是 list
),有时您不能。
但是元组和列表不必对它们的元素进行哈希处理。
为什么在元组上使用列表?
列表的主要优点是它们避免了一个元素的元组的句法怪癖。假设您有 ('foo', 'bar')
,后来决定删除 'bar'
。那么你有('foo')
。哎呀,看到我在那里做了什么吗?它实际上应该是 ('foo',)
。很容易忘记逗号。 in
检查仍然适用于像 ('foo')
这样的字符串,因为 in
检查子字符串。这可以巧妙地改变程序的含义。 'oo'
在 ('foo')
中,但不在 ('foo',)
中。
像 ['foo']
这样的单项列表没有这个问题。 [并作为
user2357112 指出,一个常量列表无论如何都会被编译成一个元组。]
请注意,像 {'a'}
这样的单项集也不存在该问题。一个空的 {}
是一个字典,但这不会导致 in
检查出现任何问题,因为它也是一个空集合。
但是当仅与一个元素进行比较时,可以说您应该使用 ==
而不是 in
。
为了清楚起见,就这些了。现在进行微优化。早期优化是万恶之源。在实际需要之前,不要以牺牲可读性为代价进行优化。
集合查找如果不是太小则速度更快,因为必须逐个检查元组的元素(平均而言)随着元组的大小而增长,而集合由哈希表支持(就像一个字典),它有一个小的恒定开销。如果事例的分布不均匀,这意味着元组中元素的顺序很重要。平均而言,将更常见的情况放在元组的前面将使检查速度比反向快得多。
要使集合的恒定开销很重要,集合必须多小?配置文件并查看。性能可能因许多因素而异。这不仅仅是元素的数量,还包括相等性检查需要多长时间,以及它们在内存中的位置等。
与其他集合相比,元组在内存和构造时间方面的开销应该略小。但是,如果编译器可以将其加载为保存的常量值,那么构造开销并不重要。 (当所有元素本身在编译时都是常量时,就会发生这种情况。您可以使用 dis
模块来确认这种情况。)