Reputation: 303
I understand the operation as converting sth., which is not an integer, to integer. do I understand it correctly?
my attempt to implement the function "operator.index ()":
import operator
a = float (1.0)
print (a)
print (type (a))
print (type (operator.index (a)))
I have expected:
1.0
<class 'float'>
<class 'integer'>
actual output:
1.0
<class 'float'>
TypeError: 'float' object can not be interpreted as an integer
Upvotes: 4
Views: 2990
Reputation: 1124738
The __index__
can only be used to losslessly interpret an object as an integer index value. From the documentation for the hook:
Called to implement
operator.index()
, and whenever Python needs to losslessly convert the numeric object to an integer object (such as in slicing, or in the built-inbin()
,hex()
andoct()
functions). Presence of this method indicates that the numeric object is an integer type. Must return an integer.
A float
is not an integer type, even if a subset of float values are whole numbers.
In the standard library, only the int
and bool
types currently implement that hook. The hook exists for custom classes in your own code or defined in 3rd-party libraries to be useable when indexing sequences.
It is distinct from __int__
because that hook does allow for lossy conversion; int(3.9)
gives you 3
, but you would not expect listobject[3.9]
to work (what should that return, the element at index 3
or 4
?). You can't use int()
to coerce floats into integers when indexing, or only accept whole floats (that'd be inconsistent and confusing).
You'd only use operator.index()
if you need to support arbitrary int-like types in your own Python code:
class SequenceObject:
# ...
def __getitem__(self, idx):
idx = operator.index(idx) # convert to a valid integer index value
# ...
The __index__
special method was added to Python with PEP 357, so you can use the numpy
project integers (which are a different type) in slicing and indexing, so this works:
>>> import operator
>>> import numpy as np
>>> number1 = np.int8(1)
>>> type(number1)
<class 'numpy.int8'>
>>> type(operator.index(number1))
<class 'int'>
>>> l = [17, 42, 81]
>>> l[number1]
42
and __index__
to allow your class to be used in indexing:
>>> class EnglishNumber:
... # lets pretend this is a number that automatically shows
... # as the English name, like the https://pypi.org/p/inflect would
... def __init__(self, name, value):
... self._value = value
... self._name = name
... def __repr__(self): return f"<EnglishNumber {self._name}>"
... def __str__(self): return self._name
... def __index__(self): return self._value
...
>>> number2 = EnglishNumber("two", 2)
>>> number2
<EnglishNumber two>
>>> operator.index(number2)
2
>>> l[number2]
81
Upvotes: 9