# numbers

### Numbers Module in Python

The `numbers` module in Python defines a hierarchy of abstract base classes that represent different types of numbers, such as complex, real, and integral numbers. These classes provide a common interface for representing and manipulating numbers, and are used as base classes for specific numeric types in Python, such as `int`, `float`, and `complex`.

#### Abstract Base Classes

An abstract base class (ABC) is a class that defines a set of abstract methods, which are methods that do not have an implementation. The purpose of an ABC is to define a common interface that can be shared by different classes, while allowing each class to provide its own implementation of the abstract methods.

The `numbers` module defines the following ABCs:

* `Number`: The base class for all numeric types. It defines a single abstract method, `__add__`, which represents addition.
* `Complex`: The class for complex numbers. It defines additional abstract methods for complex arithmetic operations, such as `__mul__` (multiplication) and `__div__` (division).
* `Real`: The class for real numbers. It defines additional abstract methods for real arithmetic operations, such as `__sub__` (subtraction) and `__truediv__` (true division).
* `Integral`: The class for integral numbers. It defines additional abstract methods for integer arithmetic operations, such as `__floordiv__` (floor division) and `__mod__` (modulus).

Here is a simplified example of an abstract base class:

```python
from abc import ABC, abstractmethod

class Shape(ABC):

    @abstractmethod
    def area(self):
        pass

    @abstractmethod
    def perimeter(self):
        pass
```

In this example, the `Shape` class is an ABC that defines two abstract methods, `area` and `perimeter`. Any class that inherits from `Shape` must implement these two methods.

#### Concrete Classes

Concrete classes are classes that implement the abstract methods of an ABC. In the context of the `numbers` module, concrete classes represent specific numeric types, such as `int`, `float`, and `complex`.

Here is an example of a concrete class that inherits from the `Number` ABC:

```python
class Integer(Number):

    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        return Integer(self.value + other)
```

In this example, the `Integer` class inherits from the `Number` ABC and implements the `__add__` method. The `__add__` method defines the addition operation for `Integer` objects.

#### Real-World Applications

The `numbers` module is used in a variety of real-world applications, including:

* **Numeric computation:** The ABCs defined in the `numbers` module provide a common interface for representing and manipulating numbers, which is essential for numeric computation tasks such as scientific simulations and financial modeling.
* **Data validation:** The ABCs can be used to validate that a value is of a specific numeric type. For example, a function that takes a real number as input could use the `Real` ABC to check that the input is a valid real number.
* **Type checking:** The ABCs can be used to check the type of a value at runtime. For example, a function that needs to operate on a list of integers could use the `Integral` ABC to check that each element of the list is an integer.

***

**Number**

In Python, a number is any object that represents a numerical value. This includes integers, floats, and complex numbers. You can check if an object is a number using the `isinstance()` function:

```python
>>> isinstance(123, Number)
True
```

**Integer**

An integer is a whole number, such as 1, 2, or 3. Integers can be positive or negative. You can create an integer using the `int()` function:

```python
>>> int('123')
123
```

**Float**

A float is a decimal number, such as 1.23, 4.56, or 7.89. Floats can be positive or negative. You can create a float using the `float()` function:

```python
>>> float('1.23')
1.23
```

**Complex**

A complex number is a number that has a real part and an imaginary part. The real part is a regular number, and the imaginary part is a number multiplied by the imaginary unit `i`. You can create a complex number using the `complex()` function:

```python
>>> complex(1, 2)
(1+2j)
```

**Applications**

Numbers are used in a wide variety of applications, including:

* Mathematics
* Science
* Engineering
* Finance
* Business

Here are some real-world examples of how numbers are used:

* A scientist might use numbers to calculate the speed of light.
* An engineer might use numbers to design a bridge.
* A financial analyst might use numbers to track the stock market.
* A business owner might use numbers to track sales and expenses.

***

### Numeric Tower

#### Complex

Complex numbers are numbers that have a "real" part and an "imaginary" part. For example, 5+4i is a complex number with real part 5 and imaginary part 4. Complex numbers can be used to represent a wide variety of mathematical concepts, such as rotations in 3D space, quantum states, and wave functions.

