如何在多重继承中使用namedtuples [英] How to use namedtuples in multiple inheritance

查看:144
本文介绍了如何在多重继承中使用namedtuples的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以创建一个继承自 namedtuple ,或创建具有相同效果的东西(具有组合基本类型字段的不可变类型)?我还没有找到办法。

Is it possible to create a class that inherits from multiple instances of namedtuple, or create something to the same effect (having an immutable type that combines the fields of the base types)? I haven't found a way to do so.

此示例说明了问题:

>>> class Test(namedtuple('One', 'foo'), namedtuple('Two', 'bar')):
>>>    pass

>>> t = Test(1, 2)
TypeError: __new__() takes 2 positional arguments but 3 were given

>>> t = Test(1)
>>> t.foo
1
>>> t.bar
1

问题似乎是 namedtuple 不使用 super 初始化其基类,如创建一个基类时所见:

The problem seems to be that namedtuple does not use super to initialize its base class, as can be seen when creating one:

>>> namedtuple('Test', ('field'), verbose=True)
[...]    
class Test(tuple):
[...]
    def __new__(_cls, field,):
        'Create new instance of Test(field,)'
        return _tuple.__new__(_cls, (field,))

即使我考虑编写我自己的 namedtuple 版本来修复此问题,也不明白如何去做。如果在类的MRO中有多个 namedtuple 的实例,则它们必须共享基类的单个实例元组。要做到这一点,他们必须协调哪个 namedtuple 使用基本元组中的哪个索引范围。

Even if I considered writing my own version of namedtuple to fix this, it is not obvious how to do that. If there are multiple instances of namedtuple in the MRO of a class they'd have to share a single instance of the base class tuple. To do that, they'd have to coordinate on which namedtuple uses which range of indices in the base tuple.

使用 namedtuple 或类似的东西,有没有更简单的方法来实现多重继承?有人已经在某处实现了吗?

Is there any simpler way to achieve multiple inheritance with a namedtuple or something similar? Has anyone already implemented that somewhere?

推荐答案

您可以使用装饰器或元类将父命名的元组字段组合成新的命名元组并将其添加到类 __ bases __

You could use a decorator or metaclass to combined the parent named tuple fields into a new named tuple and add it to the class __bases__:

from collections import namedtuple

def merge_fields(cls):
    name = cls.__name__
    bases = cls.__bases__

    fields = []
    for c in bases:
        if not hasattr(c, '_fields'):
            continue
        fields.extend(f for f in c._fields if f not in fields)

    if len(fields) == 0:
        return cls

    combined_tuple = namedtuple('%sCombinedNamedTuple' % name, fields)
    return type(name, (combined_tuple,) + bases, dict(cls.__dict__))


class SomeParent(namedtuple('Two', 'bar')):

    def some_parent_meth(self):
        return 'method from SomeParent'


class SomeOtherParent(object):

    def __init__(self, *args, **kw):
        print 'called from SomeOtherParent.__init__ with', args, kw

    def some_other_parent_meth(self):
        return 'method from SomeOtherParent'


@merge_fields
class Test(namedtuple('One', 'foo'), SomeParent, SomeOtherParent):

    def some_method(self):
        return 'do something with %s' % (self,)


print Test.__bases__
# (
#   <class '__main__.TestCombinedNamedTuple'>, <class '__main__.One'>, 
#   <class '__main__.SomeParent'>, <class '__main__.SomeOtherParent'>
# )
t = Test(1, 2)  # called from SomeOtherParent.__init__ with (1, 2) {} 
print t  # Test(foo=1, bar=2)
print t.some_method()  # do something with Test(foo=1, bar=2)
print t.some_parent_meth()  # method from SomeParent
print t.some_other_parent_meth()  # method from SomeOtherParent

这篇关于如何在多重继承中使用namedtuples的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