¿Cuándo y cómo puedo cambiar el __class__ attr de un objeto?

Me gustaría poder hacer:

>>> class a(str): ... pass ... >>> b = a() >>> b.__class__ = str Traceback (most recent call last): File "", line 1, in  TypeError: __class__ assignment: only for heap types 

Lo he resuelto de esta manera:

 >>> class C(str): ... def __getattribute__(self, name): ... if name == '__class__': ... return str ... else: ... return super(C, self).__getattribute__(name) ... >>> c = C() >>> c.__class__  

Python 2 no tiene una jerarquía de objetos unificada (es decir, no todo desciende de la clase de objeto). Todo lo que forma parte de esta jerarquía se puede jugar a través de __class__ , pero los que no lo son no se pueden modificar de esta manera (o en realidad, realmente). Estos se denominan “tipos” de Python y están codificados de forma rígida en C. Los ejemplos de tipos son str , int , float , list , tuple , etc. Esto significa que no puede usar tipos de la misma manera que las clases, por ejemplo no puede cambiar la clase de una instancia de un tipo, no puede agregar, eliminar o modificar métodos de tipos, etc. La siguiente transcripción muestra la diferencia en el comportamiento entre los tipos como str (construcciones C no codificadas, no dinámicas) y clases que he llamado A y B (construcciones Python modificables, dinámicas):

 >>> str  >>> class A: ... pass ... >>> a = A() >>> A  >>> a <__main__.A instance at 0xb747e74c> >>> type(a)  >>> type(A)  >>> type(str)  >>> type(type(a))  >>> type(type(A))  >>> A.foo = lambda self,x: x >>> a.foo(10) 10 >>> A().foo(5) 5 >>> str.foo = lambda self,x: x Traceback (most recent call last): File "", line 1, in  TypeError: can't set attributes of built-in/extension type 'str' >>> 'abc'.foo(5) Traceback (most recent call last): File "", line 1, in  AttributeError: 'str' object has no attribute 'foo' >>> class B: ... pass ... >>> a.__class__  >>> a.__class__ = B >>> a <__main__.B instance at 0xb747e74c> >>> 'abc'.__class__  >>> 'abc'.__class__ = B Traceback (most recent call last): File "", line 1, in  TypeError: __class__ must be set to new-style class, not 'classobj' object >>> class B(object): ... pass ... >>> 'abc'.__class__ = B Traceback (most recent call last): File "", line 1, in  TypeError: __class__ assignment: only for heap types 

Solo las clases que se definieron con una palabra clave de class podrían usarse para la asignación del atributo __class__ :

 >>> class C: pass >>> class D: pass >>> C().__class__ = D >>> 

¡Lo intenté de esta manera!

 >>> class C(str): ... __class__ = str ... >>> c = C() >>> c.__class__