Home > Software engineering >  Named tuples existence in a hashset
Named tuples existence in a hashset

Time:11-17

In [1]: x = set()
In [2]: pos = collections.namedtuple('Position', ['x','y'])
In [4]: x.add(pos(1,1))
In [5]: x
Out[5]: {Position(x=1, y=1)}
In [6]: pos(1,1) in x
Out[6]: True
In [8]: pos(1,2) in x
Out[8]: False

I was not expecting Line 6 pos(1,1) in x to work. Since it does seem that pos(1,1) creates an object with a different object id every time.

In [9]: id(pos(1,1))
Out[9]: 140290954200696
In [10]: id(pos(1,1))
Out[10]: 140290954171016

How does the set in operator work on named tuples in this case? Does it check the contents of namedtuple?

CodePudding user response:

namedtuple is not special. The element should be exactly equal(__eq__) and must have similar hash to pass the containment.

>>> hash(pos(1, 1))
8389048192121911274
>>> pos(1, 1) == pos(1, 1)
True

If you are interested see the implementation here, set().__contains__(y) first have to compute the hash value of y.

static int
set_contains_key(PySetObject *so, PyObject *key)
{
    Py_hash_t hash;

    if (!PyUnicode_CheckExact(key) ||
        (hash = _PyASCIIObject_CAST(key)->hash) == -1) {
        hash = PyObject_Hash(key);
        if (hash == -1)
            return -1;
    }
    return set_contains_entry(so, key, hash);
}

but computing hash alone does not says whether the element are equal. For example

>>> hash(-1)
-2
>>> hash(-2)
-2

Which means that if the hash values are equal then __eq__ check is required to confirm if the elements are exactly equal.

Please note that my answer is purely based on Cpython implementation.

CodePudding user response:

A tuple of hashable objects is hashable, so it can be used as a member of a set and therefore pass the in check.
Since you are using numbers as tuple values, which are obviously hashable, there is no problem hashing the entire tuple.

  • Related