Type of an object:

Steven D'Aprano steve+comp.lang.python at pearwood.info
Tue Dec 17 10:08:51 EST 2013


On Tue, 17 Dec 2013 23:35:10 +1300, Gregory Ewing wrote:

> Steven D'Aprano wrote:
>> I think I need to see an actual working demonstration, because as far
>> as I can see, type(obj) returns obj.__class__.
> 
> Nope:
> 
>  >>> class C(object):
> ...  def f(self):
> ...   return "Surprise!"
> ...  __class__ = property(f)
> ...
>  >>> c = C()
>  >>> type(c)
> <class '__main__.C'>
>  >>> c.__class__
> 'Surprise!'


Well, that is a surprise, but I don't think that is intended behaviour. I 
think that's something which only works by accident. The intention is 
that __class__ returns the instance's type, not arbitrary values. If you 
try to set it to a non-class on the instance, it fails:


py> class D(object):
...     pass
...
py> d = D()
py> d.__class__ = property(lambda self: 'Surprise!')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ must be set to a class, not 'property' object


Same when you try to set it on the class object itself:

py> D.__class__ = property(lambda self: 'Surprise!')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ must be set to a class, not 'property' object


So my guess is that the fact that your code works at all is an accident.

I can demonstrate that changing the __class__ of an instance causes 
type(obj) to return a different value, and also to dynamically change the 
behaviour of the object:


py> class Spam(object):
...     def method(self):
...             return "spam"
...
py> class Ham(object):
...     def method(self):
...             return "ham"
...
py> ham = Ham()
py> ham.method()
'ham'
py> ham.__class__ = Spam
py> ham.method()
'spam'
py> type(ham)
<class '__main__.Spam'>


So this is a case where type(obj) returns obj.__class__ rather than it's 
internal type field. That's the point I was trying to make: type(obj) may 
return obj's internal type field, but if you set obj.__class__, type(obj) 
will then return the new class, not the internal one.


-- 
Steven



More information about the Python-list mailing list