How to provide additional initialization for a subclass of namedtuple?

前端 未结 3 2052
太阳男子
太阳男子 2020-12-23 17:25

Suppose I have a namedtuple like this:

EdgeBase = namedtuple(\"EdgeBase\", \"left, right\")

I want to implement a custom hash-

3条回答
  •  春和景丽
    2020-12-23 17:50

    In Python 3.7+, you can now use dataclasses to build hashable classes with ease.

    Code

    Assuming int types of left and right, we use the default hashing via unsafe_hash+ keyword:

    import dataclasses as dc
    
    
    @dc.dataclass(unsafe_hash=True)
    class Edge:
        left: int
        right: int
    
    
    hash(Edge(1, 2))
    # 3713081631934410656
    

    Now we can use these (mutable) hashable objects as elements in a set or (keys in a dict).

    {Edge(1, 2), Edge(1, 2), Edge(2, 1), Edge(2, 3)}
    # {Edge(left=1, right=2), Edge(left=2, right=1), Edge(left=2, right=3)}
    

    Details

    We can alternatively override the __hash__ function:

    @dc.dataclass
    class Edge:
        left: int
        right: int
    
        def __post_init__(self):
            # Add custom hashing function here
            self._hash = hash((self.left, self.right))         # emulates default
    
        def __hash__(self):
            return self._hash
    
    
    hash(Edge(1, 2))
    # 3713081631934410656
    

    Expanding on @ShadowRanger's comment, the OP's custom hash function is not reliable. In particular, the attribute values can be interchanged, e.g. hash(Edge(1, 2)) == hash(Edge(2, 1)), which is likely unintended.

    +Note, the name "unsafe" suggests the default hash will be used despite being a mutable object. This may be undesired, particularly within a dict expecting immutable keys. Immutable hashing can be turned on with the appropriate keywords. See also more on hashing logic in dataclasses and a related issue.

提交回复
热议问题