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:
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:
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:
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:
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:
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:
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:
You can access the real and imaginary parts of a complex number using the real
and imag
attributes. For example:
You can perform arithmetic operations on complex numbers using the usual operators. For example:
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:
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 afloat
using thefloat()
function. For example:
Truncation: Truncation removes the decimal part of a number. You can truncate a
Real
number using themath.trunc()
function. For example:
Rounding: Rounding rounds a number to the nearest integer. You can round a
Real
number using theround()
function. For example:
Floor: Floor returns the greatest integer less than or equal to a number. You can floor a
Real
number using themath.floor()
function. For example:
Ceiling: Ceiling returns the least integer greater than or equal to a number. You can ceiling a
Real
number using themath.ceil()
function. For example:
Division and remainder: You can perform division and remainder operations on
Real
numbers using thedivmod()
function. For example:
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:
Modulo: Modulo returns the remainder of two numbers. You can perform modulo on
Real
numbers using the%
operator. For example:
Comparisons: You can compare
Real
numbers using the<
,<=
,>
, and>=
operators. For example:
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 aReal
number is simply the number itself.Imaginary part: The imaginary part of a
Complex
number is the part with thei
in front of it. The imaginary part of aReal
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 aReal
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
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:
The r
object has the following attributes:
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:
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:
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:
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:
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:
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:
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:
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:
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:
Call an implementation that handles both types specifically.
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:
Example Implementation
Here's an example implementation for a custom MyDecimal
class:
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:
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:
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:
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:
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:
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.
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'sfractions
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:
Real World Implementation:
The following code shows how to overload the +
and -
operators for a Fraction
object:
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