Python Numbers¶
Number Types¶
int: integral numberfloat: floating point number, usually IEEE 754 (64 bits, base 2)complex: complex number, implemented as two floatsdecimal.Decimal: floating point number stored in base 10, arbitrary precisionfractions.Fraction: rational, numerator/denominator; automatically compute the greatest common divisor (GCD) to simplify the fraction
Number Tower¶
The numbers module is specified by the PEP 3141 – A Type Hierarchy for Numbers.
numbers.Number: base class
numbers.Complex: Add
real,imag,conjugate()numbers.Real: subclass of Complex; add many float operations.
numbers.Rational: subclass of Real; add
numeratoranddenominatorattributesnumbers.Integral: subclass of Rational
Subclasses:
numbers.Number: int, float, complex, decimal.Decimal, fractions.Fraction
numbers.Complex: int, float, complex, fractions.Fraction
numbers.Real: int, float, fractions.Fraction
numbers.Rational: int, fractions.Fraction
numbers.Integral: int
int, float, complex methods and attributes:
conjugate()imagreal
int and Fraction attributes:
denominatornumerator
Conversions in Python¶
int(obj) and float(obj) accept:
intfloatdecimal.Decimalfractions.Fractionbytesstr
int(obj) rounds towards zero (ROUND_DOWN, ex: int(0.9) == 0 and
int(-0.9) == 0).
But int(obj) and float(obj) reject:
complex
complex(obj) accepts:
intfloatcomplexdecimal.Decimalfractions.Fractionstr
But complex(obj) rejects:
bytes
decimal.Decimal(obj) accepts:
intfloatdecimal.Decimalstr
But decimal.Decimal(obj) rejects:
complexfractions.Fractionbytes
fractions.Fraction(obj) accepts:
intfloatdecimal.Decimalfractions.Fractionstr(ex:"1"or"1/2")
But fractions.Fraction(obj) rejects:
complexbytes
int type¶
Examples:
>>> (123).bit_length()
7
>>> sys.int_info
sys.int_info(bits_per_digit=30,
sizeof_digit=4)
Serialization as bytes:
>>> (123).to_bytes(4, 'little')
b'{\x00\x00\x00'
>>> int.from_bytes(b'{\x00\x00\x00', 'little')
123
Rounding:
int(float)callsfloat.__trunc__(), so rounds towards zero (ROUND_DOWN)
float type¶
Examples:
>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308,
max_exp=1024,
max_10_exp=308,
min=2.2250738585072014e-308,
min_exp=-1021,
min_10_exp=-307,
dig=15,
mant_dig=53,
epsilon=2.220446049250313e-16,
radix=2,
rounds=1)
>>> sys.float_repr_style
'short'
>>> (1.2).as_integer_ratio()
(5404319552844595, 4503599627370496)
Formatting as hexadecimal (base 16):
>>> (1.1).hex()
'0x1.199999999999ap+0'
>>> float.fromhex('0x1.199999999999ap+0')
1.1
Rounding:
float.__trunc__(): Round towards zero (ROUND_DOWN)
float.__round__(): Round to nearest with ties going to nearest even integer (ROUND_HALF_EVEN).
float.__int__() is an alias to float.__trunc__() (ROUND_DOWN)
Fraction¶
>>> fractions.Fraction(5, 10) # int / int
Fraction(1, 2)
>>> fractions.Fraction(1.2) # float
Fraction(5404319552844595, 4503599627370496)
C API¶
Convert a Python object to an integer. Type methods:
__int__(): slottype->tp_as_number->nb_int__index__(): slottype->tp_as_number->nb_index__trunc__()(no slot)
PyNumber_Long(obj):
Call
obj.__trunc__()(Round towards zero, ROUND_DOWN)or: If
objtype is bytes or str, parse the string in decimal (base 10)or: error!
PyNumber_Index(x) calls the __index__() method: raises an exception if
the type has no __index__() method or if method does not return exactly an
int type (*).
_PyLong_FromNbInt(x):
Call
type(x).__int__(x): the result type must be exactly the int type (*)or: error!
_PyLong_FromNbIndexOrNbInt(x): __index__() or __int__():
return
xiftype(x) == int(PyLong_CheckExact())call
type(x).__index__(x)if defined: the result type must be exactly the int type (*)call
type(x).__int__(x)(call_PyLong_FromNbInt()): the result type must be exactly the int type (*)error if it is not a int subclass, and the type don’t define
__index__()nor__int__()methodNew in Python 3.8
PyLong_AsLong() converts a Python int to a C long:
call
_PyLong_FromNbIndexOrNbInt()raise OverflowError if the result does not fit into a C long
Python 3.7 and older only calls
__int__(), not__index__().
PyLong_AsUnsignedLongMask() converts a Python object to a C unsigned
long:
call
_PyLong_FromNbIndexOrNbInt(x)and then_PyLong_AsUnsignedLongMask()on the resulterror if the object cannot be converted to an int by
_PyLong_FromNbIndexOrNbInt(x)mask integer overflow
Python 3.7 and older only calls
__int__(), not__index__().
(*) Special case: __int__() or __index__() return a int subclass. This
feature is deprecated since Python 3.3 (see commit 6a44f6ee).
This feature may be removed from Python 3.9: see bpo-17576.
PyArg_ParseTuple and Py_BuildValue¶
Reference documentation: Parsing arguments and building values.
PyArg_ParseTuple is implemented in
Python/getargs.c, core function:convertsimple().Py_BuildValue is implemented in
Python/modsupport.c, core function:do_mkvalue().Functions behave differently if
PY_SSIZE_T_CLEANis defined:For all
#variants of formats (s#,y#, etc.), the type of the length argument (int orPy_ssize_t) is controlled by defining the macroPY_SSIZE_T_CLEANbefore includingPython.h.
PyArg_ParseTuple formats:
"i"(Cint):__index__()or__int__(); callPyLong_AsLong(obj), but explicitly rejects float usingPyFloat_Check(arg)."l"(Clong):__index__()or__int__(); callPyLong_AsLong(), but explicitly rejects float usingPyFloat_Check(arg)"n"(Cssize_t):__index__(); callPyNumber_Index()and thenPyLong_AsSsize_t(). Exception on overflow."k": callPyLong_AsUnsignedLongMask()if it’s an int or int subclass, error otherwise. Mask integer overflow.
Note: In Python 3.7 and older, PyLong_AsLong() only calls __int__(),
not __index__().
Script to update this page¶
number_tower.py:
from __future__ import print_function
import numbers
import warnings
import fractions
import decimal
warnings.simplefilter("error", DeprecationWarning)
VALUES = (
("int", 123),
("float", 1.5),
("complex", complex(0, 1.5)),
("decimal.Decimal", decimal.Decimal("1.1")),
("fractions.Fraction", fractions.Fraction(1, 7)),
("bytes", b"123"),
("str", "123"),
)
TYPES = (
("int", int),
("float", float),
("complex", complex),
("decimal.Decimal", decimal.Decimal),
("fractions.Fraction", fractions.Fraction),
)
for type_descr, num_type in TYPES:
accepted = []
rejected = []
for value_descr, value in VALUES:
try:
num_type(value)
except TypeError:
rejected.append(value_descr)
else:
accepted.append(value_descr)
if accepted:
print("``%s(obj)`` accept:" % type_descr)
print()
for name in accepted:
print("* ``%s``" % name)
print()
if rejected:
print("``%s(obj)`` reject:" % type_descr)
print()
for name in rejected:
print("* ``%s``" % name)
print()
print()
for tower_name, tower_type in (
("Number", numbers.Number),
("Complex", numbers.Complex),
("Real", numbers.Real),
("Rational", numbers.Rational),
("Integral", numbers.Integral),
):
subclasses = []
for type_descr, num_type in TYPES:
if issubclass(num_type, tower_type):
subclasses.append(type_descr)
print("%s subclasses: %s" % (tower_name, ", ".join(subclasses)))