Support subclassing (extending) numeric classes

I am not saying that anyone should be able, etc. I think you’ve lost the thread of the dialog that started with “So, let me put is simple”.

I don’t think there are such invariants:

>>> from gmp import mpz
>>> from fractions import Fraction
>>> type(Fraction('1/2').numerator)
<class 'int'>
>>> type(Fraction(1, 2).numerator)
<class 'int'>
>>> type(Fraction(mpz(1), 2).numerator)
<class 'gmp.mpz'>
>>> type(Fraction(mpz(1), 2).denominator)
<class 'gmp.mpz'>
>>> type(Fraction(1, mpz(2)).numerator)
<class 'gmp.mpz'>
>>> type(Fraction(1, mpz(2)).denominator)
<class 'gmp.mpz'>

And I think, it’s intentional. As I said, Fraction’s should work with any numbers.Integral type.

Though, sometimes you may want to add such invariant, for performance reasons.

In practice, this was the python-gmp extension, which also implements bindings to the GMP library, but lacks rational type. (To more closely resemble builtin integers and the stdlib behavior.)

BTW, there are plenty other examples. In the SymPy — Fraction class was reinvented (all math methods, etc; sometimes using worse algorithms). Twice, at least.

It is not “intended”, but that is not “forbidden” also - it just means at the time of design, it was not made sub-classing friendly.

Maybe that is better illustrated by Python’s `datetime`, which just a few years ago went through an overhaul to change exactly that behavior: in recent Python versions, subclasses of `datetime` will return a proper instance of the subclass when creating a new instance (either the class methods, or by being operated along with a `timedelta`)

So, I prefer attributing this rather to “it was not done” than to “you should not be out there subclassing our numeric types” - in the worst case the subclasses might not be compatible everywhere, or may get slower - but they should work for your code. And it would just be “bad practice” if subclassing would at all be “bad practice”.

All in all, if you want to do it, yes, you have to wrap all methods. I myself can’t stand jsut seeing a bunch of repeated methods doing the same, and I would prefer creating a class decorator to iterate over the dunder methods, and create a decorated call for each - but nowadays, with generative LLMs, you could just tell then to make the drudgework of creating all dunder-method wrappers as an alternative.

(to the detractors of the idea, please, this is not '“Ruby” where people would monkey patch the original class in place as a pattern favored by the language (even in docs) - it is proper sub-classing, generating instances that are to be used under control of the code author)

backlink https://stackoverflow.com/questions/79903031/how-can-i-make-methods-of-a-subclass-of-python-numeric-class-return-instances-of/79903043