This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Deprecate delegation of int to __trunc__
Type: Stage: resolved
Components: Interpreter Core Versions: Python 3.11
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: ZackerySpytz, mark.dickinson, rhettinger, serhiy.storchaka
Priority: normal Keywords: patch

Created on 2021-08-22 09:17 by mark.dickinson, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 31031 merged ZackerySpytz, 2022-01-31 02:32
Messages (12)
msg400063 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2021-08-22 09:17
The int constructor, when applied to a general Python object `obj`, first looks for an __int__ method, then for an __index__ method, and then finally for a __trunc__ method.

The delegation to __trunc__ used to be useful: it meant that users could write a custom class SomeNumber with the property that:

- SomeNumber instances supported 'int' calls, returning a truncated value, but
- SomeNumber instances weren't usable in indexing, chr() calls, and all the various other calls that implicitly invoked __int__.

class SomeNumber:
    def __trunc__(self):
       <return truncated value for self>

However, with Python >= 3.10, we no longer use __int__ implicitly for argument conversion in internal code. So the second point above is no longer a concern, and SomeNumber can now simply be written as

class SomeNumber:
    def __int__(self):
       <return truncated value for self>

This decouples int from __trunc__ and leaves __trunc__ as simply the support for the math.trunc function.
msg400064 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2021-08-22 09:19
> This decouples int from __trunc__ and leaves __trunc__ as simply the support for the math.trunc function.

Argh; copy and paste fail - I left out the crucial line.

I propose deprecating the delegation of int to __trunc__: calls to int(a) where type(a) implements __trunc__ but not __int__ or __index__ would raise a DeprecationWarning, and at some point in the future int(a) would become a TypeError.
msg400073 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2021-08-22 13:20
Completely agree.
msg400074 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-08-22 14:36
Afterwards, do __trunc__ and math.trunc() still need to exist?

They were mostly unused.  Now they would also be unnecessary.  Just having them around would be a point of confusion.
msg400076 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2021-08-22 15:13
A GitHub code search shows a substantial number of uses of math.trunc out in the wild:

https://github.com/search?q=math.trunc+extension%3Apy&type=Code

So unfortunately, getting rid of math.trunc and __trunc__ looks a bit too much as though it would cause gratuitous breakage.
msg400078 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-08-22 15:25
Possibly, we could have math.trunc() call __int__, letting us deprecate __trunc__.

That would let users avoid gratuitous aliasing such as that in _pydecimal.py:

   __trunc__ = __int__
msg400079 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2021-08-22 15:54
I do not think that math.trunc() for UUID or IP4Address makes sense.
msg400080 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2021-08-22 15:56
I think the needs are sufficiently different that __trunc__ still has value as its own thing, and it's a natural counterpart to __floor__ and __ceil__ (out of all the directed rounding modes, rounding towards zero probably turns up more often than rounding towards +inf or -inf).

__int__ has the disadvantage that it must return an int, so it's not useful for other Python-based numeric systems with their own rational number / integer pairing. For example, with gmpy2, truncating an mpq instance returns an mpz instance, which is what I'd expect and want - if I'm working with huge values then it would be annoying for math.trunc to do the inefficient thing and return a plain int.

>>> from gmpy2 import mpq
>>> math.trunc(mpq(22, 7))
mpz(3)

SymPy behaves similarly:

>>> from sympy import Rational
>>> type(math.trunc(Rational(22, 7)))
<class 'sympy.core.numbers.Integer'>

On the other side, there are conversions to integer that it doesn't make sense to think of as truncation. It would be odd for a UUID to be a valid input to math.trunc, for example:

>>> int(uuid.uuid4())
43341414945793370480422623795805641537
msg400082 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-08-22 17:32
I retract the suggestion to deprecate __trunc__.
msg412190 - (view) Author: Zackery Spytz (ZackerySpytz) * (Python triager) Date: 2022-01-31 02:46
I have created a patch for this issue.  Please consider having a look.
msg412431 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2022-02-03 09:43
New changeset b4bd1e1422997de61faf506b4916e83013bc7d21 by Zackery Spytz in branch 'main':
bpo-44977: Deprecate delegation of int to __trunc__ (GH-31031)
https://github.com/python/cpython/commit/b4bd1e1422997de61faf506b4916e83013bc7d21
msg412432 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2022-02-03 09:44
Thanks Zackery.
History
Date User Action Args
2022-04-11 14:59:49adminsetgithub: 89140
2022-02-03 09:44:44serhiy.storchakasetstatus: open -> closed
resolution: fixed
messages: + msg412432

stage: patch review -> resolved
2022-02-03 09:43:45serhiy.storchakasetmessages: + msg412431
2022-01-31 02:46:16ZackerySpytzsetmessages: + msg412190
2022-01-31 02:32:26ZackerySpytzsetkeywords: + patch
nosy: + ZackerySpytz

pull_requests: + pull_request29214
stage: needs patch -> patch review
2021-10-15 12:41:40serhiy.storchakasettitle: Deprecate delegation of int to __trunc__? -> Deprecate delegation of int to __trunc__
stage: needs patch
components: + Interpreter Core
versions: + Python 3.11
2021-08-22 17:32:04rhettingersetmessages: + msg400082
2021-08-22 15:56:51mark.dickinsonsetmessages: + msg400080
2021-08-22 15:54:26serhiy.storchakasetmessages: + msg400079
2021-08-22 15:25:48rhettingersetmessages: + msg400078
2021-08-22 15:13:07mark.dickinsonsetmessages: + msg400076
2021-08-22 14:36:49rhettingersetnosy: + rhettinger
messages: + msg400074
2021-08-22 13:20:49serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg400073
2021-08-22 09:19:56mark.dickinsonsetmessages: + msg400064
2021-08-22 09:17:57mark.dickinsoncreate