Author: James Bourbeau
%load_ext watermark
%watermark -d -v
Let's get a feel for some of the built-in types in python. Specifically, we'll discuss some of the most commonly used types, how to change the type of an object, and how some numeric operations behave between different types. If you would like to know the type of something, you can always use python's built-in type()
function.
In python there are three basic numerical types: integers, floating-point, and complex numbers. These types are denoted by int
, float
, and complex
, repsectively. Generally speaking, integers represent whole numbers ( ...,-2, -1, 0, 1, 2,...), floats represent decimal numbers, and complex are, well, complex numbers (where the real and imaginary parts are both floats). Information regarding the precision of floating-point can be found via
import sys
sys.float_info
Numbers without a decimal point produce integers, while number that include a decimal (or an exponent sign) produce floats.
a = 2
type(a)
b = 6.47
type(b)
c = 9e8
type(c)
A complex number can be created by including a 'j' or 'J' in a number. The corresponding real and imaginary parts of the complex number can be accessed using real
and imag
attributes.
z = 7 + 4.3j
type(z)
z.real
z.imag
Note that the real and imaginary parts for the complex
type are floating-point numbers--regardless of whether or not there is a decimal point.
There are other built-in numeric types such as fractions
and decimal
, but I find int
, float
, and complex
to be the most commonly used.
Booleans are actually a subtype of integers with values represent one of two constant values: True
or False
. More will be discussed about booleans later on when we discuss type casting.
n = True
type(n)
p = False
type(p)
Some commonly used sequence types are the list, tuple, and string. Denoted by list
, tuple
, and str
, respectively. These can be thought of as an ordered containers that can store several different items. It is important to note that the items that are stored in a list or tuple need not be of the same type.
Lists are can be constructed in several ways. However, using square brackets with list items seperated by commas is very common.
d = [1, 2.3, 5, 74.7]
type(d)
Tuples can be construced similarly, but with parenthesis instead of square brackets.
f = (83.2, -4 ,5e7)
type(f)
One weird quirk is that a tuple with a single item needs to have a trailing comma, e.g.
f = (83.2,)
print(f)
type(f)
If this trailing comma is left out, then python will assume you don't actually want a tuple and will assign whatever the single item is in parenthesis to your variable. For example,
f = (83.2)
print(f)
type(f)
Each item in a sequence has a number to represent its location in the sequence. This number, called the index, starts at 0 for the first item, 1 for the second item, and so on. One can access an individual item in a sequence by using square brackets and the item's index. For example, the first item in the d
list is
d[0]
The second item in the d
list is
d[1]
The third item in the d
list is
d[2]
and so on...
The length of a sequence, the number of items is contains, can be found with the built-in len()
function.
print(d)
len(d)
Up to this point, it may seem like lists and tuples aren't any different. They are both containers that can hold items, you can access the items with an index, etc. How are these things different? The difference between the list
type and the tuple
type is that lists are mutable, while tuples are immutable. Mutable objects are objects that can be changed in place, while immutable objects cannot be changed in place. Let's look at an example.
Let's create a list
g = [1, 2, 3, 4]
print(g)
Now let's modify the list in place. That is, let's try to change the items in the list without creating a whole new list.
g[0] = 99
print(g)
As you can see, there wasn't a problem here. We assigned to the variable g
the list [1, 2, 3, 4]
, then modified the first item in the g
list to be the number 99
. This is an example of a mutable object—it can be changed. Let's try the same thing with a tuple
now.
g = (1, 2, 3, 4)
print(g)
g[0] = 99
print(g)
We got this error because tuples are immutable—they can't be modified once they're created.
Strings are another sequence type and are used to represent a sequence of characters. Strings can be created by enclosing characters in either single or double quotes.
g = 'pizza'
type(g)
h = "jamesbond007"
type(h)
Because a string is a sequence, it can also be index just like lists and tuples.
h[0]
h[1]
You can also find out how many characters are in a string using the len()
function
len(h)
In python, there is only one mapping type: the dictionary. It is denoted by dict
. Dictionaries are unordered containers for key-value pairs. That is, for each key in a dictionary there is an associated value. Dictionaries are created by placing comma-separated key-value pairs inside curly brackets {}
. For a key-value pair, the key and corresponding value are seperated by a colon, :
.
An example might help...
k = {'key1': 23, 'key2': -53.2, 'key3': 'Tokyo'}
type(k)
Here, the dictionary keys are 'key1', 'key2', and 'key3', with corresponding values of 23, -53.2, and 'Tokyo'. In a similar way to sequences, you can access the values in a dicionary by giving the corresponding key in square brackets.
k['key1']
k['key2']
k['key3']
The size of a dictionary, the number of key-value pairs is contains, can be found with the built-in len()
function.
len(k)
It is important to note that in the previous example all the keys were strings, but this doesn't have to be the case. The only restriction on keys is that they be an immutable type. For example, the following is also an acceptable dictionary.
m = {-23: [1, 2, 3, 4], 'desk': 3.2, 7.12: (-3, 'bird')}
m[-23]
m['desk']
m[7.12]
Let see what happens if I try to contruct a dictionary with a list key
n = {[1, 2, 3]: 'WOO'}
Whoops lists are mutable! So remember to always use immutable objects for dictionary keys!
Sometimes it can be useful to manually change the type of an object. In python, this so-called 'type-casting' can be accomplished using several built-in functions:
int()
—casts to integerfloat()
—casts to floatstr()
—casts to stringbool()
—casts to booleanLet's see it in action
Casting integers to floats is fairly straight-forward
a = float(2)
print(a)
type(a)
When casting a float to an integer, python will round down to the nearest integer
b = int(78.81)
print(b)
type(b)
You can even cast a number to a string! (This effectively just returns the number in quotes)
c = str(-1324.1)
print(c)
type(c)
Things get a little less straight-forward when casting to bool
. Below are the bool
casting rules:
0
, 0.0
, 0j
, cast to False
. Everything else casts to True
.()
, []
, ''
, cast to False
. Everything else casts to True
.{}
, casts to False
. Everything else casts to True
.Here are some examples:
bool(0)
bool(178.3)
bool([])
bool([1, 2, 3, 4, 5])
bool({})
bool({'key': 'value'})
The following numerical operations are supported for numeric types:
+
-
*
/
//
**
Some examples...
1+1
10-3
3*5.0
5/2
5//3
9.0**2
When performing numeric operations, the type of numbers does matter. According to the Python Software Foundation:
Python fully supports mixed arithmetic: when a binary arithmetic operator has operands of different numeric types, the operand with the 'narrower' type is widened to that of the other, where integer is narrower than floating point, which is narrower than complex.
So, when you have a numeric operation with mixed numeric types, say adding an int
and a float
, the result will have the 'widest' type of the two numbers, in this case float
. The convention is int
is the most narrow type, float
is wider than int
, and complex
is wider than float
.