default repr?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sun Jul 22 21:40:26 EDT 2012


On Mon, 23 Jul 2012 10:29:33 +1000, Chris Angelico wrote:

> On Mon, Jul 23, 2012 at 10:24 AM, Steven D'Aprano
> <steve+comp.lang.python at pearwood.info> wrote:
>>> Methods are just functions, and you can call any method of any class
>>> with any object as its first parameter.
>>
>> Not quite: they have to be an instance of that class.
>>
>>> Though this mightn't work with everything. I wasn't able to paint a
>>> list as a tuple - "tuple.__repr__([1,2,3])" threw a TypeError. Oh
>>> well. There's a limit to the ways Python lets you shoot yourself in
>>> the foot.
>>
>> Of course -- [1,2,3] is not a tuple, so how would tuple know what to do
>> with it?
> 
> Hmm. I would have thought that methods were like all other functions:
> they take their arguments and do code with them. Duck typing and all. I
> stand corrected, then.
> 
> In any case, it works fine for methods of object, at least with Python 3
> and with new-style classes in Py2.

Naturally. In Python 3, and for new-style classes in 2, any instance is 
an instance of object. As the base class of everything, object has a 
generic repr that can handle everything.

But subclasses are entitled to be more picky. What would you expect 
int.__repr__ do with a tuple for an argument? Raise an error, of course, 
and a TypeError at that. Which it does, in both 2 and 3:

py> int.__repr__( (1, 2) )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor '__repr__' requires a 'int' object but received a 
'tuple'


In general, you should assume that an arbitrary method will insist on its 
"self" argument actually being a valid instance of its class. There may 
be occasions where that is not the case, but don't count on it. I expect 
that this is under-specified behaviour: whether it works or not is 
implementation-specific, and so may change from compiler to compiler, or 
version to version.

The mechanism behind method look-up is slightly complex, and changed 
significantly in Python 3. In Python 2, *both* these lookups:

myclass.mymethod
myinstance.mymethod

return a *method object* -- the first case returns an "unbound method", 
which needs self to be provided when it is called, and the second returns 
a "bound method", which already knows what value of self to use 
(myinstance). In CPython, they are the same type with slightly different 
reprs, but that's an implementation detail.

In either case, the method type enforces the rule that self is an 
instance of the type.

In Python 3, the rule is slightly different. As before, *bound* methods 
(those that already have self supplied) are still returned when you look-
up on an instance:

myinstance.mymethod  # returns a bound method object

but unbound methods are no longer returned. (I presume you could still 
create one, by hand, but haven't tried.) Instead, looking up on the class 
returns the raw function object without the method wrapper, and that does 
no type-checking on self unless the developer put one in.

Which built-in methods have got.


> (Other than backward compatibility with old code, is there any reason to
> use an old-style class?)

Old-style classes have subtle differences in behaviour, and in principle 
at least are slightly faster. (At least they were back in Python 2.2.)

Some differences include:

1) descriptor protocol does not work, including properties
2) super does not work
3) no __getattribute__
4) magic dunder methods such as __add__ do not bypass the instance
5) automatic delegation is trivial


So if you *require* such differences, then they would be good reasons for 
using classic classes. But frankly, as far as I can tell only #4 and #5 
are positive differences, the others are reasons to avoid classic classes.


-- 
Steven



More information about the Python-list mailing list