Reputation: 17537
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
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