Quick Intro to Python

By Sajad Darabi

September 29, 2017

Condemn none: if you can stretch out a helping hand, do so. If you cannot, fold your hands, bless your brothers, and let them go their own way. - Swami Vivekananda

Running Interactive Shell

We will be using python 2.7 in this class.

Check if you have python installed by running the following in your terminal.

python --version

It is useful to install jupyter notebooks you can do so by running

pip install jupyter

Note: Make sure you are using the correct pip command, if you have multiple versions of python installed on your system!

Data Types and Variables

Python is a dynamically-typed language.

  • There is no explicit is no explicit way of declaring the type of a variable
i = 10 # int 
j = 10.123 # float
a = "A" # str
b = [1, 2, 3] # list

Note: you can check the type of a variable by using the built-in type function

In [81]:
i = 20
type(i)
Out[81]:
int

Operators

The usual operators are used in python with few you might not have seen before, if you c/c++ background.

  • + : addition
  • - : subtraction
  • * : multiplication
  • % : modulo
  • / : division
  • //: truncation division
  • ** : exponentiation

Logical Operators

  • ~ : bitwise negation
  • or : logical or
  • and : logical and
  • not : logical not
  • <, <=, >, >=, !=, ==
  • |, &, ^ : bitwise or, and, xor
  • in : element in (a list, tupple, dictionary..)
  • <<, >> : left shift and right shift

Conditional Statements and Control Flow

If/Else Block

It's useful to be able to check whether a particular statement is True/False prior to executing a code block.

The if else block in python

if (True):
    print("if")
elif (statement):
    print("elif")
else:
    print("else")

Note: statements used in paranthesis must be boolean statements i.e. result in either a True or False value.

For/While Loop

for i in range(n):
    #code goes here
    #iterate n times.

range(start, stop, step) function generates a list of numbers, which is used to iterate over in loops, starting at start and ending with stop - 1 using step increments.

Say we want to add the first 100 integers, we can do this using a for loop.

In [82]:
cum_sum = 0
for i in range(101):
    cum_sum += i
print(cum_sum)
5050

This is equivalent to the following while loop

In [83]:
cum_sum = 0
i = 0
while(i < 100):
    i += 1
    cum_sum += i
print(cum_sum)
5050

Compute Fibonnaci Sequence Using a Loop

In [84]:
n = 11
old, new = 0, 1
for i in range(n - 3):
    t = new
    new = old + new
    old = t

print("fib_" + str(n - 2) + ": " + str(old) + " fib_" + str(n - 1) + ": " + str(new))
fib_9: 21 fib_10: 34

Lists/Tuples/Dicts

We will be dealing with different data structures, and those are:

  • Lists : mutable list
  • Tuples : non-mutable list
  • Dicts : mutable list of <key, value> pairs

Mutability means the data structure can be modified after creation.

Lists

You can create lists using brackets a = [1, 2].

In [85]:
a = [1, 2, 3] # list with 3 elements
b = [10] * 10; # list with 100 elements all of which are 10.

print('a = ', a)
print('b = ', b)
a =  [1, 2, 3]
b =  [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]

Indexes in python start from 0. You can index through a list using the indexing operator [] for example a[1], will index the 2nd element 2.

You can get the length of a list by using the len function.

In [86]:
len(a)
Out[86]:
3

It is quite common to run through a list to check if a particular value is present. Python makes it is easy by providing the in operator. It checks if a particular value is present in a list. You can also use the not in which checks if it is not present in the list.

In [87]:
a = [1, 2, 3]
1 in a
Out[87]:
True
In [88]:
10 not in a
Out[88]:
True

List Slicing

Python lists support slice indexing syntax. If you're not familiar with slice indexing it's simple...

print(a[start:end])

Will print elements of array a from $[start, end)$ exclusive (i.e. end will not be included in the set of indexes that will be returned).

Either start or end can be left out, for example

print(a[:end]) # will print from index 0 to end exclusive
print(a[start:]) # will print from index start to end of list

In general when slicing an array you can use set start, end, step, where

  • start: starting index to begin slicing
  • end: last index at which array will be sliced at
  • step: increments from start index to end index
a[start:end:step]
In [89]:
a = 'hello world'
print(a[0:3])  # print the first 3 characters
print(a[0:-5]) # print everything besides the last 5 characters (note the -5 used as the end value)
print(a[::-1]) # start from index 0 to end and take steps of -1 
               # i.e. the slices will be end - 1, end - 2, .., 0
               # which will reverse the string; in one line!
hel
hello
dlrow olleh

List Comprehension

Say we want a list with all even numbers between 0 to 101. This can be written in one line using list comprehension as follows:

zero_to_101 = [i for i in range(101) if i % 2 == 0]
print(zero_to_101)

If you look at the way mathematicians would write out a set using math notation, you would see that there are quite a bit of similarity between list comprehension and the mathematical notation.

$$ S = \{~ x^3 : x\text{ in }[0, 9]~\}$$ $$ A = \{3, 6, 9, 12, ..., 300\}$$ $$ D = \{ x~ | ~x ~\text{ in } A \text{ and } ~x \text{ in } S \}$$

The above sets can be converted into list comprehension in one line of code

$$ S = \{~ x^3 : x\text{ in }[0, 9]~\}$$

In [90]:
S = [x ** 3 for x in range(0, 10)]
S
Out[90]:
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]