The `complex` class in Python represents complex numbers. You can create a complex number by calling the `complex` function, passing in the real and imaginary parts as arguments. For example:

```
>>> z = complex(5, 4)
>>> z
(5+4j)
```

You can access the real and imaginary parts of a complex number using the `real` and `imag` attributes. For example:

```
>>> z.real
5
>>> z.imag
4
```

You can perform arithmetic operations on complex numbers using the usual operators. For example:

```
>>> z1 = complex(1, 2)
>>> z2 = complex(3, 4)
>>> z1 + z2
(4+6j)
>>> z1 - z2
(-2-2j)
>>> z1 * z2
(-5+10j)
>>> z1 / z2
(0.4444444444444444-0.2222222222222222j)
>>> z1 ** z2
(0.3678794411714423-0.9302847925323812j)
```

You can also use the `abs()` function to find the absolute value of a complex number, and the `conjugate()` method to find the complex conjugate. For example:

```
>>> abs(z1)
2.23606797749979
>>> z1.conjugate()
(1-2j)
```

Complex numbers are often used in science and engineering to represent physical quantities that have both a magnitude and a direction. For example, complex numbers can be used to represent the voltage and current in an electrical circuit, or the position and momentum of a particle in quantum mechanics.

***

**Real**

**Definition:** The `Real` class in Python is a subclass of the `Complex` class that represents real numbers. Real numbers are numbers that can be written without an imaginary part, such as 5 or -2.3.

**Operations:** `Real` adds the following operations to those provided by `Complex`:

* **Conversion to float:** You can convert a `Real` number to a `float` using the `float()` function. For example:

```
>>> x = Real(5)
>>> float(x)
5.0
```

* **Truncation:** Truncation removes the decimal part of a number. You can truncate a `Real` number using the `math.trunc()` function. For example:

```
>>> x = Real(5.4)
>>> math.trunc(x)
5
```

* **Rounding:** Rounding rounds a number to the nearest integer. You can round a `Real` number using the `round()` function. For example:

```
>>> x = Real(5.4)
>>> round(x)
5
```

* **Floor:** Floor returns the greatest integer less than or equal to a number. You can floor a `Real` number using the `math.floor()` function. For example:

```
>>> x = Real(5.4)
>>> math.floor(x)
5
```

* **Ceiling:** Ceiling returns the least integer greater than or equal to a number. You can ceiling a `Real` number using the `math.ceil()` function. For example:

```
>>> x = Real(5.4)
>>> math.ceil(x)
6
```

* **Division and remainder:** You can perform division and remainder operations on `Real` numbers using the `divmod()` function. For example:

```
>>> x = Real(5)
>>> y = Real(2)
>>> divmod(x, y)
(2, 1)
```

* **Integer division:** Integer division returns the quotient of two numbers, rounded towards negative infinity. You can perform integer division on `Real` numbers using the `//` operator. For example:

```
>>> x = Real(5)
>>> y = Real(2)
>>> x // y
2
```

* **Modulo:** Modulo returns the remainder of two numbers. You can perform modulo on `Real` numbers using the `%` operator. For example:

```
>>> x = Real(5)
>>> y = Real(2)
>>> x % y
1
```

* **Comparisons:** You can compare `Real` numbers using the `<`, `<=`, `>`, and `>=` operators. For example:

```
>>> x = Real(5)
>>> y = Real(2)
>>> x > y
True
```

**Defaults:** `Real` also provides defaults for the following attributes and methods of `Complex`:

* **Real part:** The real part of a `Complex` number is the part without the imaginary part. The real part of a `Real` number is simply the number itself.
* **Imaginary part:** The imaginary part of a `Complex` number is the part with the `i` in front of it. The imaginary part of a `Real` number is always 0.
* **Conjugate:** The conjugate of a `Complex` number is the number with the same real part but the opposite imaginary part. The conjugate of a `Real` number is the number itself.

**Real World Applications**

Real numbers are used in a wide variety of applications, including:

