​What are the numbers in Python?

**Spend the time: **In Python, different types of numbers can be directly used for arithmetic operations without explicit type conversion. However, its "implicit type conversion" may be different from other languages, because numbers in Python are a special kind of objects derived from the same abstract base class. In previous article, we discussed the calculation of Python numbers, and then I wanted to explore the topic of "what is the number object of Python", so I translated this PEP, I hope it will be helpful to you too .


**PEP original text: ** https://www.python.org/dev/peps/pep-3141

**PEP Title: ** PEP 3141 - A Type Hierarchy for Numbers

**PEP Author: ** Jeffrey Yasskin

**Creation Date: ** 2007-04-23

Translator: Pea Flower Under the Cat @Python猫 Public Number

**PEP translation plan: ** https://github.com/chinesehuazhou/peps-cn

Summary

This proposal defines a hierarchical structure of abstract base classes (ABC) (PEP 3119) to represent number-like classes. It proposes a hierarchical structure of Number :> Complex :> Real :> Rational :> Integral, where A :> B means "A is a superclass of B". This hierarchy is inspired by Scheme's numeric tower. (Annotation: Number-Complex Number-Real Number-Rational Number-Integer)

Fundamental

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

For example, slice requires its parameter to be Integrals, while the function in the math module requires its parameter to be Real.

Specification

This PEP specifies a set of abstract base classes (Abstract Base Class) and proposes a general strategy for implementing certain methods. It uses terminology from PEP 3119, but the hierarchy is intended to make sense for any system approach of a particular set of classes.

Type checking in the standard library should use these classes instead of specific built-in types.

Numerical class

We start with the Number class, which is a vague concept of number types that people imagine. This class is only used for overloading; it does not provide any operations.

classNumber(metaclass=ABCMeta): pass

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

