Cuando dónde y cómo se puede cambiar la attr __class__ de un objeto?
-
26-09-2019 - |
Pregunta
Me gustaría ser capaz de hacer:
>>> class a(str):
... pass
...
>>> b = a()
>>> b.__class__ = str
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types
Solución
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__
<type 'str'>
Otros consejos
Python 2 no tiene una jerarquía de objetos unificado (es decir. No todo es descendiente de la clase de objeto). Cualquier cosa que es parte de esta jerarquía se puede jugar con vía __class__
, pero los que no lo son no se puede modificar de esta manera (o en absoluto, en realidad). Estos se llaman "tipos" de Python, y son no modificable en C. Ejemplos de tipos son str
, int
, float
, list
, tuple
, etc. Esto significa que no se puede utilizar tipos de la misma manera como las clases, por ejemplo, no se puede cambiar la clase de una instancia de un tipo, no se puede añadir, eliminar o modificar los métodos de los tipos, etc. los siguientes transcripción muestra la diferencia de comportamiento entre los tipos tales como str
(no modificable, construcciones C no dinámicos) y clases que he llamado A y B (cambiante, dinámico, construcciones de Python):
>>> str
<type 'str'>
>>> class A:
... pass
...
>>> a = A()
>>> A
<class __main__.A at 0xb747f2cc>
>>> a
<__main__.A instance at 0xb747e74c>
>>> type(a)
<type 'instance'>
>>> type(A)
<type 'classobj'>
>>> type(str)
<type 'type'>
>>> type(type(a))
<type 'type'>
>>> type(type(A))
<type 'type'>
>>> 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 "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
>>> 'abc'.foo(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'foo'
>>> class B:
... pass
...
>>> a.__class__
<class __main__.A at 0xb747f2cc>
>>> a.__class__ = B
>>> a
<__main__.B instance at 0xb747e74c>
>>> 'abc'.__class__
<type 'str'>
>>> 'abc'.__class__ = B
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
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 "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types
Sólo las clases que se definieron con una palabra clave class
podrían ser utilizados para la asignación de atributos __class__
:
>>> class C:
pass
>>> class D:
pass
>>> C().__class__ = D
>>>
Me trató de esta manera!
>>> class C(str):
... __class__ = str
...
>>> c = C()
>>> c.__class__
<class 'str'>