Python Numbers — Unofficial Python Development (Victor's notes) documentation (original) (raw)
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 moduleis 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
numerator
anddenominator
attributes - numbers.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()
imag
real
int and Fraction attributes:
denominator
numerator
Conversions in Python¶
int(obj)
and float(obj)
accept:
int
float
decimal.Decimal
fractions.Fraction
bytes
str
int(obj)
rounds towards zero (ROUND_DOWN, ex: int(0.9) == 0
andint(-0.9) == 0
).
But int(obj)
and float(obj)
reject:
complex
complex(obj)
accepts:
int
float
complex
decimal.Decimal
fractions.Fraction
str
But complex(obj)
rejects:
bytes
decimal.Decimal(obj)
accepts:
int
float
decimal.Decimal
str
But decimal.Decimal(obj)
rejects:
complex
fractions.Fraction
bytes
fractions.Fraction(obj)
accepts:
int
float
decimal.Decimal
fractions.Fraction
str
(ex:"1"
or"1/2"
)
But fractions.Fraction(obj)
rejects:
complex
bytes
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
obj
type 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
x
iftype(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__()
method - New 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 result - error 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_CLEAN
is 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_CLEAN
before 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)))