改变Python对象的类(类型转换)
在这个 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
我以为我改变了 f2
的 type
。
我哪里出错了?我漏掉了什么?
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