[Python-Dev] Semantics of __int__(), __index__()

Terry Jan Reedy tjreedy at udel.edu
Fri Apr 5 19:34:10 CEST 2013

On 4/4/2013 10:04 PM, Steven D'Aprano wrote:

> When I call int(), I'm expecting an int.

We agree so far...,

 > That includes well-behaved subclasses of int that continue to behave
 > like ints in all the ways that matter.

but not here. I currently expect an actual int instance for 3 reasons.

1. As I read the doc, that is the currently documented 'should'.

2. I believe class constructors should, generally, return an instance of 
the class, in the narrow sense, and that factory functions should, 
generally, be used to return instances of multiple classes. The multiple 
classes would typically, or at least often, all be subclasses of some 

3. Most apropos to your next paragraph: *because* Python is duck-typed, 
I would not replace a function arg that might be an int subclass with 
int(arg) unless (I thought) the difference would make a difference.

Lets consider cases:

1. int(non-scalar-number): this is usually an error, except for bytes or 
unicode strings that represents a number in standard base-[2-32] 
notation. int has builtin knowledge of these two builtin classes. One 
can add an __int__ method to string subclasses that represent integers 
with non-standard notation.

A common use is int(input(prompt)) or int(other-external-input).

2. int(rational): for floats, Fractions, and Decimals, this returns the 
integral part, truncating toward 0. Decimal and float have __int__ 
methods. Fractions, to my surprise, does not, so int must use __floor__ 
or __round__ as a backup.

I believe we have no disagreement that int() should return an int for 
these cases. Here is a possible use for input checking.

def fib(n):
   "return fibonnaci(integral input); return type == input type"
   if int(n) != n or n < 0:
      raise TypeError('fib input must be a count')
   # let int() or < exception propagate
   # the input check is needed to prevent infinite looping
   <calculate with input n>
   return fib-of-n

Because of duck-typing, there is no need to replace n with int(n). The 
return type will be the input type.

3. int(int-subclass-instance): If the int subclass instances behave like 
an int in all ways that matter in the context, there is no reason to 
specifically do. In other words, this use should be very rare, such as 
wanting the int repr. I am also not sure, without checking the doc for 
the definition of the bit operations, if all int subclasses would 
dependably substitute in bit manipulations. So unless you can give a 
good reason otherwise, I think the subclass .__int__ class should assume 
that the programmer might actually specifically want an int instance.

In the example above, int() is part of a general case 2 input check that 
non-negative subclass instances should pass whether they return 
themselves or an int.

> It's curious to see the (d)evolution of thinking on type checking in
> Python circles. Once upon a time, type checking was discouraged,
> duck-typing was encouraged, and the philosophy was that an int is
> anything that behaves like an int.

I always differentiated 'int' as a type/class int object from 'integer' 
as anything that behaves like an 'int'. For me, and the function 
outlined above, that includes integer-values rationals along with int 
subclass instances.

> Now type-checking is tolerated or
> even encouraged, provided that you use isinstance,

I seem to have missed the encouragement.

 > and an int is anything that inherits from the builtin (or the ABC).
> And this proposed change in behaviour

To conform to how come read the doc..

 > continues the move away from Python's former emphasis on duck-typing.

For the reason explained above, I do not see this issue in such 
apocalyptic terms ;-)

Terry Jan Reedy

More information about the Python-Dev mailing list