Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
121 views
in Technique[技术] by (71.8m points)

python - Why are tuples constructed from differently initialized sets equal?

I expected the following two tuples

>>> x = tuple(set([1, "a", "b", "c", "z", "f"]))
>>> y = tuple(set(["a", "b", "c", "z", "f", 1]))

to compare unequal, but they don't:

>>> x == y
>>> True

Why is that?

question from:https://stackoverflow.com/questions/26115765/why-are-tuples-constructed-from-differently-initialized-sets-equal

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

At first glance, it appears that x should always equal y, because two sets constructed from the same elements are always equal:

>>> x = set([1, "a", "b", "c", "z", "f"])
>>> y = set(["a", "b", "c", "z", "f", 1])
>>> x
{1, 'z', 'a', 'b', 'c', 'f'}
>>> y
{1, 'z', 'a', 'b', 'c', 'f'}
>>> x == y
True

However, it is not always the case that tuples (or other ordered collections) constructed from two equal sets are equal.

In fact, the result of your comparison is sometimes True and sometimes False, at least in Python >= 3.3. Testing the following code:

# compare.py
x = tuple(set([1, "a", "b", "c", "z", "f"]))
y = tuple(set(["a", "b", "c", "z", "f", 1]))
print(x == y)

... a thousand times:

$ for x in {1..1000}
> do
>   python3.3 compare.py
> done | sort | uniq -c
147 False
853 True

This is because, since Python 3.3, the hash values of strings, bytes and datetimes are randomized as a result of a security fix. Depending on what the hashes are, "collisions" may occur, which will mean that the order items are stored in the underlying array (and therefore the iteration order) depends on the insertion order.

Here's the relevant bit from the docs:

Security improvements:

  • Hash randomization is switched on by default.

https://docs.python.org/3/whatsnew/3.3.html

EDIT: Since it's mentioned in the comments that the True/False ratio above is superficially surprising ...

Sets, like dictionaries, are implemented as hash tables - so if there's a collision, the order of items in the table (and so the order of iteration) will depend both on which item was added first (different in x and y in this case) and the seed used for hashing (different across Python invocations since 3.3). Since collisions are rare by design, and the examples in this question are smallish sets, the issue doesn't arise as often as one might initially suppose.

For a thorough explanation of Python's implementation of dictionaries and sets, see The Mighty Dictionary.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...