Fermi paradox Fermi paradox - 4 months ago 8
Python Question

Create child of str that accepts kwargs

I need a class that behaves like a string but also takes additional

kwargs
. Therefor I subclass
str
:

class Child(str):

def __init__(self, x, **kwargs):
# some code ...
pass


inst = Child('a', y=2)
print(inst)


This however raises:

Traceback (most recent call last):
File "/home/user1/Project/exp1.py", line 8, in <module>
inst = Child('a', y=2)
TypeError: 'y' is an invalid keyword argument for this function


Which is rather strange, since the code below works without any error:

class Child(object):

def __init__(self, x, **kwargs):
# some code ...
pass


inst = Child('a', y=2)





Questions:


  • Why do I get different behavior when trying to subclass
    str
    ,
    int
    ,
    float
    ,
    tuple
    etc compared to other classes like
    object
    ,
    list
    ,
    dict
    etc?

  • How can I create a class that behaves like a string but has
    additional kwargs?


Answer

You need to override __new__ in this case, not __init__:

>>> class Child(str):
...    def __new__(cls, s, **kwargs):
...       inst = str.__new__(cls, s)
...       inst.__dict__.update(kwargs)
...       return inst
...
>>> c = Child("foo")
>>> c.upper()
'FOO'
>>> c = Child("foo", y="banana")
>>> c.upper()
'FOO'
>>> c.y
'banana'
>>>

See here for the answer to why overriding __init__ doesn't work when subclassing immutable types like str, int, and float:

__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.

Comments