# The Integer Class int

In the previous tutorials text datatypes were explored such as the Immutable Unicode string, Immutable byte string and Mutable byte string the bytearray. These text datatypes were based upon the object class and were seen to have consistent data model identifiers. Python also has a number of numeric datatypes, this tutorial will focus on the immutable integer, which is a full number.

## Dot Attributes and the Decimal Point

When the text datatypes were explored a dot . was used to access attributes. For example:

``greeting = 'hello'``

And inputting:

``greeting.upper()``
``'HELLO'``

An attribute can also be accessed directly from an instance without using an instance name:

``' '.join(['the', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog'])``
``'the quick brown fox jumps over the lazy dog'``

For numeric datatypes attributes can still be accessed from the instance name:

``num = 99``

For example:

``num.to_bytes()``
``b'c'``

However if a dot attribute is attempted to be used from an integer, the dot is recognised by Python as a decimal point and instead of looking up an attribute for the integer 99, invalid characters are found following the decimal point in the floating point number 99.

``99.to_bytes()``
``SyntaxError: invalid decimal literal``

As a consequence to the above, most of the identifiers used with numeric values are data model identifiers which typically map to numeric operators. Details about these identifiers can be seen when examining the help for the int class:

``help(int)``
``````Help on class int in module builtins:

class int(object)
|  int([x]) -> integer
|  int(x, base=10) -> integer
|
|  Convert a number or string to an integer, or return 0 if no arguments
|  are given.  If x is a number, return x.__int__().  For floating point
|  numbers, this truncates towards zero.
|
|  If x is not a number or if base is given, then x must be a string,
|  bytes, or bytearray instance representing an integer literal in the
|  given base.  The literal can be preceded by '+' or '-' and be surrounded
|  by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
|  Base 0 means to interpret the base from the string as an integer literal.
|  >>> int('0b100', base=0)
|  4
|
|  Built-in subclasses:
|      bool
|
|  Methods defined here:
|
|  __abs__(self, /)
|      abs(self)
|
|      Return self+value.
|
|  __and__(self, value, /)
|      Return self&value.
|
|  __bool__(self, /)
|      True if self else False
|
|  __ceil__(...)
|      Ceiling of an Integral returns itself.
|
|  __divmod__(self, value, /)
|      Return divmod(self, value).
|
|  __eq__(self, value, /)
|      Return self==value.
|
|  __float__(self, /)
|      float(self)
|
|  __floor__(...)
|      Flooring an Integral returns itself.
|
|  __floordiv__(self, value, /)
|      Return self//value.
|
|  __format__(self, format_spec, /)
|      Default object formatter.
|
|  __ge__(self, value, /)
|      Return self>=value.
|
|  __getattribute__(self, name, /)
|      Return getattr(self, name).
|
|  __getnewargs__(self, /)
|
|  __gt__(self, value, /)
|      Return self>value.
|
|  __hash__(self, /)
|      Return hash(self).
|
|  __index__(self, /)
|      Return self converted to an integer, if self is suitable for use as an index into a list.
|
|  __int__(self, /)
|      int(self)
|
|  __invert__(self, /)
|      ~self
|
|  __le__(self, value, /)
|      Return self<=value.
|
|  __lshift__(self, value, /)
|      Return self<<value.
|
|  __lt__(self, value, /)
|      Return self<value.
|
|  __mod__(self, value, /)
|      Return self%value.
|
|  __mul__(self, value, /)
|      Return self*value.
|
|  __ne__(self, value, /)
|      Return self!=value.
|
|  __neg__(self, /)
|      -self
|
|  __or__(self, value, /)
|      Return self|value.
|
|  __pos__(self, /)
|      +self
|
|  __pow__(self, value, mod=None, /)
|      Return pow(self, value, mod).
|
|      Return value+self.
|
|  __rand__(self, value, /)
|      Return value&self.
|
|  __rdivmod__(self, value, /)
|      Return divmod(value, self).
|
|  __repr__(self, /)
|      Return repr(self).
|
|  __rfloordiv__(self, value, /)
|      Return value//self.
|
|  __rlshift__(self, value, /)
|      Return value<<self.
|
|  __rmod__(self, value, /)
|      Return value%self.
|
|  __rmul__(self, value, /)
|      Return value*self.
|
|  __ror__(self, value, /)
|      Return value|self.
|
|  __round__(...)
|      Rounding an Integral returns itself.
|
|      Rounding with an ndigits argument also returns an integer.
|
|  __rpow__(self, value, mod=None, /)
|      Return pow(value, self, mod).
|
|  __rrshift__(self, value, /)
|      Return value>>self.
|
|  __rshift__(self, value, /)
|      Return self>>value.
|
|  __rsub__(self, value, /)
|      Return value-self.
|
|  __rtruediv__(self, value, /)
|      Return value/self.
|
|  __rxor__(self, value, /)
|      Return value^self.
|
|  __sizeof__(self, /)
|      Returns size in memory, in bytes.
|
|  __sub__(self, value, /)
|      Return self-value.
|
|  __truediv__(self, value, /)
|      Return self/value.
|
|  __trunc__(...)
|      Truncating an Integral returns itself.
|
|  __xor__(self, value, /)
|      Return self^value.
|
|  as_integer_ratio(self, /)
|      Return integer ratio.
|
|      Return a pair of integers, whose ratio is exactly equal to the original int
|      and with a positive denominator.
|
|      >>> (10).as_integer_ratio()
|      (10, 1)
|      >>> (-10).as_integer_ratio()
|      (-10, 1)
|      >>> (0).as_integer_ratio()
|      (0, 1)
|
|  bit_count(self, /)
|      Number of ones in the binary representation of the absolute value of self.
|
|      Also known as the population count.
|
|      >>> bin(13)
|      '0b1101'
|      >>> (13).bit_count()
|      3
|
|  bit_length(self, /)
|      Number of bits necessary to represent self in binary.
|
|      >>> bin(37)
|      '0b100101'
|      >>> (37).bit_length()
|      6
|
|  conjugate(...)
|      Returns self, the complex conjugate of any int.
|
|  to_bytes(self, /, length=1, byteorder='big', *, signed=False)
|      Return an array of bytes representing an integer.
|
|      length
|        Length of bytes object to use.  An OverflowError is raised if the
|        integer is not representable with the given number of bytes.  Default
|        is length 1.
|      byteorder
|        The byte order used to represent the integer.  If byteorder is 'big',
|        the most significant byte is at the beginning of the byte array.  If
|        byteorder is 'little', the most significant byte is at the end of the
|        byte array.  To request the native byte order of the host system, use
|        `sys.byteorder' as the byte order value.  Default is to use 'big'.
|      signed
|        Determines whether two's complement is used to represent the integer.
|        If signed is False and a negative integer is given, an OverflowError
|        is raised.
|
|  ----------------------------------------------------------------------
|  Class methods defined here:
|
|  from_bytes(bytes, byteorder='big', *, signed=False) from builtins.type
|      Return the integer represented by the given array of bytes.
|
|      bytes
|        Holds the array of bytes to convert.  The argument must either
|        support the buffer protocol or be an iterable object producing bytes.
|        Bytes and bytearray are examples of built-in objects that support the
|        buffer protocol.
|      byteorder
|        The byte order used to represent the integer.  If byteorder is 'big',
|        the most significant byte is at the beginning of the byte array.  If
|        byteorder is 'little', the most significant byte is at the end of the
|        byte array.  To request the native byte order of the host system, use
|        `sys.byteorder' as the byte order value.  Default is to use 'big'.
|      signed
|        Indicates whether two's complement is used to represent the integer.
|
|  ----------------------------------------------------------------------
|  Static methods defined here:
|
|  __new__(*args, **kwargs) from builtins.type
|      Create and return a new object.  See help(type) for accurate signature.
|
|  ----------------------------------------------------------------------
|  Data descriptors defined here:
|
|  denominator
|      the denominator of a rational number in lowest terms
|
|  imag
|      the imaginary part of a complex number
|
|  numerator
|      the numerator of a rational number in lowest terms
|
|  real
|      the real part of a complex number``````

Notice that the return value shown above for each data model method shows how the function is typically invoked using a Python builtins function or operator.

The __getattribute__ data model defines the behaviour of the getattr builtins function which can be used to retrieve an attribute from an integer:

``getattr(99, 'numerator')``
``99``

This can also be used to call a method, were the second set of brackets are used to call the method and provide any input arguments:

``getattr(99, 'as_integer_ratio')()``
``(99, 1)``

## Initialisation

Inputting int() will display the docstring of the initialisation signature of the integer class as a popup balloon. Some IDEs such as JupyterLab may require the keypress shift ⇧ and tab ↹ to invoke the docstring:

```Init signature:  int(self, /, *args, **kwargs)
Docstring:
int([x]) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4
Type:           type
Subclasses:     bool, IntEnum, IntFlag, _NamedIntConstant, Handle```

An integer can be instantiated using:

``````num = int(99)
num``````
``99``

However since the integer is a fundamental datatype it is usually abbreviated as:

``````num = 99
num``````
``99``

An integer can also be created using a string:

``````num = int('99', base=10)
num``````
``99``

If the base is not specified, it is assumed to be 10:

``````num = int('99')
num``````
``99``

Recall that Hexadecimal values use the base 16.

``hex(99)``
``'0x63'``

The hexadecimal string can be cast into an integer using:

``````num = int('0x63', base=16)
num``````
``99``

## Identifiers

A list of identifiers can be seen from an integer instance:

• as_integer_ratio
• bit_count
• bit_length
• conjugate
• denominator
• from_bytes
• imag
• numerator
• real
• to_bytes

These are grouped into fraction related identifiers:

• numerator
• denominator
• as_integer_ratio

numerator and denominator are data descriptors which match the integer and are 1 respectively making the integer compatible with the Fraction class:

``num.numerator``
``99``
``num.denominator``
``1``

The integer ratio returns the numerator and denominator within a tuple:

```Signature:  num.as_integer_ratio()
Docstring:
Return integer ratio.

Return a pair of integers, whose ratio is exactly equal to the original int
and with a positive denominator.

>>> (10).as_integer_ratio()
(10, 1)
>>> (-10).as_integer_ratio()
(-10, 1)
>>> (0).as_integer_ratio()
(0, 1)
Type:      builtin_function_or_method```
``num.as_integer_ratio()``
``(99, 1)``

Complex number related identifiers:

• real
• imag
• conjugate

real and imag are data descriptors which match the integer and are 0 respectively making the integer compatible with the complex class:

``num.real``
``99``
``num.imag``
``0``

The complex conjugate, returns the real value and reverses the sign of the negative value; since this is 0, the number returned is unchanged:

```Docstring: Returns self, the complex conjugate of any int.
Type:      builtin_function_or_method```
``num.conjugate()``
``99``

And byte related identifiers:

• from_bytes
• to_bytes
• bit_count
• bit_length

from_bytes is an alternative constructor:

```Signature:  int.from_bytes(bytes, byteorder='big', *, signed=False)
Docstring:
Return the integer represented by the given array of bytes.

bytes
Holds the array of bytes to convert.  The argument must either
support the buffer protocol or be an iterable object producing bytes.
Bytes and bytearray are examples of built-in objects that support the
buffer protocol.
byteorder
The byte order used to represent the integer.  If byteorder is 'big',
the most significant byte is at the beginning of the byte array.  If
byteorder is 'little', the most significant byte is at the end of the
byte array.  To request the native byte order of the host system, use
`sys.byteorder' as the byte order value.  Default is to use 'big'.
signed
Indicates whether two's complement is used to represent the integer.
Type:      builtin_function_or_method```

The byte string b'hello' can be converted to an integer using:

``int.from_bytes(b'hello', byteorder='big')``
``448378203247``

This can manually be calculated using the ordinal values for each character multiplied by powers of 256 (highest power to the right hand side – big endian):

``(ord('h') * 256 ** 4) + (ord('e') * 256 ** 3) + (ord('l') * 256 ** 2)  + (ord('l') * 256 ** 1) + (ord('o') * 256 ** 0)``
``448378203247``

For a little byteorder:

``int.from_bytes(b'hello', byteorder='little')``
``478560413032``
``(ord('h') * 256 ** 0) + (ord('e') * 256 ** 1) + (ord('l') * 256 ** 2)  + (ord('l') * 256 ** 3) + (ord('o') * 256 ** 4)``
``478560413032``

An unsigned byte ranges between 0 to 256, the mid value 128 can be examined:

``hex(128)``
``'0x80'``

If the byte is signed this range is split between negative and positive values ranging from -128 to +128. The first 128 values (which incorporate the ASCII characters) are unchanged, the next 128 values take on positive values to 256 if unsigned or negative values if signed:

``int.from_bytes(b'\x80', byteorder='big', signed=False)``
``128``
``int.from_bytes(b'\x80', byteorder='big', signed=True)``
``-128``

The to_bytes method is the reverse method and can be used to cast an integer into a bytes:

``num = 448378203247``

It requires the length f the bytearray to be supplied as an input argument:

```Signature:  num.to_bytes(length=1, byteorder='big', *, signed=False)
Docstring:
Return an array of bytes representing an integer.

length
Length of bytes object to use.  An OverflowError is raised if the
integer is not representable with the given number of bytes.  Default
is length 1.
byteorder
The byte order used to represent the integer.  If byteorder is 'big',
the most significant byte is at the beginning of the byte array.  If
byteorder is 'little', the most significant byte is at the end of the
byte array.  To request the native byte order of the host system, use
`sys.byteorder' as the byte order value.  Default is to use 'big'.
signed
Determines whether two's complement is used to represent the integer.
If signed is False and a negative integer is given, an OverflowError
is raised.
Type:      builtin_function_or_method```
``num.to_bytes(length=5, byteorder='big', signed=False)``
``b'hello'``

Trailing zeros will be displayed if the length specified is larger:

``num.to_bytes(length=25, byteorder='big', signed=False)``
``b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00hello'``

An OverflowError will display if the int is too big for the specified length:

``num.to_bytes(length=1, byteorder='big', signed=False)``
``OverflowError: int too big to convert``

The bit_length method returns the number of bits required to represent a number in binary:

```Signature:  num.bit_length()
Docstring:
Number of bits necessary to represent self in binary.

>>> bin(37)
'0b100101'
>>> (37).bit_length()
6
Type:      builtin_function_or_method```

For example:

``num = 19``

The binary representation of the number is:

``bin(19)``
``'0b10011'``

There are 5 bits (shown after the 0b prefix):

``num.bit_length()``
``5``

The bit_count, returns the number of these bits which have a value of 1:

```Signature:  num.bit_count()
Docstring:
Number of ones in the binary representation of the absolute value of self.

Also known as the population count.

>>> bin(13)
'0b1101'
>>> (13).bit_count()
3
Type:      builtin_function_or_method```

In the example 3 of the values are 1:

``num.bit_count()``
``3``

## Data Model Identifiers

The data model identifier __hash__ is defined for an integer, because an integer is hashable, the hash value is the integer itself:

``hash(1)``
``1``

This means an integer can be used as a key in a mapping for example:

``mapping = {1: 'one', 2: 'two', 3: 'three'}``

And the value can be indexed using the integer key:

``mapping[1]``
``'one'``

The data model method __index__ is also defined, meaning an integer can be used to index into a collection such as a Unicode string:

``````greeting = 'hello'
greeting[1]``````
``'e'``

The formal representation of a string __repr__ is also defined:

``repr(num)``
``'19'``

Note because only the formal string representation __repr__ is defined, the informal string representation __str__ will behave identically:

``str(num)``
``'19'``

The data model __format__ is defined which means the integer can be used in a formatted string, such as an fstring:

``f'The number is {num}'``
``'The number is 19'``
``f'The number is {num:03d}'``
``'The number is 019'``
``f'The number is {num:3d}'``
``'The number is 19'``

The __getnewargs__ data model identifier is used by the pickle module to pickle an integer into a byte string for transfer of data for example over a serial port:

``````import pickle
pickle.dumps(num)``````
``b'\x80\x04K\x13.'``

the pickled byte sequence contains details about the pickle protocol and uses the hex value of the integer:

``hex(13)``
``'0x13'``

## Unitary Data Model Identifiers

The unitary operator __pos__ defines the behaviour of the + operator. This returns the number unchanged:

``+num``
``19``

The unitary operator __neg__ defines the behaviour when the – operator. The returned number has an inverted sign:

``-num``
``-19``

The unitary operator __abs__ defines the behaviour of the builtins function abs. The returned number is stripped of the sign:

``abs(num)``
``19``
``abs(-num)``
``19``

The unitary operator __invert__ returns the ones complement:

``~num``
``-20``

If the ones complement is assigned to a variable:

``complement = ~num``

Then num and complement can be converted to bytes and displayed in hex:

``num.to_bytes(length=2, byteorder='big', signed=True).hex()``
``'0013'``
``inverted.to_bytes(length=2, byteorder='big', signed=True).hex()``
`'ffec'`

Essentially the following hex characters are switched in the hex complement:

## Rounding Data Model Identifiers

The data model identifiers __round__, __floor__, __ceil__, __trunc__ define the behaviour behind the builtins function round and the math functions ceil, floor and trunc. These rounding functions are used to round other numeric data types to an integer and in the case of an integer just return a copy of the integer.

``round(num)``
``19``
``````import math
math.floor(num)``````
``19``
``math.ceil(num)``
``19``
``math.trunc(num)``
``19``

## Casting Data Model Identifiers

The __int__ data model identifier defines the behaviour when an integer is cast to an integer using the builtins int class. Since it is originally an integer, the returned integer has the same value:

``int(num)``
``19``

The __bool__ data model identifier defines the behaviour when an integer is cast to a bool using the builtins bool class. All non-zero values are True and a zero value is False:

``bool(num)``
``True``

The __float__ data model identifier defines the behaviour when an integer is cast to a float using the builtins float class. Notice the inclusion of the decimal point in the output:

``float(num)``
``19.0``

## Binary Data Model Identifiers

Binary data model identifiers are designed to work between two instances.

The instance the operator is called from is known as self and the other instance is known as value. If the data model identifier was to be called directly it would be used with the following syntax:

``self.__add__(value)``

More typically, the operator is used:

``self + value``

Notice the instance the method is being called from self is on the left hand side of the operator and the other instance value is on the right hand side. There are a number of reverse data model methods which complement the above and describe what to do when the order is reversed:

The reverse data model identifiers are typically invoked when the instances surrounding the operator are different class types. For example an integer can be used to replicate a string. The int data model identifier __mul__ will be used for the following operation (self is 2 and is on the left hand side of the * operator):

``2 * 'hello'``
``'hellohello'``

The int data model operator __rmul__ will instead be used for the following operation (self is 2 and is on the right hand side of the * operator):

``'hello' * 2``
``'hellohello'``

To use these, two instances will need to be created:

``````num1 = 19
num2 = 52``````

Addition of two integers can be returned:

``num1 + num2``
``71``

Subtraction of two integers can be returned:

``num1 - num2``
``-33``

Multiplication of two integers can be returned:

``num1 * num2``
``988``

Exponentiation (raising one integer to the power of another integer) of two integers can be returned:

``num1 ** num2``
``3127427491907749548018497790443751608857168317658177523074947729361``

Integer Division of two integers can be returned:

``num2 // num1``
``2``

The associated Modulo of two integers can be returned (this is the integer remainder):

``num2 % num1``
``14``

And therefore, the following equals num2:

``num1 * 2 + 14``
``52``

The divmod of two integers returns a tuple containing the integer division and modulo:

``divmod(num2, num1)``
``(2, 14)``

Float Division of two integers will always return a floating point number, even if there is no Modulo with the integer division:

``num2 / num1``
``2.736842105263158``

## Binary Bitwise Data Model Operators

The int num1 can be examined in binary:

``num1 = 19``
``bin(num1)``
``'0b10011'``

If it is right shifted by two places, the two least significant digits which were 11 are removed:

``bin(num1 >> 2)``
``'0b100'``

This gives the integer:

``num1 >> num2``
``1``

If num1 is examined in binary again:

``bin(num1)``
``'0b10011'``

And instead is left-shifted by two places

``bin(num1 << num2)``
``'0b1001100'``

This gives the integer:

``num1 << 2``
``76``

The bitwise operator & will return an integer that has a bit of 1 when both respective bits in the instance num1 and num2 are 1 and is 0 otherwise.

This can be seen when the following two integers are created:

``````num1 = 201
num2 = 210``````

This can be seen more clearly by examining the binary sequence for num1 and num2:

``bin(num1)``
``'0b11001001'``
``bin(num2)``
``'0b11010010'``

Then examining the binary sequence returned from the bitwise and operator:

``bin(num1 & num2)``
``'0b11000000'``

In this example on the first two bits are 1 in num1 and num2:

``num1 & num2``
``192``

The bitwise operator or will return an integer that has a bit of 1 when either bits in the instance num1 and num2 are 1 and is only 0 when both are 0. The binary sequence of each number can be examined:

``bin(num1)``
``'0b11001001'``
``bin(num2)``
``'0b11010010'``

Then the bitwise or operator can be examined, only the third and sixth position are 0 as the corresponding bit is 0 in num1 and num2:

``bin(num1 | num2)``
``'0b11011011'``

This corresponds to the integer:

``num1 | num2``
``219``

Finally the exclusive or operator will return an integer that has a bit of 1 when the bits in the instance num1 and num2 are different and otherwise has a bit of 0. The binary sequence of each number can be examined:

``bin(num1)``
``'0b11001001'``
``bin(num2)``
``'0b11010010'``

The first three leading bits are 0 and aren't shown:

``bin(num1 ^ num2)``
``'0b11011'``

This corresponds to:

``num1 ^ num2``
``27``

These operators also have reverse equivalents:

## Binary Comparison Data Model Identifiers

Since integers are ordinal, the 6 comparison operators are configured:

These 6 comparison operators can be used to compare two integers returning a boolean value of True, if the statement is True, otherwise returning a boolean value of False.

``````num1 = 19
num2 = 20``````

A check can be made to see if num1 is equal to num2:

``num1 == num2``
``False``

A check can be made to see if num1 is not equal to num2:

``num1 != num2``
``True``

A check can be made to see if num1 is greater than num2:

``num1 > num2``
``False``

A check can be made to see if num1 is greater than or equal to num2:

``num1 >= num2``
``False``

A check can be made to see if num1 is less than num2:

``num1 < num2``
``True``

A check can be made to see if num1 is less than or equal to num2:

``num1 <= num2``
``True``

## PEDMAS

When multiple binary operators are used, a calculation is no carried out from left to right, instead there is a preference for operations in the form of PEDMAS:

The effect of PEDMAS can be seen in the following:

``1 + 2 - 3 * 4 ** 5``
``-3069``

This is done using the exponentiation first:

``1 + 2 - 3 * 4 ** 5``

Then the multiplication:

``1 + 2 - 3 * 1024``

Then the addition and subtraction have the same order of precedence:

``1 + 2 - 3072``

This gives the result:

``-3069``

``(1 + 2 - 3) * 4 ** 5``
``0``