# 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

# 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"]

# 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]])