Python Crash Course Part 2

Adapted by Volodymyr Kuleshov and Isaac Caswell from the CS231n Python tutorial by Justin Johnson (http://cs231n.github.io/python-numpy-tutorial/).

Update to Python 3 by Long Nguyen

Python Crash Course Tutorial for anyone with some experience in programming.

Part 2 will cover:

  • Functions
  • Containers: Lists, Tuples, Dictionaries.

Functions

Python functions are defined using the def keyword. By default, arguments are positional.

In [20]:
def doubling(x):
    """ This is the function's docstrings. It provides 
        information about the function. 
        Given a number x.
        Returns 2 * x. 
    """
    return 2 * x

def mult(x, y):
    return x * y


print(doubling(5))
mult(3, 4) # positional arguments, x = 3, y = 4.
10
Out[20]:
12

Input arguments can be specified by name. In this case, the order does not matter.

In [9]:
def printNums(x, y):
    print("x's value is {} and y's value is {}".format(x,y))

# the following are all equivalent.    
printNums(2, 3)
printNums(x=2, y=3)
printNums(y=3, x=2)
x's value is 2 and y's value is 3
x's value is 2 and y's value is 3
x's value is 2 and y's value is 3

If named arguments and positional arguments are used together, named arguments must follow positional arguments.

In [13]:
def name(first, middle, last):
    print(first, middle, last)
    
name("John", "F", "Kennedy")    
name("George", last="Bush", middle="W")
John F Kennedy
George W Bush

Functions can take optional keyword arguments. These are given default values.

In [1]:
def hello(greeting="Hello,", name="Mike"):
    print(greeting, name)
    
hello()
hello(greeting="Hi,") #name="Mike"
hello(name="John")  #greeting="Hello,"
hello(name="Bob",greeting="Welcome,")
Hello, Mike
Hi, Mike
Hello, John
Welcome, Bob

Containers

Python includes several built-in container types: lists, dictionaries, sets, and tuples.

Lists

A list is the Python equivalent of an array, but is resizeable and can contain elements of different types:

In [109]:
xs = [3, 1, 2]   # Create a list
print(xs, xs[2])
print(xs[-1])     # Negative indices count from the end of the list; prints "2"
[3, 1, 2] 2
2
In [110]:
xs[2] = 'foo'    # Lists can contain elements of different types
print(xs)
[3, 1, 'foo']
In [111]:
xs.append('bar') # Add a new element to the end of the list
print(xs)  
[3, 1, 'foo', 'bar']
In [112]:
x = xs.pop()     # Remove and return the last element of the list
print(x, xs) 
bar [3, 1, 'foo']

You can iterate over a list like this:

In [2]:
animals = ['cat', 'dog', 'monkey']
for animal in animals:
    print(animal)
cat
dog
monkey

To sum over list, use sum instead of a for loop.

In [31]:
nums = [1,2,3,4]
print(sum(nums))
10

If you want access to the index of each element within the body of a loop, use the built-in enumerate function.

In [5]:
animals = ['cat', 'dog', 'monkey']
for index, animal in enumerate(animals):
    print('#{}: {}'.format(index + 1, animal))
#1: cat
#2: dog
#3: monkey

As usual, you can find all the gory details about lists in the documentation.

Slicing

In addition to accessing list elements one at a time, Python provides concise syntax to access sublists; this is known as slicing. This is similar to string slicing we saw earlier.

In [115]:
nums = range(5)    # range is a built-in function that creates an iterator, in this case, 
                   # from 0 up to but not including 5. 
nums = list(nums)  # convert to a list. Later we'll use numpy to do this instead. 

print(nums)         # Prints "[0, 1, 2, 3, 4]"
print(nums[2:4])    # Get a slice from index 2 to 4 (exclusive); prints "[2, 3]"
print(nums[2:])     # Get a slice from index 2 to the end; prints "[2, 3, 4]"
print(nums[:2])     # Get a slice from the start to index 2 (exclusive); prints "[0, 1]"
print(nums[:])      # Get a slice of the whole list; prints ["0, 1, 2, 3, 4]"
print(nums[:-1])    # Slice indices can be negative; prints ["0, 1, 2, 3]"
print(nums[:-2])    # Slice indices can be negative; prints ["0, 1, 2]"
nums[2:4] = [8, 9]  # Assign a new sublist to a slice
print(nums)         # Prints "[0, 1, 8, 9, 4]"
[0, 1, 2, 3, 4]
[2, 3]
[2, 3, 4]
[0, 1]
[0, 1, 2, 3, 4]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1, 8, 9, 4]
In [10]:
nums = range(10)
nums = list(nums)
print(nums)
print(nums[1:8:2]) # from 1(including) to 8(not including) by 2.
print(nums[::2]) # from beginning to end(not including) by 2
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 3, 5, 7]
[0, 2, 4, 6, 8]

List comprehensions:

When programming, frequently we want to transform one type of data into another. As a simple example, consider the following code that computes square numbers:

In [116]:
nums = [0, 1, 2, 3, 4]
squares = []
for x in nums:
    squares.append(x ** 2)
