改变Python对象的类(类型转换)

34 投票
4 回答
39650 浏览
提问于 2025-04-17 19:03

在这个 Python文档页面 上,它提到:

一个对象的身份和类型都是不能改变的。

然后我试了这个脚本:

#!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

我以为我改变了 f2type
我哪里出错了?我漏掉了什么?

4 个回答

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 中使用了。

19

什么时候以及如何做这个

改变对象的类型(我们称之为“类型转换”)是有意义的,特别是当你想要给一个你无法修改的对象增加一些功能时。

假设有一句代码 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 的版本时。

21

页面上的脚注提到:

[1] 在某些特定的情况下,可以改变一个对象的类型。不过,这通常不是个好主意,因为如果处理不当,可能会导致一些非常奇怪的行为。

如果你尝试把 f2 的 __class__ 改成 list

f2.__class__ = list

会出现一个类型错误:

TypeError: __class__ assignment: only for heap types

撰写回答