You are on page 1of 83

Python

67557
Lecture 2
CS.HUJI
Fall 2014 - "
Dr. Arie Schlesinger

Containers of data
Motivation: keep data and processing
tools close by,

11/8/2014 10:37:29 PM

Some classifications
Simple objects, :
int, float, bool (non iterable)
Containers of objects : (iterable)
str, list, tuple, range, set, frozenset, dict

11/8/2014 10:37:29 PM

Order
Sequences: ordered Containers
A sequence is a container whose elements are ordered
and can be accessed by their position index, starting
from 0. Example, the 1st element in the string:
>>> s=abc
>>> s[0]
a
Containers: strings, lists, tuples, range,..

Not Sequences-unordered Containers


- Can not index their elements: sets, frozensets, dictionaries
11/8/2014 10:37:29 PM

Freedom
Mutable: list,

set, dictionary

- Contents can be changed :


- add , remove, change elements.

Immutable: strings, tuples,

frozenset, range

- No changes can be made


(Not containers: int, float, bool )

11/8/2014 10:37:29 PM

The two titles every container


holds
there are more

Sequence, Mutable: list


Sequence, Immutable: string, tuple, range

Not sequence, Mutable

: set, dictionary

Not sequence, Immutable : frozenset


11/8/2014 10:37:29 PM

What about the titles of the


non containers ?
No Sequence, Immutable : int,

float, bool

(no order, no freedom to change)

11/8/2014 10:37:29 PM

sequences
strings, lists, tuples, range

11/8/2014 10:37:29 PM

Sequences
Tuples
Contain 0 or more items of mixed types, including other
containers Immutable

Strings
Contain a seq of 0 or more single chars Immutable

Lists
Contain a seq of 0 or more items of mixed types, including
other containers Mutable

Ranges
Contain
a seq of 0 or more ordered integers ! - immutable
11/8/2014 10:37:29 PM

Similar Syntax
The three sequences types : tuples, strings, and
lists, have similar syntax and functionality

Therefore most operations on all sequences, can be


demonstrated on one seq, to illustrate the others

11/8/2014 10:37:29 PM

10

Sequences
Tuples : defined using parentheses, and commas.
>>> tup = (12, 'bcd', 3.45, (1,2), 'efg')
Lists : defined using square brackets, and commas.
>>> liz = ["bcd", 23, 3.23, 12]
Strings are defined using quotes (", ', or """).
>>> st = "abc"
>>> st = 'abc'
>>> st = """an example
of a multi-line string that uses triple quotes."""
Empty seq: [], (), ''
11/8/2014 10:37:29 PM

11

Sequence indexing

11/8/2014 10:37:29 PM

12

Indexing
You can access individual elements of a tuple, list, or string
using square bracket indexing notation, ( 0 based)
>>> tup = (12, bcd, 3.45, (1,2), efg)
>>> tup[1] # 2nd element in the tuple.
bcd
>>> liz = [bcd, 23, 3.23, 12]
>>> liz[1] # 2nd element in the list.
23
>>> st = bcd
>>> st[1] # 2nd char in string.
c
The index is an expression that evaluates to
an
int
11/8/2014
10:37:29 PM

13

Positive and negative indices


>>> tup = (12, bcd, 3.45, (1,2), efg)

Positive index: count from the left, starting with 0.


>>> tup[1]
bcd
Negative index:count from right, starting with the last
element, represented by index: -1

>>> tup[-3] # the 3rd from the end


3.45
11/8/2014 10:37:29 PM

14

Sequence slicing

11/8/2014 10:37:29 PM

15

Slicing
>>> tup = (12, bcd, 3.45, (1,2), efg)
>>> t[1:4]
(bcd, 3.45, (1,2))
Return a same-class-container, with a subset of the
original members.
It starts copying from the first index, and stops
copying before the second index.
negative indices can be used :
>>> t[1:-1]
(bcd, 3.45, (1,2))
11/8/2014 10:37:29 PM

16

Slicing defaults
>>> tup = (12, bcd, 3.45, (1,2), efg)
Without a first index, it starts from position 0:
>>> t[:2]
(12, bcd)
Without the second index, it starts at the first index
until end of the container.
>>> t[2:]
(3.45, (1,2), efg)