classComplex(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 ofthis number.

  This should subclass Real."""
  raise NotImplementedError

 @ abstractproperty
 def imag(self):"""Retrieve the real component ofthis 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.

The Real abstract base class represents the value on the real number axis and supports the built-in float operation. Real numbers are completely ordered, except for NaN (this PEP basically does not consider it).

classReal(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):returncomplex(float(self))

 @ property
 def real(self):return+self

 @ property
 def imag(self):return0

 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 to add to the standard library. Then it will implement the abstract base class for rational numbers (Rational).

classRational(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:

classIntegral(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__()."""returnint(self)

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

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

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

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

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

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

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

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

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

 def __ror__(self, other):returnint(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))"""returnfloat(int(self))

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

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

Changes to calculations and magic method

In order to support the precision shrinkage from float to int (to be precise, from Real to Integral), we propose the following new magic method, which can be called from the corresponding library function. All these methods return Intergral instead of Real.

  1. __ trunc__(self): Called in the new built-in trunc(x), it returns the Integral from 0 to x that is closest to x.
  2. __ floor__(self): Called in math.floor(x) and returns the largest Integral <= x.
  3. __ ceil__(self): Called in math.ceil(x) and returns the smallest Integral >= x.
  4. __ round__(self): Called in round(x), returns the Integral closest to x, and rounds up according to the selected type. Floating point numbers will be rounded to the even end from version 3.0. (Annotation: round(2.5) is equal to 2, round(3.5) is equal to 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(). Generally speaking, the conversion of int() will first try int(), if not found, then try trunc().

complex.{divmod, mod, floordiv, int, float} also disappeared. It's good to provide a good error message to help the confused porter, but more importantly, it doesn't appear in help(complex).

Instructions for type implementers

Implementers should take care to make equal numbers equal and hash them to the same value. If real numbers have two different extensions, this can become subtle. For example, a complex type can reasonably implement hash() like this:

def __hash__(self):returnhash(complex(self))

But you should pay attention to all values that exceed the built-in complex number range or precision.

Add more digital abstract base classes

Of course, numbers may have more abstract base classes. If the possibility of adding these numbers is ruled out, this would be a bad hierarchy. You can use the following methods to add MyFoo between Complex and Real:

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

Implement arithmetic operations

We hope to implement arithmetic operations, so that in mixed-mode operations, either the caller knows how to deal with the two parameter types, or both are converted to the closest built-in type and operated accordingly.

For the subtypes of Integral, this means that add and radd should be defined as:

classMyIntegral(Integral):

 def __add__(self, other):ifisinstance(other, MyIntegral):returndo_my_adding_stuff(self, other)
  elif isinstance(other, OtherTypeIKnowAbout):returndo_my_other_adding_stuff(self, other)else:return NotImplemented

 def __radd__(self, other):ifisinstance(other, MyIntegral):returndo_my_adding_stuff(other, self)
  elif isinstance(other, OtherTypeIKnowAbout):returndo_my_other_adding_stuff(other, self)
  elif isinstance(other, Integral):returnint(other)+int(self)
  elif isinstance(other, Real):returnfloat(other)+float(self)
  elif isinstance(other, Complex):returncomplex(other)+complex(self)else:return NotImplemented

There are 5 different situations for mixed-type operations on complex subclasses. I call all the above code that does not include MyIntegral and OtherTypeIKnowAbout "boilerplate".

a is an instance of A, which is a subtype of Complex(a: A &lt;: Complex), and b: B &lt;: Complex. For a + b, I consider this:

  1. If A defines add that accepts b, then there is no problem.
  2. If A goes to the boilerplate code branch and returns a value from add, then we miss the possibility of defining a smarter radd for B, so the boilerplate should start from add Return NotImplemented. (Or A may not implement add)
  3. Then B's radd opportunity came. If it accepts a, then there is no problem.
  4. If it goes to the boilerplate branch, there is no way, so there needs to be a default implementation.
  5. If B <: A, Python will try B.__ radd__ before A.__ add__. This is also possible because it is implemented based on A, so these instances can be processed before delegating to Complex.

If A <: Complex and B <: Real have no other relationship, then the appropriate shared operation is the operation of the built-in complex number, and their radd is in it, so a + b == b + a. (Annotation: I didn’t read these paragraphs too clearly, maybe they were translated incorrectly)

Rejected proposal

The initial version of this PEP defines an algebraic hierarchy inspired by Haskell Numeric Prelude, which includes MonoidUnderPlus, AdditiveGroup, Ring and Field, and there are several other possible algebra types before getting numbers.

We originally hoped that this would be useful to people who use vectors and matrices, but the NumPy community is really not interested in it, and we also encountered a problem, even if x is an instance of X <: MonoidUnderPlus and y is an instance of Y <: MonoidUnderPlus , X + y may still not work.

Then, we provide more branch structures for numbers, including things like Gaussian Integer and Z/nZ. They can be complex, but do not necessarily support operations such as "divide".

The community thinks this is too complicated for Python, so I now narrow the scope of the proposal to make it closer to the Scheme digital tower.

Decimal type

After consulting with the author, it has been decided not to use the Decimal type as part of the digital tower at this time.

references

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

2、 Could it be the class tree of Python 3? Bill Janssen's Wiki page: http://wiki.python.org/moin/AbstractBaseClasses

3、 NumericPrelude: Experimental alternative hierarchy of numeric 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

(Annotation: After the translation, I found out that the "PEP Chinese Translation Project" has included a translation. Some parts of the translation are not the same. Readers can click to read the original text and compare and read.)

**Thanks **

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

Copyright

The document has been placed in the public domain.

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

Recommended Posts

​What are the numbers in Python?
What are the ways to open files in python
What are the required parameters of python
What are web development frameworks in python
What are the advantages of python language
What does the tab key in python mean
What are python class attributes
What is introspection in python
What is object-oriented in python
What conditions are needed for infinite loop in Python
What are the methods for python to connect to mysql
Python data visualization: who are the big names in Python?
The usage of wheel in python
What is list comprehension in python
What does rc1 mean in python
What does def in python do
What is the use of Python
How to filter numbers in python
There are several keywords in Python
What does np do in python
Talking about the modules in Python
The usage of tuples in python
Understanding the meaning of rb in python
The usage of Ajax in Python3 crawler
What is the scope of python variables
What is an anonymous function in Python
What is the prospect of python development
What is a sequence table in Python
What is the function body of python
Python randomly shuffles the elements in the list
Functions in python
2.1 The Python Interpreter (python interpreter)
How to use the round function in python
Explain the list under Python multithreading in detail
How to use the zip function in Python
An article to understand the yield in Python
Python implements the shuffling of the cards in Doudizhu
The meaning and usage of lists in python
How to use the format function in python
First acquainted with python, the grammatical rules in python
What is the difference between python and pycharm
The consequences of uninstalling python in ubuntu, very
How to install the downloaded module in python
The best way to judge the type in Python
What is the difference between synchronous and asynchronous Python?
03. Operators in Python entry
What can Python do
Join function in Python
print statement in python
How to understand the introduction of packages in Python
How to understand a list of numbers in python
Concurrent requests in Python
Install python in Ubuntu
Consolidate the Python foundation (2)
Context management in Python
Arithmetic operators in python
Write gui in python
MongoDB usage in Python
Str string in Python
For the first time in history, Python surpassed Java!
Computational Geometry in Python