# Python – Deep dive into Number types

This post is the sixth of many that attempts to document everything I have been learning about Python.

Number types in Python

1. Integers
2. Floating Point
3. Complex Numbers
4. Fixed precision decimal numbers
5. Fractions

Integers in 2.6 come in 2 flavors, int which is 32 bits and long which has as much precision as the system memory allows for. Python automatically switches to using long when int cannot hold values. It prints long values with a l or L at the end of the number.

Integers in 3.0 allow for as much precision as the system memory allows. There is no long type in 3.0.

Floating points precision is the same as the precision allowed for by the float data type of the C compiler that was used to build Python.

You can express integer literals as octal, hexadecimal and binary number expressions. All these are just expressions that evaluate to an integer.

>>> ‘0b11‘, ‘0o21‘, ‘0xA2
(‘0b11‘, ‘0o21‘, ‘0xA2‘)
>>>

The built in methods oct, hex and bin convert the integer to the respective forms.

You specify a oct with a 0o, hex with 0x and bin with 0b.

>>>
>>> bin(128), oct(128), hex(128)
(‘0b10000000‘, ‘0o200‘, ‘0x80‘)
>>>

Operator precedence the easy way

You do not have to memorize the operator precedence rules in Python if you are careful enough to group operations in parenthesis.

Mixed type expressions

When evaluating expressions that have different types (only numeric), the resulting type of the entire expression is the most complex type, that is, types are converted up to the most complex type being used in the expression. This means that integers are converted up to floats and floats to complex numbers.

>> # adding a int with a float, resulting type is a float
>>> 1 + 3.0
4.0
>>>

In 2.6, mixed type comparisons are allowed. By mixed type comparisons, I mean comparisons between types that are not numbers.

>> # In 2.6, mixed type comparisons
>>> 3 < ‘test
True
>>>

In 3.0, mixed type comparisons, types in which you use numbers with other types like strings will result in an error.

>>> # In 3.0, mixed type comparisons are not allowed
>>> 3 < ‘test
Traceback (most recent call last):
File “”, line 1, in
3 < ‘test’
TypeError: unorderable types: int() < str()

Variable creation in Python

1. Variables are never declared ahead of time.
2. Variables are replaced by their values when used in expressions.
3. Variables are created when they are first assigned values.
4. Variables have to be initialized before they can be used.

You can display numbers using both repr and str display formats. repr is used to display numbers as codes and str is usually used to display numbers in user friendly formats.

>>> # repr and str
>>> repr(“Throw it in the bag“), str(“Throw it in the bag“)
(“‘Throw it in the bag‘”, ‘Throw it in the bag‘)
>>>

Chain comparison operations

Python allows you to chain comparison operations.

>>>
>>> #Chaining comparison operators
>>> # 2 < 3 AND 3 < 4
>>> 2 < 3 < 4
True
>>> # 1 == 2 AND 2 < 3
>>> 1 == 2 < 3
False
>>>

Division in Python

There are 2 operators that perform division and they come in 3 flavors.

In 3.0:

The / operator performs true division, no matter what type of operands, the result is always a float.

The // operator performs a floor division and maintains the type conversion convention. int and int will result in int. int and float will result in float

>>>
>>> 3 / 2, 3.0 / 2.0
(1.5, 1.5)
>>> 3 // 2, 3.0 // 2.0
(1, 1.0)
>>>

In 2.6:

The / operator preforms classic division, it drops the decimal part in case of integers.

The // operator works the same way as in 3.0

>>>
>>> 3 / 2, 3.0 / 2.0
(1, 1.5)
>>> 3 // 2, 3.0 // 2.0
(1, 1.0)
>>>

// (3.0 & 2.6) and / (2.6) have a special case because of floor division.

Floor division is the same as truncation in case of positive numbers, but when negative numbers are involved, floor is different from truncation.

Complex Numbers

These are built-in types in Python. They consist of a real part and a imaginary part. You can use the Cmath module to process them. It is the complex number equivalent to the standard Math module.

Oct, Hex, Bin notation

You can code integer literals using oct, hex and bin notation, they are just one way of generating integers.

In 2.6, you can code an octal by adding a zero to the beginning of an integer and it will be interpreted as base 8.

In 3.0, you have to use 0o that is zero followed by the letter o.

The built-in functions oct(), hex() and bin() generate numbers in their respective bases.

The int() built in takes a string and a optional base.

>>>
>>> bin(128), oct(128), hex(128)
(‘0b10000000‘, ‘0o200‘, ‘0x80‘)
>>> int(‘0o200‘, 8)
128
>>> int(‘0x80‘, 16)
128
>>>

You can also use formatting expressions

{0:o} is for octal
{0:b} is for binary

>>> # octal
>>> ‘{0:o}‘.format(200)
310
>>> # hex
>>> ‘{0:x}‘.format(200)
c8
>>> # bin
>>> ‘{0:b}‘.format(200)
11001000
>>>

The eval built in function, takes any string and runs it as Python code. You can pass integer literals to it as strings (in any base) and it will run it as python code and echo the result in IDLE.

>> eval(‘0b011‘)
3
>>>

Bit Operators

Python has support for bitwise operations, << (left shift), >> (right shift), ^ (XoR), & (and), | (or)

