[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.
"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>
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
> 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