When where and how can i change the __class__ attr of an object?

Question:

I’d like to be able to do:

>>> 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
Asked By: Juanjo Conti

||

Answers:

Only classes that were defined with a class keyword could be used for __class__ attribute assignment:

>>> class C:
    pass

>>> class D:
    pass

>>> C().__class__ = D
>>>
Answered By: SilentGhost

I’ve solved it in this way:

>>> 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'>
Answered By: Juanjo Conti

Python 2 doesn’t have a unified object hierarchy (ie. not everything is derived from the object). Anything that is part of this hierarchy can be played with via __class__, but those that aren’t cannot be modified in this way (or at all, really). Python 2 calls these "types" rather than "classes", and they’re hard-coded in C. Examples of types are str, int, float, list, tuple, etc. This means that you cannot use types in the same ways as classes, for example you cannot change the class of an instance of a type, you cannot add, remove or modify methods of types, etc. The following transcript shows the difference in behaviour between types such as str (hard-coded, non-dynamic C constructs) and classes I’ve called A and B (changeable, dynamic, Python constructs):

>>> 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
Answered By: Chris Warburton

I tried this way!

>>> class C(str):
...     __class__ = str
...
>>> c = C()
>>> c.__class__
<class 'str'>
Answered By: GEEVARGHESE
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.