msg207048 - (view) |
Author: Ethan Furman (ethan.furman) * |
Date: 2013-12-28 19:56 |
In order to create a coherent integer type class both __int__ and __index__ must be defined or the resulting instances will behave inconsistently in different places.
For example, if __index__ is not defined then the class cannot be used in slices, and if __int__ is not defined then int(integer_type) will fail.
At this point the programmer must remember to define both, but since they should return the same value we can have the type constructor automatically assign __int__ to __index__ when the latter is defined and the former is not. This would be similar to how we currently treat __ne__ when __eq__ is defined.
|
msg207050 - (view) |
Author: Benjamin Peterson (benjamin.peterson) * |
Date: 2013-12-28 20:08 |
__ne__ is not "bound" to __eq__. The comparison code simply falls back onto __eq__ if __ne__ is not defined.
|
msg207051 - (view) |
Author: Ethan Furman (ethan.furman) * |
Date: 2013-12-28 20:23 |
True. I meant similar in that Python will use what's available to fill in the blank:
class has __eq__ but user tried != ? use __eq__ and invert result
class has __index__ but user tried int() ? use __index__ as-is
|
msg207065 - (view) |
Author: R. David Murray (r.david.murray) * |
Date: 2013-12-29 02:19 |
It is not clear to me that that would be correct, though. Isn't the whole point of __index__ that some types can act as indicies even though they are *not* integers? Shouldn't it be up to the type to decide if converting them to int is a sensible thing to do? Maybe that's being silly/pendantic, though. On the gripping hand, it feels like this is another case of what you have pointed out elsewhere, that it is not clear that we actually have a consistent API here...
|
msg207068 - (view) |
Author: Ethan Furman (ethan.furman) * |
Date: 2013-12-29 08:11 |
In issue19995, in msg206339, Guido exhorted:
--------------------------------------------
>> [Ethan claimed] it is possible to want a type that can be used as an
>> index or slice but that is still not a number
>
> I'm sorry, but this requirement is absurd. An index *is* a number. You
> have to make up your mind. (I know, in the context of the example that
> started this, this is funny, but I still stand by it.)
>
> Finally, the correct name should perhaps have been __integer__ but I don't
> see enough reason to change it now.
The de facto API that is forming is that if an actual int is needed from an actual integer type (not float, not complex, not etc.), then __index__ is used. If __index__ is not defined by some numeric type then it will not be considered a true int in certain key places in Python, such as as indices, arguments to hex(), etc.
Making the change suggested in the title would help solidify the API.
|
msg207072 - (view) |
Author: R. David Murray (r.david.murray) * |
Date: 2013-12-29 13:44 |
Ah, I see. A link to that issue would have been helpful :).
To summarize for anyone like me who didn't follow that issue: __index__ means the object can be losslessly converted to an int (is a true int), while __int__ may be an approximate conversion. Thus it makes sense for an object to have an __int__ but not __index__, but vice-versa does not make sense.
Is someone updating the docs to reflect this, or should that be spun off as a separate issue as well?
|
msg207075 - (view) |
Author: Ethan Furman (ethan.furman) * |
Date: 2013-12-29 14:57 |
I have the following as part of the patch for that issue:
---------------------------------------------------------
diff -r b668c409c10a Doc/reference/datamodel.rst
--- a/Doc/reference/datamodel.rst Sat Dec 28 20:37:58 2013 +0100
+++ b/Doc/reference/datamodel.rst Sun Dec 29 06:55:11 2013 -0800
@@ -2073,23 +2073,31 @@ left undefined.
builtin: float
builtin: round
Called to implement the built-in functions :func:`complex`,
:func:`int`, :func:`float` and :func:`round`. Should return a value
of the appropriate type.
.. method:: object.__index__(self)
- Called to implement :func:`operator.index`. Also called whenever Python needs
- an integer object (such as in slicing, or in the built-in :func:`bin`,
- :func:`hex` and :func:`oct` functions). Must return an integer.
+ Called to implement :func:`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 :func:`bin`, :func:`hex` and :func:`oct`
+ functions). Presence of this method indicates that the numeric object is
+ an integer type. Must return an integer.
+
+ .. note::
+
+ When :meth:`__index__` is defined, :meth:`__int__` should also be defined,
+ and both shuld return the same value, in order to have a coherent integer
+ type class.
---------------------------------------------------------
If for some reason that patch doesn't make it into 3.4 I'll split the doc change off to its own issue, unless you think it should be split off anyway?
|
msg207084 - (view) |
Author: R. David Murray (r.david.murray) * |
Date: 2013-12-29 20:06 |
Nah, splitting it doesn't seem worth it unless you think the patch won't make it in.
(Not that I looked at it earlier, but he patch on the issue doesn't look like what you just posted here...and here there's a typo: shuld).
|
msg207085 - (view) |
Author: Ethan Furman (ethan.furman) * |
Date: 2013-12-29 20:30 |
I updated it as I liked your wording better. :) Doing more testing to see if anything else needs fixing before I make the next patch for the tracker on that issue.
|
msg207263 - (view) |
Author: Terry J. Reedy (terry.reedy) * |
Date: 2014-01-04 00:33 |
I believe this is my suggestion 2) in msg206715 of #19995, and I think it better than 3) (and 1) alone). Thanks for moving this forward. I believe what Guido said is that indexes (integers in the broad sense) are (or should be) a subset of things convertible to ints. I concur completely.
|
msg221310 - (view) |
Author: Amitava Bhattacharyya (amitava.b) |
Date: 2014-06-22 20:50 |
I started working on this issue as part of the Bloomberg Python Sprint (https://etherpad.mozilla.org/LjZPQ55oZs).
Ethan, can you confirm if the attached test case summarizes the issue correctly?
I tried to hook _PyLong_FromNbInt to check nb_index but didn't make progress there. Will need to load in a debugger to see what's going on.
|
msg221339 - (view) |
Author: Ethan Furman (ethan.furman) * |
Date: 2014-06-23 04:14 |
Yes, that test should pass when this issue is resolved.
I can't tell from your comment what you are trying to do to resolve it, but the course of action I had in mind was to have the `type` meta-class make a final examination of the type it was creating, and if that type had __index__ but not __int__ then bind __int__ to __index__.
|
msg221453 - (view) |
Author: Amitava Bhattacharyya (amitava.b) |
Date: 2014-06-24 11:56 |
Hi Ethan, I tried adding a call to `nb_index` (if that slot exists) in `_PyLong_FromNbInt`, but that didn't work. Based on your comment it seems the fix would be to patch this at object creation. I will check where that happens (bear with me while I familiarize myself with the code base :) ).
|
msg221459 - (view) |
Author: Ethan Furman (ethan.furman) * |
Date: 2014-06-24 13:48 |
Thank you for your efforts, Amitava. Please also sign a Contributor's License Agreement so we can actually use your code. :)
http://www.python.org/psf/contrib/
|
msg221474 - (view) |
Author: R. David Murray (r.david.murray) * |
Date: 2014-06-24 16:11 |
There will be a corporate agreement from Bloomberg sometime soon (and that will be required in this case, not an individual agreement).
|
msg221510 - (view) |
Author: Amitava Bhattacharyya (amitava.b) |
Date: 2014-06-24 23:27 |
I did fill in the contributor agreement form and e-signed it, maybe it takes some time for my profile to be updated? But I guess I need to wait for the corporate agreement. :)
|
msg313287 - (view) |
Author: Josh Rosenberg (josh.r) * |
Date: 2018-03-05 21:16 |
Pingback from #33002, which is caused by the fact that parts of the CPython code base that use PyNumber_Index for type conversion still pre-check for valid types with PyNumber_Check, meaning that a type with __index__ and not __int__ gets erroneously rejected by the pre-check.
|
msg341509 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) * |
Date: 2019-05-06 14:38 |
See also the discussion on the duplicated issue33039.
Few months ago I wrote the PR that makes constructors of int, float and complex to fall back to __index__ if corresponding special methods __int__, __float__ and __complex__ are not defined. I did not exposed it to public because binding __int__ to __index__ looks better to me. But perhaps some tests from that PR can be used in an alternate PR.
|
msg344206 - (view) |
Author: Mark Dickinson (mark.dickinson) * |
Date: 2019-06-01 19:21 |
I like the delegation of `float` and `complex` to use `__index__` that was introduced in GH-13108; it would be nice to have that regardless of which solution is decided on for `__int__` and `__index__`.
|
msg344234 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) * |
Date: 2019-06-01 21:05 |
New changeset bdbad71b9def0b86433de12cecca022eee91bd9f by Serhiy Storchaka in branch 'master':
bpo-20092. Use __index__ in constructors of int, float and complex. (GH-13108)
https://github.com/python/cpython/commit/bdbad71b9def0b86433de12cecca022eee91bd9f
|
msg406580 - (view) |
Author: Patrick Yang (patrick.yang.1248) |
Date: 2021-11-19 13:14 |
I ended up in this issue after I learnt the following from the Python Library Reference Manual.
----
float(..).
For a general Python object x, float(x) delegates to x.__float__(). If __float__() is not defined then it falls back to __index__().
----
The discussion on __int__() and __index__() was very interesting but I still didn't get the answer I wanted.
If __int__() is assumed to be a possibly approximate conversion and it's possible that __int__() may exist while __index__() doesn't, shouldn't __int__() be used as a fall back before __index__()?
The downside would be that the resulting float may not be "very close" to the original object because __int__() is only an approximation while __index__() guarantees exact, but loss of precision is acceptable during type conversion, isn't it? (i.e. int(3.14) -> 3). Perhaps it's not acceptable if the conversion is a widening conversion and that's why __int__() is skipped?
|
|
Date |
User |
Action |
Args |
2022-04-11 14:57:56 | admin | set | github: 64291 |
2021-11-19 13:14:29 | patrick.yang.1248 | set | nosy:
+ patrick.yang.1248 messages:
+ msg406580
|
2019-06-01 21:05:50 | serhiy.storchaka | set | messages:
+ msg344234 |
2019-06-01 19:21:31 | mark.dickinson | set | messages:
+ msg344206 |
2019-06-01 19:16:06 | mark.dickinson | set | nosy:
+ mark.dickinson
|
2019-05-06 14:38:54 | serhiy.storchaka | set | versions:
+ Python 3.8, - Python 3.5 nosy:
+ serhiy.storchaka
messages:
+ msg341509
components:
+ Interpreter Core |
2019-05-06 14:31:39 | remi.lapeyre | set | pull_requests:
+ pull_request13023 |
2019-05-06 14:30:46 | serhiy.storchaka | set | keywords:
+ patch stage: test needed -> patch review pull_requests:
+ pull_request13022 |
2019-05-06 14:29:29 | serhiy.storchaka | link | issue33039 superseder |
2018-03-05 21:16:06 | josh.r | set | nosy:
+ josh.r messages:
+ msg313287
|
2015-07-21 07:58:21 | ethan.furman | set | nosy:
- ethan.furman
|
2014-06-24 23:27:35 | amitava.b | set | messages:
+ msg221510 |
2014-06-24 16:11:56 | r.david.murray | set | messages:
+ msg221474 |
2014-06-24 13:48:42 | ethan.furman | set | messages:
+ msg221459 |
2014-06-24 11:56:52 | amitava.b | set | messages:
+ msg221453 |
2014-06-23 04:14:50 | ethan.furman | set | messages:
+ msg221339 |
2014-06-22 20:50:11 | amitava.b | set | files:
+ test_index_not_int.py nosy:
+ trent, amitava.b messages:
+ msg221310
|
2014-01-04 00:33:51 | terry.reedy | set | stage: test needed |
2014-01-04 00:33:35 | terry.reedy | set | nosy:
+ terry.reedy messages:
+ msg207263
|
2013-12-29 20:30:07 | ethan.furman | set | messages:
+ msg207085 |
2013-12-29 20:06:52 | r.david.murray | set | messages:
+ msg207084 |
2013-12-29 14:57:18 | ethan.furman | set | messages:
+ msg207075 |
2013-12-29 13:44:05 | r.david.murray | set | messages:
+ msg207072 |
2013-12-29 08:11:38 | ethan.furman | set | messages:
+ msg207068 |
2013-12-29 02:19:26 | r.david.murray | set | nosy:
+ r.david.murray messages:
+ msg207065
|
2013-12-28 20:41:45 | Arfrever | set | nosy:
+ Arfrever
|
2013-12-28 20:23:56 | ethan.furman | set | messages:
+ msg207051 |
2013-12-28 20:08:52 | benjamin.peterson | set | nosy:
+ benjamin.peterson messages:
+ msg207050
|
2013-12-28 19:56:32 | ethan.furman | create | |