Search code examples
pythonclassinheritancetupleskeyword-argument

Inheriting a tuple class cannot take **kwargs in Python


I'm trying to inherit a hashable iterable such as a tuple. I want to also have metadata in the form of **kwargs but I'm getting a TypeError

Before I add **metadata:

class Collection(tuple):
    def __init__(self, pair):#, **metadata):
#         self.metadata = metadata
        self.pair = tuple(pair)
pair_1 = Collection(["Darth Plagueis", "Darth Sidious"])
pair_1   
# ('Darth Plagueis', 'Darth Sidious')

After I add **metadata:

class Collection(tuple):
    def __init__(self, pair, **metadata):
        self.metadata = metadata
        self.pair = tuple(pair)
pair_1 = Collection(["Darth Plagueis", "Darth Sidious"], affiliation="Sith")
# ---------------------------------------------------------------------------
# TypeError                                 Traceback (most recent call last)
# <ipython-input-119-f40b020d268d> in <module>
#      11         self.metadata = metadata
#      12         self.pair = tuple(pair)
# ---> 13 pair_1 = Collection(["Darth Plagueis", "Darth Sidious"], affiliation="Sith")
#      14 pair_1
#      15 # ('Darth Plagueis', 'Darth Sidious')

# TypeError: tuple() takes at most 1 argument (2 given)
# ​

Solution

  • To override tuple class you need to place the super initialization in __new__ method.

    class Collection(tuple):
        def __new__(self, pair, **metadata):
            return super(Collection, self).__new__(self,tuple(pair))
        def __init__(self, pair, **metadata):
            self.metadata = metadata
            self.pair = tuple(pair)
    
    >>> pair_1 = Collection(["Darth Plagueis", "Darth Sidious"], affiliation="Sith")
    >>> pair_1.pair
    ('Darth Plagueis', 'Darth Sidious')
    >>> pair_1.metadata
    {'affiliation': 'Sith'}