* **Science:** Real numbers are used to measure physical quantities such as distance, speed, and temperature.
* **Engineering:** Real numbers are used to design and build structures, machines, and systems.
* **Finance:** Real numbers are used to track and manage money.
* **Medicine:** Real numbers are used to measure and track vital signs and other medical data.

***

#### Class :class:`Rational`

The `Rational` class in the "numbers" module is a subclass of the `Real` class and represents rational numbers, which are numbers that can be expressed as a fraction of two integers. Rational numbers can be used to represent exact values, such as 1/2 or 3/4, or they can be used to approximate real numbers, such as pi or the square root of 2.

The `Rational` class has two attributes: `numerator` and `denominator`. The `numerator` attribute stores the numerator of the rational number, and the `denominator` attribute stores the denominator. The `numerator` and `denominator` attributes must be instances of the `Integral` class, and they must be in lowest terms, with the `denominator` positive.

The following code creates a `Rational` object representing the rational number 1/2:

```python
from numbers import Rational

r = Rational(1, 2)
```

The `r` object has the following attributes:

```
r.numerator == 1
r.denominator == 2
```

The `Rational` class also provides a `float()` method that returns the floating-point representation of the rational number. The following code prints the floating-point representation of the `r` object:

```python
print(float(r))

# Output: 0.5
```

Rational numbers are useful for representing quantities that are exact or that need to be represented precisely. For example, rational numbers can be used to represent the amount of money in a bank account or the length of a piece of wood.

Here is an example of how rational numbers can be used in a real-world application:

```python
from numbers import Rational

# Create a rational number representing the amount of money in a bank account.
balance = Rational(100, 1)

# Withdraw $20 from the account.
withdrawal = Rational(20, 1)
balance -= withdrawal

# Print the remaining balance.
print(balance)

# Output: 80/1
```

In this example, we create a `Rational` object representing the balance in a bank account. We then withdraw $20 from the account by subtracting a `Rational` object representing the withdrawal amount from the `balance` object. Finally, we print the remaining balance, which is represented as a rational number.

***

**Integral**

The `Integral` class, which includes `Rational` as a subclass, brings a few additional features to the world of numbers in Python. Let's dive into them one by one:

**Conversion to Integer**:

This class allows you to convert a rational number to an integer, making it easier to represent whole numbers with more precision. For example:

```python
>>> from fractions import Fraction
>>> rational_number = Fraction(3, 4)
>>> integer_number = int(rational_number)
>>> print(integer_number)
0
```

In this case, we convert the rational number 3/4 to its integer equivalent, which is 0.

**Default Values**:

The `Integral` class provides default values for some properties:

* **float**: Returns the floating-point representation of the rational number.
* **numerator**: The numerator of the rational number.
* **denominator**: The denominator of the rational number.

For example:

```python
>>> from fractions import Fraction
>>> rational_number = Fraction(3, 4)
>>> print(rational_number.float)
0.75
>>> print(rational_number.numerator)
3
>>> print(rational_number.denominator)
4
```

**Abstract Methods**:

The `Integral` class also introduces abstract methods, which are like placeholders for methods that must be implemented in subclasses. These methods include:

* **pow(self, other, modulus=None)**: Raises the rational number to the power of `other`, with optional modulus.
* **lshift(self, other)**: Shifts the bits of the rational number left by `other` positions.
* **rshift(self, other)**: Shifts the bits of the rational number right by `other` positions.
* **and(self, other)**: Performs bitwise AND operation with `other`.
* **xor(self, other)**: Performs bitwise XOR operation with `other`.
* **or(self, other)**: Performs bitwise OR operation with `other`.
* **invert(self)**: Performs bitwise NOT operation.

**Real-World Applications**:

Here are some potential applications of these features in real-world scenarios:

* Financial calculations: Fraction objects can be used to represent and manipulate currency values and percentages.
* Scientific computations: Rational numbers can represent exact values, which is important for applications that require precision.
* Cryptography: Bitwise operations are commonly used in cryptographic algorithms to encrypt and decrypt messages.
* Computer graphics: Bit shifting is used to manipulate images and animations.
* Software engineering: Integer conversion can be useful for representing numbers in a compact form.

