Repository navigation
Deprecate delegation of int to __trunc__ #89140
Description
Activity
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.
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.
Completely agree.
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.
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.
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__
I do not think that math.trunc() for UUID or IP4Address makes sense.
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()) 43341414945793370480422623795805641537I retract the suggestion to deprecate __trunc__.
- added3.11only security fixesonly security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Oct 15, 2021 - changed the title
[-]Deprecate delegation of int to __trunc__?[/-][+]Deprecate delegation of int to __trunc__[/+]on Oct 15, 2021 - added3.11only security fixesonly security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Oct 15, 2021 - changed the title
[-]Deprecate delegation of int to __trunc__?[/-][+]Deprecate delegation of int to __trunc__[/+]on Oct 15, 2021 I have created a patch for this issue. Please consider having a look.
Thanks Zackery.
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields: