mike3996
mike3996

Reputation: 17537

Why inheriting from namedtuple results in infinite recursion in this case?

I planned to write a small class to host a dictionary of stuff and some helper methods related to it. While in this particular case inheriting from namedtuple doesn't make much sense, I did it out of habit.

class Conf(collections.namedtuple('Conf', 'data')):
    def __getitem__(self, attr):
        return self.data[attr]

    def get(self, attr, default=None):
        return self.data.get(attr, default)

This, however, triggers in infinite recursion wrt __getitem__ calling itself repeatedly when I call .get() properly! F.ex like this:

Conf({}).get('')
-> RuntimeError: maximum recursion depth exceeded while calling a Python object

Why it seems like the methods on this external member are being overridden, while all I try to do is to keep data out of the API. On the other hand, the following works just fine.

class Config(object):
    def __init__(self, d):
        self.data = d

    def __getitem__(self, attr):
        return self.data[attr]

    def get(self, attr, default=None):
        return self.data.get(attr, default)

Upvotes: 3

Views: 816

Answers (1)

falsetru
falsetru

Reputation: 369294

namedtuple define data as a kind of property.

You can confirm that if you define the namedtuple with verbose=True argument:

>>> import collections
>>> collections.namedtuple('Conf', 'data', verbose=True)
class Conf(tuple):
    ...
    data = _property(_itemgetter(0), doc='Alias for field number 0')  # <---

Accessing the data will cause __getitem__ to be called; which in turn access data again; cause __getitem__, ....; causing the infinite recursion.


You need to avoid accessing the data inside the your own __getitem__ method to prevent the recursion. For example:

>>> import collections
>>>
>>> class Conf(collections.namedtuple('Conf', 'data')):
...     def __getitem__(self, attr):
...         return super(Conf, self).__getitem__(0)[attr]
...
>>> Conf({'x': 'y'})['x']
'y'

Upvotes: 3

Related Questions