Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to provide additional initialization for a subclass of namedtuple?

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.

like image 302
Björn Pollex Avatar asked Sep 02 '10 07:09

Björn Pollex


People also ask

Can you subclass Namedtuple?

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.

How do I change Namedtuple 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.

Can Namedtuple be pickled?

@Antimony: pickle handles namedtuple classes just fine; classes defined in a function local namespace not so much.


1 Answers

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.

like image 61
habnabit Avatar answered Sep 19 '22 14:09

habnabit