What are numbers in Python?

Time:2021-6-28

What are numbers in Python?

Cat language: in Python, different types of numbers can do arithmetic operations directly without explicit type conversion. However, its “implicit type conversion” may be different from other languages, because numbers in Python are special objects derived from the same abstract base class. In the last articlearticleIn, we discussed the python number operation, and then I want to explore the topic of “what is the number object of Python in the end”, so I translated this PEP, hoping to help you.


PEP Original: https://www.python.org/dev/peps/pep-3141/

PEP Title: PEP 3141 — A Type Hierarchy for Numbers

PEP Author: Jeffrey Yasskin

Created on: 2007-04-23

translatorTofu pudding cat @Python public official account

PEP translation plan: https://github.com/chinesehua…

outline

This proposal defines an abstract base class (ABC)(PEP 3119)It is used to represent a number like class. It proposes a number: > complex: > Real: > rational: > integral hierarchy, where a: > b means “a is the superclass of B”. This hierarchy is inspired by scheme’s numerical tower( Number – complex number – real number – rational number – integer)

Basic principles

Functions with numbers as parameters should be able to determine the attributes of these numbers, and determine whether and when to overload according to the type of numbers, that is, functions should be overloadable based on the type of parameters.

For example, slicing requires that its parameters beIntegrals, andmathThe function in the module requires that its parameters beReal

standard

This PEP specifies a set of abstract base classes, and proposes a general strategy to implement some methods. It uses data fromPEP 3119But the hierarchy is designed to make sense of any system approach to a particular set of classes.

Type checking in the standard library should use these classes rather than specific built-in types.

Numerical class

We start with the number class, which is the fuzzy concept of the number type people imagine. This class is only used for heavy loads; It does not provide any operation.

class Number(metaclass=ABCMeta): pass

Most complex number implementations are hashable, but if you need to rely on it, you must explicitly check that this hierarchy supports variable numbers.

class Complex(Number):
    """Complex defines the operations that work on the builtin complex type.

    In short, those are: conversion to complex, bool(), .real, .imag,
    +, -, *, /, **, abs(), .conjugate(), ==, and !=.

    If it is given heterogenous arguments, and doesn't have special
    knowledge about them, it should fall back to the builtin complex
    type as described below.
    """

    @abstractmethod
    def __complex__(self):
        """Return a builtin complex instance."""

    def __bool__(self):
        """True if self != 0."""
        return self != 0

    @abstractproperty
    def real(self):
        """Retrieve the real component of this number.

        This should subclass Real.
        """
        raise NotImplementedError

    @abstractproperty
    def imag(self):
        """Retrieve the real component of this number.

        This should subclass Real.
        """
        raise NotImplementedError

    @abstractmethod
    def __add__(self, other):
        raise NotImplementedError

    @abstractmethod
    def __radd__(self, other):
        raise NotImplementedError

    @abstractmethod
    def __neg__(self):
        raise NotImplementedError

    def __pos__(self):
        """Coerces self to whatever class defines the method."""
        raise NotImplementedError

    def __sub__(self, other):
        return self + -other

    def __rsub__(self, other):
        return -self + other

    @abstractmethod
    def __mul__(self, other):
        raise NotImplementedError

    @abstractmethod
    def __rmul__(self, other):
        raise NotImplementedError

    @abstractmethod
    def __div__(self, other):
        """a/b; should promote to float or complex when necessary."""
        raise NotImplementedError

    @abstractmethod
    def __rdiv__(self, other):
        raise NotImplementedError

    @abstractmethod
    def __pow__(self, exponent):
        """a**b; should promote to float or complex when necessary."""
        raise NotImplementedError

    @abstractmethod
    def __rpow__(self, base):
        raise NotImplementedError

    @abstractmethod
    def __abs__(self):
        """Returns the Real distance from 0."""
        raise NotImplementedError

    @abstractmethod
    def conjugate(self):
        """(x+y*i).conjugate() returns (x-y*i)."""
        raise NotImplementedError

    @abstractmethod
    def __eq__(self, other):
        raise NotImplementedError

    # __ne__ is inherited from object and negates whatever __eq__ does.

RealAbstract base classes represent values on the real axis and support built-infloatThe operation of. Real numbers are completely ordered, except Nan, which is not considered in this pep.

