Question presented to candidate:
"x in my_list is slow for a big list, but x in my_set is fast. What does a set actually do to find x, which of your object's methods does it call, and when does that speed break down?"
What a strong answer should cover:
- A set is a hash table of keys only:
hash(x)picks a starting slot (hash & mask), and the search walks a probe sequence until it hits the key or an empty slot. Average O(1), worst case O(n). - The match test, in order: equal stored hash, then identity (
is), then__eq__. So__eq__runs only on a hash match, and the identity shortcut is why the same NaN object is found. - The rules this imposes: members must be hashable, equal objects must hash alike (
{1, 1.0, True}has one element), and mutating an object's hash after insertion loses it. - A CPython detail: sets probe a few neighbouring slots linearly (
LINEAR_PROBES, 9) before jumping with the perturbed5*i + 1 + perturbstep, and resize at about 60% full, growing 4x. - Order: iteration walks slots, so set order depends on hashes, is not insertion order, and can change between runs for strings (hash randomisation).
Code / implementation expected: Optional โ instrumenting __hash__ / __eq__ to show which calls a lookup makes is a strong answer.