Further, you can use the bit_length method (new in 3.1) to see how many bits are needed to represent a integer. You can achieve this in 2.6 by getting the length of the binary representation of the integer and subtracting 2 to get the bits needed to represent the number.

>>> a = 3
>>> a.bit_length()
2
>>> len(bin(3)) – 2
2
>>>

There are many built in tools and modules that allow you to process numbers.

Built-ins like abs (absolute), pow (exponent) and round.

The Math module has many of the same functions as the math library in C

trunc – just drops the decimal part.
floor – drops the decimal part and floors the value (same as trunc for positive numbers, but diff for negative numbers)
There are 3 ways to compute a square root in Python

Import the math library and use math.sqrt
Raise the number to the power .5 using **
Use the pow built in function and specify .5 as the power.

>>> abs(-10), pow(3, 2)
(10, 9)
>>>
>>> import math
>>> math.trunc(3.0)
3
>>> math.floor(-3.5)
-4
>>> round(3.456, 2)
3.46
>>>
>>> # all compute the square root
>>> math.sqrt(81)
9.0
>>> pow(81, .5)
9.0
>>> 81 ** .5
9.0
>>>

The default namespace in Python is builtins in 3.0 and __builtin__ in 2.6

Decimals

The decimal type in Python represents fixed precision decimal. They are decimal numbers with a fixed set of decimal places.

You cannot create a decimal using a literal. The decimal module must be imported and you call the Decimal method by passing in a string that has the number.

With the decimal type, you can set the number of decimal places to be used. It tends to be a lot more accurate than using floats, but you incur a small performance penalty.

When you run operations on decimals with different precision of decimal places, Python will scale up all the other decimal values to the value with the largest number of decimal places.

You can set the number of decimals to be used by calling the getcontext() method of the decimal module and setting its prec property.

>>> decimal.getcontext().prec = 2
>>> decimal.Decimal(‘1.4444‘) + decimal.Decimal(‘4.11111‘)
Decimal(‘5.6’)

Using the with statement to set the precision will cause all the code inside the with block to use the precision and the code outside the block will use the global default precision value.

>>> # this will set a scope in which the
>>> # precision will be applied to
>>> with decimal.localcontext() as xt:
xt.prec = 2
var1 + var2

Decimal(‘8.0‘)
>>>

Fraction

Like the Decimal type, Fraction was introduced to get past the inaccuracies of floating point operations.

Like the Decimal type, you have to import the fraction module to use the Fraction type.

You can create the Fraction type by passing in 2 numbers (numerator and denominator). You can also pass in a float to the fraction type’s from_float() method to create it.

Floats have a as_integer_ratio method that convert a float to a fraction.

While you can convert float to fractions, you might lose a lot of precision.

You might have to limit the denominator to be able to retain precision. You limit the denominator using the limit_denominator() method of the fraction.

>>> import fractions
>>> v1 = fractions.Fraction(1,3)
>>> v2 = fractions.Fraction(2,3)
>>> v1 + v2
Fraction(1, 1)
>>>
>>> v3 = fractions.Fraction.from_float(3.44)
>>> v3.limit_denominator(10)
Fraction(31, 9)

You can pass a fraction to Float() to convert it into a float

Mixed type conversions

Expressions that have int & fraction will result in a fraction

Expressions that have float & fraction will result in a float

Sets

Sets are a un-ordered collection of unique, immutable objects. The set type is iterable

They support all the regular set based operations.

You can create a set by passing in any iterable type to the Set() method.

Apart from the built-in operators that allow you to perform operations on sets. The set type has methods that allow you to perform those same operations.

While the built in operators operate only on set types, the built in methods will accept any iterable type.

In 2.6 you do not have a literal syntax to create a set, you had to rely on the Set() method. In 3.0 you can use the {} syntax to create a set.

Sets can only contain immutable objects and so you cannot embed lists and dictionaries in them. Sets also cannot contain other sets. To store one set inside another, you have to create a frozen set and embed that in other sets.

Set comprehension syntax is the same as list comprehension, except for Sets you enclose it in {}

>>> set1 = set(‘this is a set‘)
>>> set1
{‘a‘, ‘ ‘, ‘e‘, ‘i‘, ‘h‘, ‘s‘, ‘t‘}
>>> set2 = {‘n‘,’e‘,’w‘,’s‘}
>>> set1 & {‘1‘, ‘2‘, ‘3‘}
set()
>>> set1 | {‘1‘, ‘2‘}
{‘a‘, ‘ ‘, ‘s‘, ‘1‘, ‘e‘, ‘t‘, ‘i‘, ‘h‘, ‘2‘}
>>> set1.union

>>> set1.union({‘1‘, ‘2‘})
{‘a‘, ‘ ‘, ‘s‘, ‘1‘, ‘e‘, ‘t‘, ‘i‘, ‘h‘, ‘2‘}

Booleans

Python has a data type named bool which has 2 values, True and False. These are actually representations of the values 1 and 0. bool is a subclass of int and True / False are basically values that are being printed instead of 1 and 0, this has been done by overriding the repr and str methods of the bool class.

>>> truth = True
>>> truth + 1 # Woah!
2
>>>