11/8/2014 10:37:29 PM

17

What indexing, and slicing return


Strings return strings:
Indexing: returns the one-char string at index pos.
Slicing : returns the substring specified (a new string)

Lists, tuples return:


Indexing: returns the element at index position
Slicing : returns a new seq as specified
(element can be simple or compound: int,string, list ,)
11/8/2014 10:37:29 PM

18

indexing slicing doc


http://docs.python.org/2/library/stdtypes.html#
sequence-types-list-tuple-range

11/8/2014 10:37:29 PM

19

Copying the Whole Sequence


[:] makes a copy of an entire sequence.
>>> tup[:]
(12, bcd, 3.45, (1,2), efg)
>>> list1=[1,[2,3],4]
Two diff names of one seq:
>>> list2 = list1 # 2 names refer to 1 ref
# NEW: Changing one affects both
Shallow copy: Two diff names of two diff seq
>>> list3 = list1[:]
(copying will b back..)
11/8/2014 10:37:29 PM

20

The in Operator
membership test, returns True or False :
>>> t
>>> 3
False
>>> 4
True
>>> 4
False

= [1, 2, 4, 5]
in t
in t
not in t

11/8/2014 10:37:29 PM

21

Membership for strings


tests for substrings of 1 or more adjacent chars
>>> a = 'abcde'
>>> 'c' in a
True
>>> 'cd' in a
True
>>> 'ac' in a
False
Careful: the in keyword is also used in the syntax of for loops
and list comprehensions.
11/8/2014 10:37:29 PM

22

The + Operator
The + operator produces a new tuple, list, or
string whose value is the concatenation of its
arguments.
>>> (1, 2, 3) + (4, 5, 6)
(1, 2, 3, 4, 5, 6)
>>> [1, 2, 3] + [4, 5, 6]
[1, 2, 3, 4, 5, 6]
>>> The + + Beatles
The Beatles
11/8/2014 10:37:29 PM

23

The * Operator
The * operator produces a new tuple, list, or
string that repeats the original content.
>>>
(1,
>>>
[1,

(1, 2, 3) *
2, 3, 1, 2,
[1, 2, 3] *
2, 3, 1, 2,

3
3, 1, 2, 3)
3
3, 1, 2, 3]

>>> Hello * 3
HelloHelloHello
Its operands are a seq, and an int
11/8/2014 10:37:29 PM

24

Mutability:
Tuples vs. Lists

11/8/2014 10:37:29 PM

25

Tuples: Immutable
>>> tup = (12, bcd, 3.45, (1,2), efg)

>>> tup[2] = 2
TypeError: object doesn't support item assignment

You cant change a tuple.


You can make a fresh tuple and assign its
reference to a previously used name.
>>> tup = (12, bcd, 2, (1,2), efg)
After the assignment, tup is now the name of the new
tuple
11/8/2014 10:37:29 PM
26

Lists: Mutable
Lists are mutable: it is possible to change their
content (strings are immutable)
Assign to a legal position:
>>> liz = [abc, 12, 4.34, 23]
>>> liz[1] = 35 # assignment
>>> liz
[abc, 35, 4.34, 23]
11/8/2014 10:37:29 PM

27

More examples
>>> myList
[1, 'a', -2.7]
>>> myList[0]='Iosi'
>>> myList
['Iosi', 'a', -2.7]

We can change lists in place.


myList is still the name of the same container
at the same address ,when were done.
11/8/2014 10:37:29 PM

28

Assignment to slices1
Assignment to slices can even change the size of
the list or clear it entirely:
>>> letters =['a,'b,'c,'d,'e,'f,'g']
# replace some values
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']

11/8/2014 10:37:29 PM

29

Assignment to slices2
# now remove them
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']

# clear the list by replacing all the elements with an


empty list
>>> letters[:] = []
>>> letters
[]
([] is the destroyer tool)
11/8/2014 10:37:29 PM

30

len() works with all sequences


>>> letters = ['a', 'b', 'c', 'd']
>>> len(letters)
4

