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