***

**Hashing and Equality for Custom Types in Python**

When you create your own custom types in Python, it's important to consider how they are handled by equality checks and hashing.

**Equality Checks**

For two objects to be considered equal, they must have the same value. For custom types, this means implementing the `__eq__` method. For example:

```python
class Fraction:
    def __init__(self, numerator, denominator):
        self.numerator = numerator
        self.denominator = denominator

    def __eq__(self, other):
        return self.numerator == other.numerator and self.denominator == other.denominator
```

**Hashing**

Hashing is used to determine the location of an object in a hash table, a data structure that stores key-value pairs. For custom types, this means implementing the `__hash__` method.

**Potential Collisions**

When hashing objects, it's possible that two different objects have the same hash value. This is known as a collision. To minimize collisions, the hash value should be as unique as possible.

**Example: Implementing Hashing for `Fraction`**

The following example shows how to implement hashing for the `Fraction` class:

```python
import math

class Fraction:
    def __init__(self, numerator, denominator):
        self.numerator = numerator
        self.denominator = denominator

    def __eq__(self, other):
        return self.numerator == other.numerator and self.denominator == other.denominator

    def __hash__(self):
        # Fast hash for integers
        if self.denominator == 1:
            return hash(self.numerator)

        # Use the built-in hash function for floating-point values
        if math.isclose(self, float(self)):
            return hash(float(self))

        # Fallback to a slower but more reliable hash
        return hash((self.numerator, self.denominator))
```

**Real-World Applications**

Hashing and equality checks are used in various real-world applications, such as:

* **Databases:** To efficiently store and retrieve data based on keys.
* **Hash tables:** To accelerate lookups in large datasets.
* **Sets:** To check if an element is present in a collection without duplicates.

***

**Adding More Numeric ABCs**

In the hierarchy of numeric types in Python, there are several abstract base classes (ABCs) that define the behavior of different numeric types. These ABCs include:

* **Number:** The base ABC for all numeric types.
* **Real:** The ABC for real numbers, including integers, floats, and decimals.
* **Complex:** The ABC for complex numbers.

You can add your own custom ABCs to this hierarchy by subclassing one of the existing ABCs and registering your new ABC with the existing ABC. For example, if you wanted to create a new ABC called **MyFoo** that represents a type of number that is a subclass of **Complex**, you would do the following:

```python
class MyFoo(Complex):
    ...

MyFoo.register(Real)
```

This would create a new **MyFoo** ABC that is a subclass of **Complex** and a subclass of **Real**.

**Real-world Application:**

Customizing the numeric ABC hierarchy can be useful in a number of scenarios. For example, you could create a new ABC to represent a type of number that has specific properties or operations that are not supported by the existing ABCs. This could be useful in specialized domains, such as financial modeling or scientific computing.

**Improved Code Snippet:**

Here is an improved version of the code snippet that adds the **MyFoo** ABC to the numeric ABC hierarchy:

```python
class MyFoo(Complex):
    def __init__(self, real, imaginary):
        super().__init__(real, imaginary)

    def my_foo_method(self):
        ...

MyFoo.register(Real)
```

This code creates a new **MyFoo** class that inherits from the **Complex** class and implements a custom **my\_foo\_method** method. The **MyFoo** class is then registered with the **Real** ABC using the **register** method.

***

### Implementing Arithmetic Operations

In Python, we can implement arithmetic operations, like addition, subtraction, multiplication, and division, for our custom data types.

#### Mixed-Mode Operations

When dealing with different types of numbers (mixed-mode operations), we want to:

1. Call an implementation that handles both types specifically.
2. If not available, convert both numbers to the closest built-in type (e.g., int or float) and perform the operation there.

#### Integral Subtypes

For subtypes of `Integral`, which represent whole numbers, we can define `__add__` and `__radd__` methods like this:

```python
class MyIntegral(Integral):

    def __add__(self, other):
        if isinstance(other, MyIntegral):
            # Both are our type, use a specific implementation
            return MyIntegral(self.value + other.value)
        else:
            # Convert both to int and perform the operation
            return int(self) + int(other)
```