11/8/2014 10:37:29 PM

31

nesting lists
Create lists containing other lists:
>>> a = ['a', 'b', 'c']
>>> n = [1, 2, 3]
>>> x = [a, n]
>>> x
[['a', 'b', 'c'], [1, 2, 3]]
>>> x[0]
['a', 'b', 'c'] # list a
>>> x[0][1]
'b'
11/8/2014 10:37:29 PM

32

For your lists Only..1


>>> liz1 = [1, 1, 3, 4, 5]
>>> liz1.append(x) # a method of lists
>>> liz1
[1, 1, 3, 4, 5, x]
>>> liz1.insert(2, y)
>>>liz1 [1, 1, y, 3, 4, 5, x]
11/8/2014 10:37:29 PM

33

The extend method vs the


operator +
+ creates a fresh list (with a new memory
reference)
extend operates on liz1 in place.
>>> liz1.extend([9, 8, 7])
>>> liz1
[1, 2, i, 3, 4, 5, a, 9, 8, 7]

11/8/2014 10:37:29 PM

34

Append
>>> x = [1, 2, 3]
>>> x.append([4, 5])
>>> x

# appends its arg packed as it comes

[1, 2, 3, [4, 5]]

11/8/2014 10:37:29 PM

35

Extend
>>> x = [1, 2, 3]
>>> x.extend([4, 5])
>>> x

# extend unpacks its arg

[1, 2, 3, 4, 5]

11/8/2014 10:37:29 PM

36

For your lists Only ..2


>>> liz4 = [a, b, c, b]
>>> liz4.index(b)
1
>>> liz4.count(b)
2
>>> liz4.remove(b)
>>> liz4
[a, c, b]
11/8/2014 10:37:29 PM

37

For your lists Only ..3


>>>
>>>
>>>
[8,

li = [5, 2, 6, 8]
li.reverse() # reverse the list in place
li
6, 2, 5]

>>> li.sort() # sort the list in place


>>> li
[2, 5, 6, 8]

11/8/2014 10:37:29 PM

38

Tuples vs. Lists


Lists can be modified, and they have lots of
handy operations we can perform on them.
Tuples are immutable and have fewer
features.
To convert between tuples and lists use the
list() and tuple() functions:
>>> li = list(tu)
>>> tu = tuple(li)
11/8/2014 10:37:29 PM

39

More on list(),tuple()
list(iterable), tuple(iterable) are constructors that
decompose their arg and create a list/tuple from its
elements:
>>> list('abc')
['a', 'b', 'c']
>>> list([1,2])
[1, 2]
>>> list((11,22))
[11, 22]
>>> list(12)
TypeError: 'int' object is not iterable
(other types have similar constructors: set(), dict()
which decompose some iterable and use its elems)

The magic of tuples

The Magic of Tuples


>>> a=(1,2)

>>> b=1,2

# a tuple without

parens

>>> a
(1, 2)
>>> b
(1, 2)
42

From Tuples Unpacking to Swap


>>>
>>>
1
>>>
2
>>>
>>>
11
>>>
22

x,y=(1,2) # tuple unpacking


x
y
x,y=11,22 # also tuple unpacking
x
y

43

Swap
>>> x,y=y,x
>>> x
22
>>> y
11
>>> x,y
(22,11)

# swap is a tuple unpacking !!

# just writing like that, creates a tuple

44

Swap de luxe
Assume:
>>> a=1; b=2
>>> a
1
>>> b
2
# swap de lux made by unpacking
>>> a,b=b,a+b
>>> a
2
>>> b
3
45

From Swap de luxe to .. Fibonacci

>>> a=0; b=1


>>> for i in range(5):
a, b = b, a+b
print b,
1 2 3 5 8
46

The range() Function

11/8/2014 10:37:29 PM

47

range,xrange
The built-in function range([i,]j [,step])
creates an object that represents a range of integers
k such that i <= k < j.
i, step are optional, and have default values of 0
and 1, respectively.
range(10), range(0,10),range(3,21,4)

An xrange() object calculates its values only when accessed, in a for loop
or with a list(), tuple() constructor

