2

I want to create a class that if inherited with any other sibling class will set a 'origin' attribute on the instance. The other sibling class may be mutable or immutable.

I've got it partially working.

class MyOrigin(object):
    def __new__(cls, *args, **kwargs):
        origin = kwargs.get('origin')
        if 'origin' in kwargs:
            del kwargs['origin']
        obj = super(MyOrigin, cls).__new__(cls, *args, **kwargs)
        obj.origin = origin
        return obj

    def __init__(self, *args, **kwargs):
        origin = kwargs.get('origin')
        if 'origin' in kwargs:
            del kwargs['origin']
        super(MyOrigin, self).__init__(*args, **kwargs)
        self.origin = origin

class MyListWithOrigin(MyOrigin, type(list())):
    pass
    # This works correctly

class MyDictWithOrigin(MyOrigin, type(dict())):
    pass
    # This works correctly too

class MyStringWithOrigin(MyOrigin, str):
    pass
    # This doesnt work if MyOrigin defines __init__

Basically, if I define __init__ on MyOrigin, then the super(MyOrigin, self).__init__ tries to call object.__init__ (as str is immutable, so there's no str.__init__) with the first parameter which fails with a TypeError as object.__init__ doesn't take arguments.

For now, I've created two classes (MyOriginMutable and MyOriginImmutable) and I'm selecting from them when creating MyStrWithOrigin or MyListWithOrigin, etc. Is there some way to detect which class super() will get the method from before running it, so that I can detect and not call object.__init__ with args.


For clarity, this example works, but is there a way to do it without having two separate Mutable and Immutable classes?

class MyOriginImmutable(object):
    def __new__(cls, *args, **kwargs):
        origin = kwargs.get('origin')
        if 'origin' in kwargs:
            del kwargs['origin']
        obj = super(MyOriginImmutable, cls).__new__(cls, *args, **kwargs)
        obj.origin = origin
        return obj


class MyOriginMutable(object): # Edited so that it DOES NOT inherit from MyOriginImmutable
    def __init__(self, *args, **kwargs):
        # We define __init__ only for mutable classes
        origin = kwargs.get('origin')
        if 'origin' in kwargs:
            del kwargs['origin']
        super(MyOriginMutable, self).__init__(*args, **kwargs)
        self.origin = origin


class MyOriginString(MyOriginImmutable, str):
    """A custom string class to hold origin"""
    pass


class MyOriginList(MyOriginMutable, type(list())):
    """A custom list class to hold origin"""
    pass


class MyOriginDict(MyOriginMutable, type(dict())):
    """A custom dict class to hold origin"""
    pass

if __name__ == '__main__':
    # Testing
    try:
        line = MyOriginString('some string', origin=('somewhere',))
        print(line)
        assert line.origin == ('somewhere',)
        assert line == 'some string'
    except Exception as e:
        print("String like failed")
        # raise e

    try:
        list_like = MyOriginList(['some', 'list'], origin=('somewhere',))
        print(list_like)
        assert list_like.origin == ('somewhere',)
        assert list_like == ['some', 'list']
    except Exception as e:
        print("List like failed")
        # raise e

    try:
        dict_like = MyOriginDict({'some': 'dict'}, origin=('somewhere',))
        print(dict_like)
        assert dict_like.origin == ('somewhere',)
        assert dict_like == {'some': 'dict'}
    except Exception as e:
        print("Dict like failed")
        raise e
user80551
  • 1,134
  • 2
  • 15
  • 26
  • By calling `super(MyOriginImmutable, cls)`, are you trying to get the superclass of the *class* `MyOriginImmutable`, or of *instances* of `MyOriginImmutable`? i.e., `cls` is a `type`, and the `super()` of `type` is `object`. If you want the superclass of `MyOriginImmutable`, you can find it (in single-inheritance) using `cls.__mro__[1]`. – PaulMcG Jun 16 '17 at 13:18
  • @PaulMcGuire Technically, there wont be any direct instances of MyOriginImmutable. It will always be subclassed with some other type and there will be instances of the subclass. So I'm trying to get whatevers next in the mro of the instance of the subclass of MyOriginImmutable. – user80551 Jun 16 '17 at 13:21
  • 2
    Subclassing `str` can be difficult. It would probably be best to use composition instead of inheritance. See [this question](https://stackoverflow.com/q/7255655/1222951), and specifically [this answer](https://stackoverflow.com/a/7255971/1222951). – Aran-Fey Jun 16 '17 at 14:02

0 Answers0