Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python multiple inheritance of __new__ and __init__ with a string and second class

I'm trying to create a derived class that inherits from both a str type and a second class. It's problematic since the str type doesn't simply call __init__, but the __new__ method due to its immutability. I know that for __init__ and super to work well, you need to have the same calling structure all the way down. However the following implementation fails:

class base(object):
    def __new__(cls, *args, **kwargs):
        print "NEW  BASE:", cls, args, kwargs
        return super(base, cls).__new__(cls, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        print "INIT BASE", args, kwargs

class foo(base, str):
    def __new__(cls, *args, **kwargs):
        return super(foo, cls).__new__(cls, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        super(foo, self).__init__(*args, **kwargs)

Here foo('cat') works with:

>> NEW  BASE: <class '__main__.foo'> ('cat',) {}
>> INIT BASE ('cat',) {}

but with an argument foo('cat', x=3), it fails:

>> NEW  BASE: <class '__main__.foo'> ('cat',) {'x': 3}
Traceback (most recent call last):
  File "inh.py", line 19, in <module>
    foo('cat', x=3)
  File "inh.py", line 12, in __new__
    return super(foo, cls).__new__(cls, *args, **kwargs)
  File "inh.py", line 4, in __new__
    return super(base, cls).__new__(cls, *args, **kwargs)
TypeError: str() takes at most 1 argument (2 given)

I can get this to work by changing the base.__new__ method to:

def __new__(cls, *args, **kwargs):
    return super(base, cls).__new__(cls)

but now I've changed the calling structure, which I feel will cause me problems later down the line.

How do I properly inherit from a string and a second class?

like image 871
Hooked Avatar asked May 30 '13 18:05

Hooked


People also ask

Can you inherit 2 classes in Python?

In Python a class can inherit from more than one class. If a class inherits, it has the methods and variables from the parent classes. In essence, it's called multiple inheritance because a class can inherit from multiple classes. This is a concept from object orientated programming.

Is it true that if a class inherits from multiple classes the order of inheritance does not matter in Python?

Yes, you can do multiple inheritance. please note the order of class in ExampleSimMod matters. The's a great article about this.

Does Python class support multiple inheritance?

Yes, Python supports multiple inheritance. Like C++, a class can be derived from more than one base classes in Python.

How do you inherit a class from another class in Python?

Use the super() Function By using the super() function, you do not have to use the name of the parent element, it will automatically inherit the methods and properties from its parent.


1 Answers

You can't just do

def __new__(cls, *args, **kwargs):
    return super(base, cls).__new__(cls)

because this will cause incorrect call for new of str (you will not pass allowed argument

>>> foo('t')
NEW  BASE: <class '__main__.foo'> ('t',) {}
INIT BASE ('t',) {}
''

You should do something like

def __new__(cls, *args, **kwargs):
    return super(base, cls).__new__(cls, *args[:1])

But this can broken something if You will use base class as mixin for class which __new__ method accept more than one argument.

as a option maybe You should have class inherited from str but with overridden new method:

class CarelessStr(str):
    def __new__(cls, *args, **kwargs):
        return super(CarelessStr, cls).__new__(cls, *args[:1])

class foo(base, CarelessStr):
    def __new__(cls, *args, **kwargs):
        return super(foo, cls).__new__(cls, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        super(foo, self).__init__(*args, **kwargs)
like image 138
oleg Avatar answered Sep 21 '22 19:09

oleg