although a xrange object looks like a sequence, it is


actually somewhat limited.
For example, slicing is not supported.
11/8/2014 10:37:29 PM

48

xrange: when, what, why


convenient when long sequences of integers are
needed.
xrange does not create a sequence of integers.
It creates a generator function able to produce
each next item of the sequence when needed.
This saves memory, especially for long lists.
11/8/2014 10:37:29 PM

49

Les Iterables
Iterable: An object(container)
capable of returning its
members one at a time.

11/8/2014 10:37:29 PM

50

Who is iterable?
all sequence types (like list, str, tuple, range)

some non-sequence types like set,


frozenset, dict, file objects,
Can be used in a for loop and in other places
where sequences are employed

11/8/2014 10:37:29 PM

51

Iterators
An iterator represents a stream of data

the built-in function iter(),


takes an iterable object as argument
returns an iterator for the object. (')'
to get successive items in the stream.
use the built-in function next()

- is good for one pass over the set of values.


11/8/2014 10:37:29 PM

52

Iterator examples
>>>
>>>
>>>
'a'
>>>
'b'
>>>
'c

s='abc'
# s is iterable
its=iter(s) # iter(s) creates an iterator to s
its.next()
# next(its) returns the next item in s

its.next()
its.next()

>>> its.next() # iterator is exausted - no more elements

ErrorStopIteration
To do it again repeat(refill) its=iter()
11/8/2014 10:37:29 PM

53

xrange show
>>> xrange(1,8,3)
xrange(1, 8, 3)
>>> list(xrange(1,8,3))
[1, 4, 7]
>>> k=iter(xrange(1,8,3))
>>> k.next()
1
>>> k.next()
4
>>> k.next()
7
>>> k.next()
StopIteration
11/8/2014 10:37:29 PM

54

References and Copies

About assignments
Magic integers )) : -5256 (..singletons)
>>> x=256
>>> y=256
>>> print id(x),id(y)
28190492

28190492

No for floats
>>> x=256.0
>>> y=256.0
>>> print id(x),id(y)
36792004 36791924

nor for ints out of


[-5256]
>>> x=257
>>> y=257
>>> print id(x),id(y)
11733080 28387720

Reference, alias
When a program makes an assignment such
as a = b, a new reference to b is created.
>>> b = 257
>>> a = b
>>> print id(a), id(b)
28387672 28387672
>>> a is b # are the ids equal ?
True
>>> a==b # are the values equal ?
True

alias

a is just an alias for b,


changing a will not change b
>>> b = 257
>>> a = b
>>> a = 258

>>> a is b
False
>>> a==b
False
>>> print a, b
258 257

What about for strings?


>>> x='a'
>>> y='a'
>>> print id(x),id(y)
20008472 20008472
>>> x='ojuwriuwrvpiurvpibpihv'
>>> y='ojuwriuwrvpiurvpibpihv'
>>> print id(x),id(y)
32475184 32475184

And what about lists, or tuples


>>> x=[1,2,3]
>>> y=[1,2,3]
>>> print id(x),id(y)
32502248 32489384
>>> x=(1,2,3)
>>> y=(1,2,3)
>>> print id(x),id(y)
32503248 32502368

Mutable objects behaviour


The behavior is different for mutable objects such as lists and
dictionaries. Example:

>>> a = [1,2,3,4]

>>> b = a
>>> b is a
True
>>> a == b
True

# b is a reference to a

Changes in an alias copy


>>> b[2] = -100 # Change an element in b
>>> a
# Notice how a also changed
[1, 2, -100, 4]
>>> b
[1, 2, -100, 4]
>>> a is b
True
>>> a==b
True

What about real copies


Here a and b refer to the same object, so a change
made to the obj thru one of the vars is seen thru the
other.
We need copies that can be changed without changing
the original: not a new reference

shallow , deep copies


There are 2 diff types of copy operations for container
objects, such as lists and dictionaries: shallow copy,
deep copy.
A shallow copy:
- creates a new object
- fills it with references to the items contained in the original
object. Example:
>>> a = [ 1, 2, [3,4] ]
>>> b = list(a) # Create a shallow copy of a.
>>> b is a
False

