In Python 3, types are classes (as far as repr()
is concerned)
In yesterday's entry, I put in a little
aside, saying 'the distinction between what is considered a 'type'
and what is considered a 'class' by repr()
is somewhat arbitrary'.
It turns out that this is not true in Python 3, which exposes an
interesting difference between Python 2 and Python 3 and a bit of
old Python 1 and Python 2 history too.
(So the sidebar in this old entry of mine is not applicable to Python 3.)
To start with, let's show the situation in Python 2:
>>> class A: ... pass >>> class B(object): ... pass >>> repr(A) '<class __main__.A at 0x7fd804cacf30>' >>> repr(B) "<class '__main__.B'>" >>> repr(type) "<type 'type'>"
Old style and new style classes in Python 2 are reported slightly
differently, but they are both 'class', while type
(or any other
built in type such as int
) are 'type'. This distinction is made
at a quite low level, as described in the sidebar in my old entry.
However, in Python 3 things have changed and repr()
's output is
uniform:
>>> class B(object): ... pass >>> repr(B) "<class '__main__.B'>" >>> repr(type) "<class 'type'>"
Both Python classes and built-in types are 'class'. This change was specifically introduced in Python 3, as issue 2565 (the change appeared in 3.0a5). The issue's discussion has a hint as to what was going on here.
To simplify a bit, in Python 1.x, there was no unification between
classes and built in types. As part of this difference, their
repr()
results were different in the way you'd expect; one said
'class' and the other said 'type'. When Python 2.0 came along, it
unified types with new style classes. The initial implementation
of this unification caused repr()
to report new style classes as
types. However, at some point relatively early in 2.x development,
this code was changed to report new style classes as 'class ...'
instead. What was reported for built in types was left unchanged
for backwards compatibility with the Python 1.x output of repr()
.
In the run up to Python 3, this backwards compatibility was removed
and now all built in types (or if you prefer, classes) are reported
as classes.
(I was going to say something about what type()
reports, but then
I actually thought about it. In reality type()
doesn't report any
sort of string; type()
returns an object, and if you're just
running that in an interactive session the interpreter prints it
using str()
, which for classes is normally the same as repr()
.
The reason to use 'repr(B)
' instead of 'type(B)
' in my interactive
example is that 'type(B)
' is type
.)
Sidebar: The actual commit message for the 2001 era change
issue 2565 doesn't quote the full commit message, and it turns out that the omitted bit is interesting (especially since it's a change made by Guido van Rossum):
Change repr() of a new-style class to say <class 'ClassName'> rather than <type 'ClassName'>. Exception: if it's a built-in type or an extension type, continue to call it <type 'ClassName>. Call me a wimp, but I don't want to break more user code than necessary.
As far as I can tell from reading old Python changelogs, this change appeared in Python 2.2a4. In a way, this is surprisingly late in Python 2.x development. The 'what's new' snippet about the change reiterates that not changing the output for built in types is for backward compatibility:
The repr() of new-style classes has changed; instead of <type 'M.Foo'> a new-style class is now rendered as <class 'M.Foo'>, except for built-in types, which are still rendered as <type 'Foo'> (to avoid upsetting existing code that might parse or otherwise rely on repr() of certain type objects).
Of course, at that point it was also for compatibility with people relying on what repr() of built in types reported in 2.0 and 2.1.
|
|