Suppose I have a namedtuple
like this:
EdgeBase = namedtuple("EdgeBase", "left, right")
I want to implement a custom hash-function for this, so I create the following subclass:
class Edge(EdgeBase): def __hash__(self): return hash(self.left) * hash(self.right)
Since the object is immutable, I want the hash-value to be calculated only once, so I do this:
class Edge(EdgeBase): def __init__(self, left, right): self._hash = hash(self.left) * hash(self.right) def __hash__(self): return self._hash
This appears to be working, but I am really not sure about subclassing and initialization in Python, especially with tuples. Are there any pitfalls to this solution? Is there a recommended way how to do this? Is it fine? Thanks in advance.
As namedtuples are a subclass of tuples, the fields can be accessed via the index or by the name of the field. The index value of a field is tied to the order during the declaration of the namedtuple. Consider the above Address example. You can access the street field by name or by using 0 as the index value.
Since a named tuple is a tuple, and tuples are immutable, it is impossible to change the value of a field. In this case, we have to use another private method _replace() to replace values of the field. The _replace() method will return a new named tuple.
@Antimony: pickle handles namedtuple classes just fine; classes defined in a function local namespace not so much.
edit for 2017: turns out namedtuple
isn't a great idea. attrs is the modern alternative.
class Edge(EdgeBase): def __new__(cls, left, right): self = super(Edge, cls).__new__(cls, left, right) self._hash = hash(self.left) * hash(self.right) return self def __hash__(self): return self._hash
__new__
is what you want to call here because tuples are immutable. Immutable objects are created in __new__
and then returned to the user, instead of being populated with data in __init__
.
cls
has to be passed twice to the super
call on __new__
because __new__
is, for historical/odd reasons implicitly a staticmethod
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With