#### Example Implementation

Here's an example implementation for a custom `MyDecimal` class:

```python
from decimal import Decimal

class MyDecimal(Decimal):

    def __add__(self, other):
        if isinstance(other, MyDecimal):
            return MyDecimal(self.as_tuple()[0] + other.as_tuple()[0])
        else:
            return float(self) + float(other)
```

#### Real-World Applications

These arithmetic operations are used in various real-world scenarios, such as:

* Financial calculations: Mixing currency types and converting to the appropriate exchange rates.
* Scientific calculations: Dealing with different units of measurement and converting between them.
* Custom data analysis: Creating specialized numeric types that handle specific data formats or constraints.

***

**Magic methods** or **dunder methods** are special methods in Python that are called automatically when specific operations are performed on an object.

The `__add__` method is called when the `+` operator is used on an object. In the provided code, the `__add__` method of the `MyIntegral` class is defined to handle addition with other `MyIntegral` objects, `OtherTypeIKnowAbout` objects, and primitive types like `int`, `float`, and `complex`. If the other object is not recognized, the method returns `NotImplemented`.

Here's a simplified example to illustrate the `__add__` method in action:

```python
class MyIntegral:
    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        if isinstance(other, MyIntegral):
            return MyIntegral(self.value + other.value)
        else:
            raise TypeError("Cannot add MyIntegral with non-MyIntegral object")

i1 = MyIntegral(10)
i2 = MyIntegral(20)

result = i1 + i2
print(result.value)  # Output: 30
```

In this example, we define a simple `MyIntegral` class that represents an integral value. The `__add__` method is defined to handle addition with other `MyIntegral` objects. When we add `i1` and `i2`, the `__add__` method is called and returns a new `MyIntegral` object with the sum of the two values.

The `__radd__` method is similar to `__add__`, but it is called when the `+` operator is used on an object of the class from the right-hand side. In the provided code, the `__radd__` method of the `MyIntegral` class is defined to handle addition with `MyIntegral` objects, `OtherTypeIKnowAbout` objects, `Integral` objects, `Real` objects, and `Complex` objects. If the other object is not recognized, the method returns `NotImplemented`.

Here's an example to illustrate the `__radd__` method:

```python
class MyIntegral:
    def __init__(self, value):
        self.value = value

    def __radd__(self, other):
        if isinstance(other, MyIntegral):
            return MyIntegral(self.value + other.value)
        else:
            raise TypeError("Cannot add MyIntegral with non-MyIntegral object")

i1 = MyIntegral(10)
i2 = 20

result = i2 + i1
print(result.value)  # Output: 30
```

In this example, we add a `MyIntegral` object (`i1`) with a primitive integer (`i2`). The `__radd__` method of the `MyIntegral` class is called automatically and returns a new `MyIntegral` object with the sum of the two values.

**Potential applications** of magic methods include:

* Defining custom behavior for arithmetic operators, such as addition, subtraction, multiplication, and division.
* Defining custom behavior for comparison operators, such as equality, inequality, greater than, and less than.
* Defining custom behavior for other operations, such as hashing, converting to a string, or iterating over the object.

***

**Mixed-Type Operations on Complex Subclasses**

**Introduction**

The Python `numbers` module provides a framework for defining numeric types that behave consistently in mathematical operations. When you define a new numeric type, you can choose to implement methods like `__add__` (`+`) and `__radd__` (`+=`) to define how your type behaves when it's involved in mathematical operations with other types.

**Cases for Mixed-Type Operations**

When defining mixed-type operations involving subclasses of `Complex`, there are five potential cases to consider:

**Case 1: Specific Implementation in Subclass**

If a subclass of `Complex` (e.g., `A`) defines a specific implementation for `__add__` that accepts the other type (e.g., `B`), everything works as expected.

**Example:**

```python
class A(Complex):
    def __add__(self, other):
        if isinstance(other, B):
            # Custom logic for A + B
            pass
```

**Case 2: Fallback to Boilerplate Code**

