Why inheriting from namedtuple results in infinite recursion in this case?
Question: 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)
    


Answer: `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'
    