class Real(Complex):
    """To Complex, Real adds the operations that work on real numbers.

    In short, those are: conversion to float, trunc(), math.floor(),
    math.ceil(), round(), divmod(), //, %, <, <=, >, and >=.

    Real also provides defaults for some of the derived operations.
    """

    # XXX What to do about the __int__ implementation that's
    # currently present on float?  Get rid of it?

    @abstractmethod
    def __float__(self):
        """Any Real can be converted to a native float object."""
        raise NotImplementedError

    @abstractmethod
    def __trunc__(self):
        """Truncates self to an Integral.

        Returns an Integral i such that:
          * i>=0 iff self>0;
          * abs(i) <= abs(self);
          * for any Integral j satisfying the first two conditions,
            abs(i) >= abs(j) [i.e. i has "maximal" abs among those].
        i.e. "truncate towards 0".
        """
        raise NotImplementedError

    @abstractmethod
    def __floor__(self):
        """Finds the greatest Integral <= self."""
        raise NotImplementedError

    @abstractmethod
    def __ceil__(self):
        """Finds the least Integral >= self."""
        raise NotImplementedError

    @abstractmethod
    def __round__(self, ndigits:Integral=None):
        """Rounds self to ndigits decimal places, defaulting to 0.

        If ndigits is omitted or None, returns an Integral,
        otherwise returns a Real, preferably of the same type as
        self. Types may choose which direction to round half. For
        example, float rounds half toward even.

        """
        raise NotImplementedError

    def __divmod__(self, other):
        """The pair (self // other, self % other).

        Sometimes this can be computed faster than the pair of
        operations.
        """
        return (self // other, self % other)

    def __rdivmod__(self, other):
        """The pair (self // other, self % other).

        Sometimes this can be computed faster than the pair of
        operations.
        """
        return (other // self, other % self)

    @abstractmethod
    def __floordiv__(self, other):
        """The floor() of self/other. Integral."""
        raise NotImplementedError

    @abstractmethod
    def __rfloordiv__(self, other):
        """The floor() of other/self."""
        raise NotImplementedError

    @abstractmethod
    def __mod__(self, other):
        """self % other

        See
        https://mail.python.org/pipermail/python-3000/2006-May/001735.html
        and consider using "self/other - trunc(self/other)"
        instead if you're worried about round-off errors.
        """
        raise NotImplementedError

    @abstractmethod
    def __rmod__(self, other):
        """other % self"""
        raise NotImplementedError

    @abstractmethod
    def __lt__(self, other):
        """< on Reals defines a total ordering, except perhaps for NaN."""
        raise NotImplementedError

    @abstractmethod
    def __le__(self, other):
        raise NotImplementedError

    # __gt__ and __ge__ are automatically done by reversing the arguments.
    # (But __le__ is not computed as the opposite of __gt__!)

    # Concrete implementations of Complex abstract methods.
    # Subclasses may override these, but don't have to.

    def __complex__(self):
        return complex(float(self))

    @property
    def real(self):
        return +self

    @property
    def imag(self):
        return 0

    def conjugate(self):
        """Conjugate is a no-op for Reals."""
        return +self

We should organize demo / classes / rat. Py and upgrade it to rational. Py and add it to the standard library. It then implements the rational abstract base class.

class Rational(Real, Exact):
    """.numerator and .denominator should be in lowest terms."""

    @abstractproperty
    def numerator(self):
        raise NotImplementedError

    @abstractproperty
    def denominator(self):
        raise NotImplementedError

    # Concrete implementation of Real's conversion to float.
    # (This invokes Integer.__div__().)

    def __float__(self):
        return self.numerator / self.denominator

Finally, the integer class:

class Integral(Rational):
    """Integral adds a conversion to int and the bit-string operations."""

    @abstractmethod
    def __int__(self):
        raise NotImplementedError

    def __index__(self):
        """__index__() exists because float has __int__()."""
        return int(self)

    def __lshift__(self, other):
        return int(self) << int(other)

    def __rlshift__(self, other):
        return int(other) << int(self)

    def __rshift__(self, other):
        return int(self) >> int(other)

    def __rrshift__(self, other):
        return int(other) >> int(self)

    def __and__(self, other):
        return int(self) & int(other)

    def __rand__(self, other):
        return int(other) & int(self)

    def __xor__(self, other):
        return int(self) ^ int(other)

    def __rxor__(self, other):
        return int(other) ^ int(self)

    def __or__(self, other):
        return int(self) | int(other)

    def __ror__(self, other):
        return int(other) | int(self)

    def __invert__(self):
        return ~int(self)

    # Concrete implementations of Rational and Real abstract methods.
    def __float__(self):
        """float(self) == float(int(self))"""
        return float(int(self))

    @property
    def numerator(self):
        """Integers are their own numerators."""
        return +self

    @property
    def denominator(self):
        """Integers have a denominator of 1."""
        return 1

Operation and__ magic__ Change of method

In order to support precision Shrinkage from float to int (to be exact, from real to integral), we propose the following new methods__ magic__ Method can be called from the corresponding library function. All of these methods return intergral instead of real.

  1. __ trunc__( Self): called in the new built-in TRUNC (x), which returns the closest integral from 0 to X.
  2. __ floor__( Self): called in math. Floor (x), returns the largest integral < = X.
  3. __ ceil__( Self): called in math. Ceil (x), returns the smallest integral > = X.
  4. __ round__( Self: call in round (x), return the integral closest to x, and round it according to the selected type. Floating point numbers will be rounded to even from version 3.0( Round (2.5) equals 2, round (3.5) equals 4). It also has a version with two parameters__ round__( Self, ndigits), which is called by round (x, ndigits), but returns a real.

In version 2.6, math. Floor, math. Ceil, and round will continue to return floating-point numbers.

The int() conversion of float is equivalent to trunc(). In general, the conversion of int () is attempted first__ int__(), If not, try again__ trunc__()。

complex.__{ divmod, mod, floordiv, int, float}__ It’s gone, too. It would be nice to provide a good error message to help the confused Porter, but more importantly, it doesn’t appear in help (complex).

Description for type implementers

Implementers should be careful to make equal numbers equal and hash them to the same value. This can be tricky if real numbers have two different extensions. For example, a plural type can reasonably implement hash ():

def __hash__(self):
    return hash(complex(self))

Note, however, that all values are outside the built-in complex range or precision.

Add more digital abstract base classes

Of course, numbers may have more abstract base classes, which would be a bad hierarchy if the possibility of adding these numbers was ruled out. You can add myfoo between complex and real in the following ways:

class MyFoo(Complex): ...
MyFoo.register(Real)

Realize arithmetic operation

We want to implement arithmetic operation, so that in mixed mode operation, either the caller knows how to handle the two parameter types, or both of them are converted to the closest built-in type for operation.

For subtypes of integral, this means that__ add__ And__ radd__ It should be defined as:

class MyIntegral(Integral):

    def __add__(self, other):
        if isinstance(other, MyIntegral):
            return do_my_adding_stuff(self, other)
        elif isinstance(other, OtherTypeIKnowAbout):
            return do_my_other_adding_stuff(self, other)
        else:
            return NotImplemented

    def __radd__(self, other):
        if isinstance(other, MyIntegral):
            return do_my_adding_stuff(other, self)
        elif isinstance(other, OtherTypeIKnowAbout):
            return do_my_other_adding_stuff(other, self)
        elif isinstance(other, Integral):
            return int(other) + int(self)
        elif isinstance(other, Real):
            return float(other) + float(self)
        elif isinstance(other, Complex):
            return complex(other) + complex(self)
        else:
            return NotImplemented

There are five different cases of mixed type operation on subclasses of complex. I refer to all of the above code that does not include myintegral and othertypeiknowabout as “templates.”.

A is an instance of a, which isComplex(a : A <: Complex)Subtypes of, andb : B <: Complex. For a + B, let me consider this:

  1. If a defines a function that accepts B__ add__, No problem then.
  2. If a goes to the else branch, it also goes from__ add__ If we return a value, we will miss a more intelligent definition for B__ radd__ So the template should start from__ add__ Returns notimplemented( Or a may not be implemented__ add__)
  3. Then B’s__ radd__ Here’s our chance. If it accepts a, then no problem.
  4. If it goes to the template branch, there is no way, so there needs to be a default implementation.
  5. If B <: A, python will be in a__ add__ Try B__ radd__。 This is also OK, because it is based on a, so you can process these instances before delegating to complex.

If there is no other relationship between a <: complex and B <: real, the appropriate shared operation is the built-in plural operation__ radd__ So a + B = = B + a( I don’t understand these paragraphs very well, maybe they are not translated correctly

Rejected solutions

The initial version of this PEP defines aHaskell Numeric PreludeThe inspired algebraic hierarchies include monoid underplus, additive group, ring and field, and there are several other possible algebraic types before numbers are obtained.

We had hoped that this would be useful for people who use vectors and matrices, but the numpy community is not interested in it. In addition, we also encounter a problem. Even if x is an instance of x <: monoidunderplus and Y is an instance of Y <: monoidunderplus, x + y may not work.

Then, we provide more branching structures for numbers, including Gaussian integer and Z / NZ, which can be complex, but do not necessarily support operations such as division.

The community thinks this is too complicated for Python, so I’ve now narrowed down the scope of the proposal to make it closer to the scheme tower.

The Decimal Type

After consultation with the author, it has been decided not to use the decimal type as part of the digital tower at present.

reference

1. Introduction to abstract base classes:http://www.python.org/dev/peps/pep-3119/

2. Could it be a python 3 class tree? Bill Janssen’s wiki page:http://wiki.python.org/moin/AbstractBaseClasses

3. Numericprelude: experimental alternative hierarchy for number type classes:http://darcs.haskell.org/numericprelude/docs/html/index.html

4. Scheme digital Tower:https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html/r5rs_8.html#SEC50

It was only after the translation that I found out“PEP Chinese translation program”I’ve included onetranslationIn some places, the translations are different, so readers can compare them.)

thank

Thanks to Neal norwitz for initially encouraging me to write this PEP, to Travis Oliphant for pointing out that the numpy community doesn’t really care about algebra concepts, to Alan Isaac for reminding me that scheme has done it, and to Guido van Rossum and others in the email group for helping improve this set of concepts.

copyright

The document has been put into the public domain.

Source file:https://github.com/python/peps/blob/master/pep-3141.txt

Recommended Today

Blog Garden Background page dynamic effects

1. To set animation, you must first apply for permission 1.1 first enter [my blog park] and enter [settings] in [management] 1.2 find [blog sidebar announcement] and click [apply for JS permission] 1.3 write the content of application JS permission (examples are as follows) Dear blog administrator: Can you open JS permission for me? I […]