If `A` doesn't define `__add__` or returns `NotImplemented`, the Python interpreter falls back to a "boilerplate" implementation that checks if the other type (e.g., `B`) defines `__radd__`.

**Case 3: Specific Implementation in Other Type**

If `B` defines a specific implementation for `__radd__` that accepts `A`, everything works as expected.

**Example:**

```python
class B(Complex):
    def __radd__(self, other):
        if isinstance(other, A):
            # Custom logic for B + A
            pass
```

**Case 4: Default Implementation in Boilerplate Code**

If neither `A` nor `B` define specific implementations, the default implementation in the boilerplate code is used.

**Example:**

```python
def __add__(self, other):
    return NotImplemented  # Trigger radd() method

def __radd__(self, other):
    return other + self  # Default implementation
```

**Case 5: Subclass Relationship**

If `B` is a subclass of `A` (e.g., `B <: A`), Python will first try `B.__radd__` before `A.__add__`. This is because `B` might have more specific logic for handling instances of `A`.

**Real-World Example**

Suppose you want to define a custom numeric type called `MyIntegral`. You might implement the `__add__` method to handle operations with other `MyIntegral` instances and return `NotImplemented` for operations with other types.

```python
class MyIntegral:
    def __add__(self, other):
        if isinstance(other, MyIntegral):
            # Custom logic for MyIntegral + MyIntegral
            pass
        else:
            return NotImplemented
```

When you then try to add a `MyIntegral` instance with a `Complex` instance, the boilerplate code will trigger `Complex.__radd__` and the default implementation will be used.

**Potential Applications**

Mixed-type operations allow you to define custom numeric types that can interact with built-in numeric types like `Complex`. This can be useful in areas like numerical simulation, physics, or financial modeling.

***

**Topic 1: Operator Overloading**

* **Concept:** Python allows you to define custom operators for your objects, such as `+`, `-`, or `*`.
* **Simplified Explanation:** Imagine a magical calculator that understands your own operations, like "combine" instead of "add."

**Topic 2: Forward and Reverse Operators**

* **Concept:** When you overload an operator, you need to define two versions: a forward operator (e.g., `__add__`) and a reverse operator (e.g., `__radd__`).
* **Simplified Explanation:** The forward operator is called when your object is on the left side of the operation (e.g., `a + b`) and the reverse operator is called when your object is on the right side (e.g., `b + a`).

**Topic 3: Helper Function for Operators**

* **Concept:** The `_operator_fallbacks` helper function in Python's `fractions` module automatically generates both the forward and reverse operators for you.
* **Simplified Explanation:** It's like a magic wand that saves you from writing redundant code.

**Code Snippet:**

```python
def _operator_fallbacks(monomorphic_operator, fallback_operator):
    def forward(a, b):
        # Forward version
        ...

    def reverse(b, a):
        # Reverse version
        ...

    return forward, reverse
```

**Real World Implementation:**

The following code shows how to overload the `+` and `-` operators for a `Fraction` object:

```python
class Fraction:
    def __init__(self, numerator, denominator):
        self.numerator = numerator
        self.denominator = denominator

    def __add__(self, other):
        # Forward version
        return Fraction(self.numerator * other.denominator +
                        other.numerator * self.denominator,
                        self.denominator * other.denominator)

    def __radd__(self, other):
        # Reverse version
        return Fraction(other.numerator * self.denominator +
                        self.numerator * other.denominator,
                        other.denominator * self.denominator)

    def __sub__(self, other):
        # Forward version
        return Fraction(self.numerator * other.denominator -
                        other.numerator * self.denominator,
                        self.denominator * other.denominator)

    def __rsub__(self, other):
        # Reverse version
        return Fraction(other.numerator * self.denominator -
                        self.numerator * other.denominator,
                        other.denominator * self.denominator)
```

**Potential Applications:**

* Simplifying mathematical operations with custom types
* Creating specialized calculators for specific domains (e.g., financial calculations)
* Data analysis and modeling with custom data structures


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://a7246c5516ab4c80cdfe21ca2be3e40c.gitbook.io/python-docs/numbers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