print(squares)
[0, 1, 4, 9, 16]

You can make this code simpler using a list comprehension:

In [117]:
nums = [0, 1, 2, 3, 4]
squares = [x ** 2 for x in nums]
print(squares)
[0, 1, 4, 9, 16]

List comprehensions can also contain conditions:

In [118]:
nums = [0, 1, 2, 3, 4]
even_squares = [x ** 2 for x in nums if x % 2 == 0]
print(even_squares)
[0, 4, 16]

Tuples

A tuple is an (immutable) ordered list of values. A tuple is a sequence of immutable Python objects. Tuples are sequences, just like lists. The differences between tuples and lists are, the tuples cannot be changed unlike lists and tuples use parentheses, whereas lists use square brackets.

A tuple is in many ways similar to a list. Here is a trivial example:

In [130]:
tup1 = ('physics', 'chemistry', 1997, 2000)
tup2 = (1, 2, 3, 4, 5 )
tup3 = "a", "b", "c", "d"
print(tup1)
print(tup1[0])
print(tup2[3])
print(tup3[-1])
tup1[0] = 'math' # error, can't change tuples!
('physics', 'chemistry', 1997, 2000)
physics
4
d
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-130-fb0a90de0adf> in <module>()
      6 print(tup2[3])
      7 print(tup3[-1])
----> 8 tup1[0] = 'math' # error, can't change tuples!

TypeError: 'tuple' object does not support item assignment

It's easy to convert between lists and tuples.

In [6]:
a = [1,2,3,4,5]
atuple = tuple(a)
alist = list(atuple)

print(atuple)
print(alist)
(1, 2, 3, 4, 5)
[1, 2, 3, 4, 5]

Dictionaries

A dictionary is stores (key, value) pairs. Lists are ordered sets of objects; dictionaries are unordered sets. A dictionary's value is accessed by its key rather its position. Dictionaries use curly brackets {}. You can use it like this:

In [7]:
d = {'cat': 'cute', 'dog': 'furry'}  # Create a new dictionary with some data, use {}
print(d['cat'])       # Get an entry from a dictionary; prints "cute"
print('cat' in d)     # Check if a dictionary has a given key; prints "True"
cute
True
In [31]:
keys = d.keys() # returns keys of the dictionary.
keys = list(keys)
print(keys)
values = d.values() # returns values of the dictionary.
values = list(values)
print(values)
['cat', 'dog', 'fish']
['cute', 'furry', 'wet']
In [8]:
d['fish'] = 'wet'    # Set a new entry in a dictionary
print(d['fish'])      # Prints "wet"
print(d)
wet
{'cat': 'cute', 'dog': 'furry', 'fish': 'wet'}
In [121]:
del(d['fish'])        # Remove an element from a dictionary

You can find all you need to know about dictionaries in the documentation.

It is easy to iterate over the keys in a dictionary:

In [122]:
d = {'person': 2, 'cat': 4, 'spider': 8}
for animal in d:
    legs = d[animal]
    print('A {} has {} legs'.format(animal, legs))
A person has 2 legs
A cat has 4 legs
A spider has 8 legs

If you want access to keys and their corresponding values, use the items method:

In [123]:
d = {'person': 2, 'cat': 4, 'spider': 8}
for animal, legs in d.items():
    print('A {} has {} legs'.format(animal, legs))
A person has 2 legs
A cat has 4 legs
A spider has 8 legs
In [3]:
d = {'cat': 'cute', 'dog': 'furry'}  # Create a new dictionary with some data, use {}
print(d['cat'])       # Get an entry from a dictionary; prints "cute"
print('cat' in d)     # Check if a dictionary has a given key; prints "True"
x="hello"
cute
True

Iterables

Lists, tuples, dictionaries and strings are examples of iterables, objects that can be iterated over, as in a for loop.

Iterables allow us to "unpack" in a way that makes our code more readable.

In [133]:
alist = [3,5,2]
# instead of doing this
x = alist[0]
y = alist[1]
z = alist[2]
print(x,y,z)

# we can do this, unpacking.
a, b, c = alist # 
print(a,b,c)
3 5 2
3 5 2

Here's another example. Suppose we have a list of (name,grade) tuples.

In [134]:
grades = [("Maria", 91), ("Mike", 88), ("Tom", 81)]
for element in grades:
    print(element)
('Maria', 91)
('Mike', 88)
('Tom', 81)

Unpacking allows us to unpack name and grade into distinct variables.

In [135]:
for name, score in grades:
    print(name, score)
Maria 91
Mike 88
Tom 81
In [10]:
points = [(1,2), (3,4,5), (6,7)]
for pt in points: # iterate over list(points)
    for coord in pt: # iterate over tuple(pt)
        print(coord)
1
2
3
4
5
6
7

By returning a tuple and unpacking, we can create the illusion of a function returning multiple values.

In [2]:
def sumDiff(a,b):
    s = a + b
    d = a - b
    return s, d  # returning the tuple (s,d)

sumAB, diffAB = sumDiff(12,7) # unpacking the tuple
print(sumAB, diffAB)
19 5