$$ A = \{3, 6, 9, 12, ..., 300\}$$

In [91]:
A = [3 * i for i in range(0, 301)]
first_4_elements = str(A[:4]).strip(']')
last_4_elements =  str(A[-4:]).strip('[')
print(first_4_elements, " ,..., ", last_4_elements)
[0, 3, 6, 9  ,...,  891, 894, 897, 900]

$$ D = \{ x~ | ~x ~\text{ in } A \text{ and } ~x \text{ in } S \}$$

In [92]:
D = [x for x in S if x in A]
print(D)
[0, 27, 216, 729]

list comprehensions are useful one lines if you want to create masks, set of indexes, etc..

Somethings to keep in mind

When working with lists you might find yourself the need to create a copy or extend a an existing one.

Simply assigning an array to another variable does not copy the content, it just copies a reference to the other variable, so you end up with two variables pointing to the same list.

a = [1, 2, 3]
b = a # does not create copy

To create a copy you can either call the list() built-in function or slice the array

b = a[:]
#  OR
b = list(a)

There are different ways of appending/extending a list in python.

  • append
  • extend
  • + operator

extend

extend method appends elements to the end of a list from an iterable list , so for example a.extend([1, 2]) will add elements, 1, 2 to list a like so [1, 2, 3, 1, 2]

In [93]:
a = [1, 2, 3]
a.extend([1, 2])
a
Out[93]:
[1, 2, 3, 1, 2]

note: An iterator is a stream of data. An iterable is an object that has an __iter__ method implemented that returns an iterator. Or it has the __getitem__ method implemented that given an index it returns an item.

append

Append is different from extend in that it appends the data to the end of the list.

a.append([1, 2]) # a will become [1, 2, 3, [1, 2]]
In [94]:
a = [1, 2, 3]
a.append([1, 2])
a
Out[94]:
[1, 2, 3, [1, 2]]

+ operator overloaded

The plus + operator is semantically similar to extend, i.e. when you're extending a list with another object that object has to be iterable.

There is a difference if you were to use + or += when mutating a list. In the first case it will extend the array and create a new copy, where as the second case will extend the array in place.

a_list = a_list + your_list #will make a new copy
a_list += your_list #will extend a_list in place
In [95]:
a = [1, 2, 3]
b = [3, 4, 5]
id_before = id(a)
a = a + b
id_after = id(a)
print(id_before)
print(a)
print(id_after)
140191917476296
[1, 2, 3, 3, 4, 5]
140191917247304

Tuples

Tuples are similar to lists, but they are not mutable i.e. once a tuple has been created you cannot append more data to it or change the data.

tupple = ("hello", "my", "name")
tupple[0]
'hello'

Why use tuples instead of lists?

  • it protects against accidental change. If you know your list shouldn't change then declare it as a tupple.
  • they are also faster than lists.

Dictionaries

Like lists dictionaries are mutable data structure. They can grow and shrink. The difference is in how elements are accessed. In dictionaries elements are accessed by using keys, whereas in lists we index through it using integer values.

Dictionaries in python are implemented as hash tables, so finding a particular value is fast!

In [96]:
full_name = {} # empty dictionary
full_name["First Name"] = "Sajad"
full_name["Last Name"]  = "Darabi"

print(full_name)
{'First Name': 'Sajad', 'Last Name': 'Darabi'}

We could have initialized the full_name dictionary in one line as well

full_name = {"First Name": "Sajad", "Last Name": "Darabi"}

We can access individual elements by using the corresponding key, for example full_name["First Name"]

Functions

Passing Parameters

Pass by reference

By default in python when passing a parameter to a function, it is passed by reference. Take a look at the function below

In [97]:
def passbyreference(x):
    print(x, id(x))
    x = 20
    print(x, id(x))

x = 10
print(x, id(x))
passbyreference(x)
10 140192660368096
10 140192660368096
20 140192660368416

We declare a variable x, and the id function returns a unique integer assigned to that variable. (note: the ids might be different if you run it on your own computer!)

Side effects

A function produces a side effect if it modifies the callers environment in any way in addition to returning a value. Typical side effects are mutating the data, printing to the screen, etc..

In python if a function uses the extending in place operator += on a list, it will mutate the original list.

In [98]:
def mutateList(l):
    print(l)
    l += [2, 1]
l = [4, 3]
mutateList(l)
print(l)
[4, 3]
[4, 3, 2, 1]

The function has modified the content of the original list. To avoid this you can pass the list by creating a new copy: mutateList(l[:]).

In [99]:
def mutateList(l):
    print(l)
    l += [2, 1]
l = [4, 3]
mutateList(l[:])
print(l)
[4, 3]
[4, 3]

The function hasn't modified the list.

Using External Modules

We can use modules written by others by importing them into our python environment

Let's use the module numpy this module is often used for processing large listst and matrices data structures.

Make sure you have numpy installed, if you don't run pip install numpy in terminal. (you might have to use pip3 depending on how you have python setup on your computer)

In [100]:
import numpy as np
np.random.randn(5, 1) # creates a column vector with dimension 5 and assigns random values.
Out[100]:
array([[-0.47876023],
       [ 0.89474721],
       [ 2.05896199],
       [ 0.57109483],
       [-0.35903142]])

Additional Resources

This should be enough to get you going. For additional resources you can refer to the following tutorials