изменение класса объекта Python (приведение)
На этой странице python doc говорится:
Как и его идентификатор, тип объектов также неизменен.
И я пробую этот script,
#!python3
class Foo:
num = 1
pass
class Bar:
num = 2
pass
f1,f2= Foo(), Foo()
f2.__class__ = Bar
print( type(f1), type(f2), f1.num, f2.num )
Результат:
<class '__main__.Foo'> <class '__main__.Bar'> 1 2
Я думаю, что я изменил type
of f2
.
Что случилось, Что мне не хватает?
Ответы
Ответ 1
Сноски, которые написаны на этой странице:
[1] В некоторых случаях можно изменить тип объектов, определенных контролируемых условиях. Это вообще не хорошая идея, хотя, поскольку это может привести к некоторому очень странному поведению, если оно обрабатывается неправильно.
Если вы попытаетесь изменить __class__
на f2 на list
:
f2.__class__ = list
A TypeError повышен:
TypeError: __class__ assignment: only for heap types
Ответ 2
Когда и как это сделать
Изменение типа ("приведение") имеет смысл, если вы хотите добавить функциональность к объекту, созданному каким-либо кодом, который вы не можете изменить.
Предположим, что некоторый оператор obj = some_call_to_a_library()
дает вам объект класса A
Вы хотите, чтобы он имел дополнительную функциональность, скажем, mymethod()
. Тогда вы могли бы представить подкласс MyA
следующим образом (стиль Python 3):
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):
...
и затем напишите obj = MyA.cast(some_call_to_a_library())
. Если MyA
полагается на дополнительные атрибуты, cast
(которое является фабричным методом) должно создать их.
Я просто сделал что-то подобное, когда мне понадобилась версия requests.Response
Ответ, который мог сохраниться и получить ответы в/из файла.
Ответ 3
Мне сегодня этот вопрос задал коллега. У него был родительский класс, который хотел продвигать себя автоматически, чтобы стать одним из его детей, основываясь на вводе во время инициализации. Следующий скрипт работал как подтверждение концепции:
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'))
Результат показывает:
<class '__main__.ClassA'>
you gave me sausage
Thankyou
I give you cabbage
You are welcome
Что показывает, что родительская и дочерняя функции теперь доступны для A