Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create child of str (or int or float or tuple) 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?
like image 400
user Avatar asked Mar 12 '23 15:03

user


1 Answers

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.

like image 92
bgporter Avatar answered Apr 06 '23 21:04

bgporter