изменение класса объекта 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