I am trying to check if an object is an instance of a number of any type (int
, float
, Fraction
, Decimal
, etc.).
I came across this question and its answer: How to properly use python's isinstance() to check if a variable is a number?
However, I would like to exclude complex numbers such as 1j
.
The class numbers.Real
looked perfect but it returns False
for Decimal
numbers.
from numbers Real
from decimal import Decimal
print(isinstance(Decimal(1), Real))
# False
In contradiction, it works fine with Fraction(1)
, for example.
The documentation describes some operations which should work with the number. I tested them without any error on a decimal instance. Moreover, decimal objects cannot contain complex numbers.
So, why should isinstance(Decimal(1), Real)
return False
?
So, I found the answer directly in the source code of cpython/numbers.py
:
## Notes on Decimal
## ----------------
## Decimal has all of the methods specified by the Real abc, but it should
## not be registered as a Real because decimals do not interoperate with
## binary floats (i.e. Decimal('3.14') + 2.71828 is undefined). But,
## abstract reals are expected to interoperate (i.e. R1 + R2 should be
## expected to work if R1 and R2 are both Reals).
Indeed, adding Decimal
to float
would raise a TypeError
.
In my point of view, it violates the principle of least astonishment, but it does not matter much.
As a workaround, I use:
import numbers
import decimal
Real = (numbers.Real, decimal.Decimal)
print(isinstance(decimal.Decimal(1), Real))
# True