更改python对象的类(强制转换)

时间:2013-03-14 08:21:52

标签: python python-3.x

python doc page上,它说:

  

与其身份一样,对象的类型也是不可更改的。

我试试这个剧本,

#!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的{​​{1}} 怎么了,我错过了什么?

4 个答案:

答案 0 :(得分:14)

页面上的脚注:

  

[1]在某些情况下,可以更改对象的类型   某些受控条件。但这通常不是一个好主意,   因为如果处理它会导致一些非常奇怪的行为   不正确。

如果您尝试将f2的__class__更改为list

f2.__class__ = list

引发了一个TypeError:

TypeError: __class__ assignment: only for heap types

答案 1 :(得分:4)

何时以及如何执行此操作

更改类型(&#34;强制转换&#34;)是有意义的,如果您想要添加功能到由您无法更改的某些代码创建的对象。

假设某些语句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版本可以持久存储并从文件中检索响应时,我就做了类似的事情。

答案 2 :(得分:1)

今天有人问我这个问题。他有一个父类,希望在初始时根据输入自动提升自己成为其中一个孩子。以下脚本用作概念证明:

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

答案 3 :(得分:0)

古老的问题,但这是一种安全地扩展python对象类型的技术。

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