I'm working through this tutorial which has the following Binary class:
import collections
class Binary:
def __init__(self, value=0):
if isinstance(value, collections.Sequence):
if len(value) > 2 and value[0:2] == '0b':
self._value = int(value, base=2)
elif len(value) > 2 and value[0:2] == '0x':
self._value = int(value, base=16)
else:
self._value = int(''.join([str(i) for i in value]), base=2)
else:
try:
self._value = int(value)
if self._value < 0:
raise ValueError("Binary cannot accept negative numbers. Use SizedBinary instead")
except ValueError:
raise ValueError("Cannot convert value {} to Binary".format(value))
def __int__(self):
return self._value
when running a unittest with pytest we get:
def test_binary_hex():
binary = Binary(6)
> assert hex(binary) == '0x6'
E TypeError: 'Binary' object cannot be interpreted as an integer
To solve this , the article states:
According to the official documentation, "If x is not a Python int object, it has to define an
__index__()
method that returns an integer." so this is what we are missing. As for__index__()
, the documentation states that "In order to have a coherent integer type class, when__index__()
is defined__int__()
should also be defined, and both should return the same value."
So we just have to add
def __index__(self):
return self.__int__()
This does work, but why do the __index__
and __int__
as written here, return the same value? Regarding:
def __index__(self):
return self.__int__()
Shouldnt it be : return self._value. __int__()
edit:
with:
def __int__(self):
return self._value
This makes sense to me because _value
is an integer.
with:
def __index__(self):
return self.__int__()
In this case again self is an instance of a class , which in theory could many attributes (although not in this case). I don't understand how in return self. __int__()
, the __int__()
knows to get the integer stored in _value
if we don't pass _value
explicitly to __int__()
self._value
is an int, calling the __int__()
method on an int returns the same value, so writing:
return self._value.__int__()
would do the same as:
return self._value
And just to prove my point it would be the same as:
return int(int(int(int(self._value))))
In most cases you can write __index__
to be a direct alias to the same function:
def __int__(self):
return self._value
__index__ = __int__
PS You may want to look at PEP 357 for the rational of why the __index__
method exists.
Basically it is to distinguish between objects that can be converted to an int
and objects that are inherently integers:
>>> int(1.3)
1
>>> hex(1.3)
Traceback (most recent call last):
File "<pyshell#55>", line 1, in <module>
hex(1.3)
TypeError: 'float' object cannot be interpreted as an integer
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.