为什么在这种情况下从namedtuple继承会导致无限递归?

3

我计划编写一个小类来托管一些内容和相关的辅助方法。虽然在这种情况下从namedtuple继承并没有太大意义,但我出于习惯而这样做。

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)

然而,当我正确地调用 .get() 时,这会触发对于 __getitem__ 的无限递归,导致其反复调用自身!例如这样:

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

为什么看起来外部成员的方法被重写了,而我所做的只是将data保持在API之外。另一方面,以下内容运作正常。

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)

为什么你不继承dict类呢?像这样写class Config(dict): pass,就可以实现你所需的所有功能了。 - Dan D.
@DanD 不喜欢继承可变的东西。 - mike3996
你难道不应该初始化父类吗? - bosnjak
1个回答

3

namedtupledata 定义为一种属性。

如果使用 verbose=True 参数定义 namedtuple,您可以确认这一点:

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

访问data会调用__getitem__,然后再次访问data,导致__getitem__被调用……从而导致无限递归。
为了避免递归,你需要避免在自己的__getitem__方法中访问data。例如:
>>> import collections
>>>
>>> class Conf(collections.namedtuple('Conf', 'data')):
...     def __getitem__(self, attr):
...         return super(Conf, self).__getitem__(0)[attr]
...
>>> Conf({'x': 'y'})['x']
'y'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接