How to use namedtuples in multiple inheritance

前端 未结 3 1252
花落未央
花落未央 2020-12-20 02:17

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 fiel

相关标签:
3条回答
  • 2020-12-20 02:59

    Well, if you just want a namedtuple with both the fields, it's easy to just recreate it:

    One = namedtuple('One', 'foo')
    Two = namedtuple('Two', 'bar')
    Test = namedtuple('Test', One._fields+Two._fields)
    
    0 讨论(0)
  • 2020-12-20 03:08

    This code adopts a similar approach to Francis Colas', although it's somewhat longer :)

    It's a factory function that takes any number of parent namedtuples, and creates a new namedtuple that has all the fields in the parents, in order, skipping any duplicate field names.

    from collections import namedtuple
    
    def combined_namedtuple(typename, *parents):
        #Gather fields, in order, from parents, skipping dupes
        fields = []
        for t in parents:
            for f in t._fields:
                if f not in fields:
                    fields.append(f)
        return namedtuple(typename, fields)
    
    nt1 = namedtuple('One', ['foo', 'qux'])
    nt2 = namedtuple('Two', ['bar', 'baz'])    
    
    Combo = combined_namedtuple('Combo', nt1, nt2)    
    ct = Combo(1, 2, 3, 4)
    print ct
    

    output

    Combo(foo=1, qux=2, bar=3, baz=4)
    
    0 讨论(0)
  • 2020-12-20 03:14

    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
    
    0 讨论(0)
提交回复
热议问题