Shallow copies merits


>>> b.append(100)
>>> b
[1, 2, [3, 4], 100]

# Append element to b.

>>> a
# Notice that a is unchanged
[1, 2, [3, 4]]
>>> b[2][0] = -100 # Modify an element inside b
>>> b
[1, 2, [-100, 4], 100]
>>> a # Notice the change inside a
[1, 2, [-100, 4]]

How it works
In this case, a and b are separate list objects, but

the elements they contain are shared.


Therefore, a modification to one of the elements
of a also modifies an element of b, as shown.
A deep copy creates a new object and recursively

copies all the objects it contains.


There is no built-in operation to create deep
copies of objects.

copy.deepcopy()
The copy.deepcopy() function in copy module does
it, example:
>>>
>>>
>>>
>>>
>>>

import copy
a = [1, 2, [3, 4]]
b = copy.deepcopy(a)
print a is b, a==b # False, True
b[2][0] = -100

>>> b
[1, 2, [-100, 4]]
>>> a
[1, 2, [3, 4]]

# a is not changed

(problems: when some element recursively points to itself)

Three ways to shallow


Each of the follows produces a shallow copy of
iterable x:
y=list(x)
y=x[:]
y=copy.copy(x)

First class objects

First-Class Objects
All objects in Python are first class,
meaning that:

- all objects that can be named by an identifier,


have equal status.
- all objects that can be named, can be treated
as data.

First class Example


A simple dictionary with two values:

items = { 'number' : 42
'text' : "Hello World"
}
Lets add some special items to this dictionary.

items["func"] = abs # Add the abs() function


import math
items["mod"] = math # Add a module
items["error"] = ValueError # Add an exception type
nums = [1,2,3,4]
items["append"] = nums.append # Add a meth of another object

First class example


The items dictionary contains: a function, a module, an
exception, and a method of another object.
Use the keys as the prev items, Example:
>>> items["func"](-5) # Executes abs(-5)
5
>>> items["mod"].sqrt(9) # Executes math.sqrt(9)
3.0
>>>try:
x = int("Iosi")
except items["error"] as e: # Same as except ValueError as e
print "Couldn't convert"
Couldn't convert

First class Example cont.


>>>

items["append"](Ety)

>>> nums
[1, 2, 3, 4, Ety]
Writing very compact code is possible because
everything in Python is first-class.

Another First class example


Given a line of text such as:
"Iosi, 1, 3.14, Malka"

lets convert it into a list of elements with the right


type-conversion.

- create a list of types (which are first-class objects)


- execute a few simple list processing operations:

Cont.
>>> line = "Iosi, 1, 3.14, Malka"
>>> field_types = [str, int, float, str]
>>> raw_fields = line.split(',')
>>> fields = [ty(val) for ty,val in
zip(field_types,raw_fields)]
>>> fields
['Iosi', 1, 3.14, 'Malka']

Aliasing function names

Did you know ?


You can bind a name to a known respectable
function, and use it instead :

>>> Iosi=len
>>> Iosi('abc')
3
>>> Ety = type

>>> Ety(2)
<type 'int'>
(Just dont forget the new names)
11/8/2014 10:37:29 PM

79

Write your functions


>>> def mySquare(x) :
return x*x

# function declaration

>>> mySquare(7)
49

# function call

>>> def mySquarePlusAnything(x,anything):


return x*x+mySquare(anything)
>>> mySquarePlusAnything(6,4)
50

11/8/2014 10:37:29 PM

# function call

80

elseing with the loops


In python
Loops (for,while)may have
an else part

Else and the loops


The else clause of a loop is executed only if :
- the loop ends naturally, or if
- the loop did not start/execute at all.
If the loop is un-naturally terminated by a
break statement (or by some exception),
- the else clause is skipped.
Why: As a simple signal of what happened in the
loop.
11/8/2014 10:37:29 PM

82

else example
while value < limit:
if value == x:
print "Found it!"
break
value+=y
else: # see the else indentation
print x its not there ! "
11/8/2014 10:37:29 PM

83

You might also like