vostro.beta
vostro.beta

Reputation: 303

could someone give an example for "operator.index ()"?

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

Answers (1)

Martijn Pieters
Martijn Pieters

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-in bin(), hex() and oct() 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

Related Questions