87

I'm wondering if there is a difference between

class Test(object):
    def __init__(self):
        print self.__class__.__name__

and

class Test(object):
    def __init__(self):
        print type(self).__name__

?

Is there a reason to prefer one or the other?

(In my use case I want to use it to determine the logger name, but I guess this doesn't matter)

Martin Schulze
  • 2,091
  • 2
  • 22
  • 27
  • @user and there is a difference between them in Python 3 under certain circumstances (see Flavien's [answer](http://stackoverflow.com/a/10633356/704244)) – bartolo-otrit Jan 23 '17 at 16:56

2 Answers2

52
>>> class Test(object): pass
>>> t = Test()
>>> type(t) is t.__class__
True
>>> type(t)
__main__.Test

So those two are the same. I would use self.__class__ since it's more obvious what it is.

However, type(t) won't work for old-style classes since the type of an instance of an old-style class is instance while the type of a new-style class instance is its class:

>>> class Test(): pass
>>> t = Test()
>>> type(t) is t.__class__
False
>>> type(t)
instance
ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • 25
    Really? You'd access `self.__class__` over `type(self)`? I think the latter is clearer, less typing, and more consistent - I doubt you'd do `[1, 2, 3].__len__()` over `len([1, 2, 3])`. – Gareth Latty Apr 30 '12 at 15:29
  • 21
    Well `len()` tells you what it does - but `type(self)` doesn't immediately tell you "gives you the class" – ThiefMaster Apr 30 '12 at 15:32
  • 10
    Past early versions of Python, Type and Class are synonymous in Python, so I guess I don't really see it like that. – Gareth Latty Apr 30 '12 at 15:35
  • 5
    Technically every class is a type, but not every type is a class. A "class" is a type that implements the typical behavior (whatever the author of the language thinks that is) of a class, ie that functions on this class get a reference to the calling instance (the `self` parameter) and can be instantiated by calling the type. Python already has two class-like types, `types.ClassType` aka `classobj` aka old-style-class and `type` aka new-style-class. You can however write a new type that does not behave like a class. – Jochen Ritzel Apr 30 '12 at 16:29
  • I wasn't aware of the different behavior for old style classes. I guess this seals the deal (favoring __class__) for me. Thank You – Martin Schulze Apr 30 '12 at 16:58
  • Note that old-style classes stopped existing in Python 3, and were deprecated long before that. In 2012 maybe it was good to prefer `.__class__` (although supporting old-style classes probably entailed more logic and care, and if you are actually consciously supporting both you should make your code explicitly express that, such as by _first_ checking if `type(foo)` equals `` and then falling back to `class` in that case). – mtraceur Nov 10 '21 at 04:16
  • 1
    Note also that the `__class__` attribute on a class can be overwritten (just by setting it) or middle-manned (by defining a `__getattribute__` method), while `type(foo)` cannot. So if you think there is a good reason for objects to be able to lie to you about what class they are, like you think typeness should be overloadable much like equality can be, then prefer `.__class__`, otherwise prefer `type`. – mtraceur Nov 10 '21 at 04:19
  • Correction/clarification on my last comment: `type(foo)` *is* overwritten by setting `foo.__class__` to another class, but it is *not* middlemanned by `__getattribute__` nor by defining a `@property` named `__class__`. – mtraceur Dec 03 '22 at 18:29
8

As far as I am aware, the latter is just a nicer way of doing the former.

It's actually not that unusual in Python, consider repr(x), which just calls x.__repr__() or len(x), which just calls x.__len__(). Python prefers to use built-ins for common functions that you are likely to use over a range of classes, and generally implements these by calling __x__() methods.

Gareth Latty
  • 86,389
  • 17
  • 178
  • 183