On this python doc page it says:
Like its identity, an object’s type is also unchangeable.
And I try this script,
<
I was asked this question by a colleague today. He had a parent class that wanted to promote itself automatically to be one of its children based on an input at init time. The following script worked as a proof of concept:
class ClassB(object):
def __init__(self):
self.__class__ = ClassA
def blah2(self,t):
print('I give you',t)
return 'You are welcome'
class ClassA(ClassB):
def blah(self, t):
print('you gave me',t)
return 'Thankyou'
a = ClassB()
print(type(a))
print(a.blah('sausage'))
print(a.blah2('cabbage'))
The result shows:
<class '__main__.ClassA'>
you gave me sausage
Thankyou
I give you cabbage
You are welcome
Which shows that both the parent and child functions are now available to A
.
Old question but here's a technique for safely extending the type of a python object.
def extendObject(obj):
# Our extended type is explicitly derived from our existing type.
class Extended(obj.__class__):
# Whatever extensions you want to make.
def someMethod(self):
pass
# Change the type of the object.
obj.__class__ = Extended
return obj
The footnotes one that page says:
[1] It is possible in some cases to change an object’s type, under certain controlled conditions. It generally isn’t a good idea though, since it can lead to some very strange behaviour if it is handled incorrectly.
If you try to change the __class__
of f2 to list
:
f2.__class__ = list
A TypeError raised:
TypeError: __class__ assignment: only for heap types
Changing the type ("casting") makes sense if you want to add functionality to an object created by some code you cannot change.
Assume some statement obj = some_call_to_a_library()
gives you an object of class A
. You want it to have additional functionality, say, mymethod()
.
Then you could introduce a subclass MyA
like this (Python 3 style):
class MyA(A):
@classmethod
def cast(cls, some_a: A):
"""Cast an A into a MyA."""
assert isinstance(some_a, A)
some_a.__class__ = cls # now mymethod() is available
assert isinstance(some_a, MyA)
return some_a
def mymethod(self):
...
and then write obj = MyA.cast(some_call_to_a_library())
.
If MyA
relies on additional attributes, cast
(which is a factory method) should create them.
I just did something like this when I needed a version of requests.Response
that could persist and retrieve responses to/from a file.