Plan For Python Lecture 2 § Review § List Comprehensions Review § Iterators, Generators § Imports >>>import this § Functions The Zen of Python, by Tim Peters § *args, **kwargs, first class functions § Classes § inheritance § “magic” methods (objects behave like built-in types) § Profiling § timeit § cProfile § Idioms CIS 391 - Fal l 2015 Intro to AI 1

List Comprehensions List Comprehension extra for [ for in if ]

#Translation [x for x in lst1 if x > 2 for y in lst2 for z in lst3 lst = [] if x + y + z < 8] for in : if : res = [] # translation lst. app end() for x in lst1: if x > 2: >>> li = [(‘a’, 1), (‘b’, 2), (‘c’, 7)] for y in lst2: >>> [ n * 3 for (x, n) in li if x == ‘b’ or x = = ‘ c’] for z in lst3: [6, 2 1] if x + y + z > 8: #Translation res.append(x) lst = [] for (x,n) in li: if x == ‘b’ or x == ‘c’ : lst.append(n *3)

CIS 391 - Fal l 2015 Intro to AI 3 CIS 391 - Fal l 2015 Intro to AI 4

Iterators use memory efficiently Generators (are iterators) § Iterators are objects with a next() method: § Function def reverse(data): § To be iterable: __iter__() for i in range(len(data)-1, -1, -1): § To be iterators: next() yield data[i]

Generator Expression >>> k = [1,2,3] § (data[i] for index in range(le n(da ta) -1, -1, -1)) >>> i = iter(k) # co uld als o u se k .__ iter __( ) >>> i.next() >>> xvec = [10, 20, 30] 1 >>> yvec = [7, 5, 3] >>> i.next() >>> sum(x *y f or x,y in zip(xve c, yvec)) # dot pr odu ct 2 260 >>> i.next() 3 § Lazy Evaluation (on demand, values generated) >>> i.next() StopIteration

CIS 391 - Fal l 2015 Intro to AI 5 CIS 391 - Fal l 2015 Intro to AI 6

1 Import Modules and Files >>> import math >>> math.sqrt(9) 3.0

# NOT: >>> from math import * >>> sqrt(9) # unclear where function defined Functions #hw1.py def concatenate(seqs ): return [seq for seq in seqs] # Th is i s w rong (Methods later) # run python interactive interpreter (REPL) in directory with hw1.py >>> import hw1 >>> assert hw1.concatenate([[1, 2], [3, 4]]) == [ 1, 2, 3 , 4] #AssertionError >>> reload(hw1) #after fixing hw1

CIS 391 - Fal l 2015 Intro to AI 7

Defining Functions Function overloading? No.

Function definition begins with def Function name and its arguments.

§ There is no function overloading in Python. def get_final_answer(filename): § Unlike Java, a Python function is specified by its name alone """Documentation String""" Two different functions can’t have the same name, even if they line1 § have different numbers, order, or names of arguments. line2 Colon return total_counter ... § But operator overloading – overloading +, ==, -, etc. – is possible using special methods on various classes (see later slides)

First line with less ‘return’ indicates the indentation is considered to be value to be sent back to the caller. outside of the function definition. No declaration of typesof arguments or result CIS 391 - Fal l 2015 Intro to AI 9 CIS 391 - Fal l 2015 Intro to AI 10

Default Values for Arguments Keyword Arguments

§ You can provide default values for a function’s arguments § Functions can be called with arguments out of order § These arguments are optional when the function is called § These arguments are specified in the call >>> def myfu n(b , c= 3, d=“h ell o”): § Keyword arguments can be used for a final subset of ret urn b + c the arguments.

>>> myfun(5, 3,”bob”) >>> def myfu n (a, b, c): 8 re turn a-b >>> myfun(5, 3) >>> myfun(2, 1, 43) 8 1 >>> myfun(5) >>> myfun(c= 43, b=1 , a =2) 8 1 >>> myfun(2, c=43, b=1) 1 >>> myfun(a= 2, b=3, 5) SyntaxError: non-ke ywo rd arg afte r k eywo rd arg

CIS 391 - Fal l 2015 Intro to AI 11 CIS 391 - Fal l 2015 Intro to AI 12

2 *args **kwargs § Suppose you want to accept a variable number of § Suppose you want to accept a variable number of non-keyword arguments to your function. keyword arguments to your function. def print_keyword_args(**kw arg s): def print_everything(*args): # kwargs is a di ct of the keyword args pa sse d to th e fn # args is a t upl e o f ar gum ents pa ssed to the fn for key, value in kwargs.iteritems(): #. item s() is list for count, thing in enumerate(arg s): print "% s = % s" % ( key , va lue ) print '{ 0}. { 1} '.fo rma t(co unt , th ing ) >>> lst = ['a ', ’ b', 'c ’] >>> kwargs = { 'first_name': 'B obby ', ' las t_n ame': 'Smith'} >>> print_everything(*lst) >>> print_keyword_args(**kw arg s) 0. a first_name = J oh n 1. b last_name = Doe 2. c >>> print_keyword_args(firs t_n ame="John”, la st_n ame ="Do e") >>> print_everything('a ', ’ b', 'c' ) # Combining ideas foo(arg1, *ar gs, **kwargs) # o ne m and ator y a rgum ent CIS 391 - Fal l 2015 Intro to AI 13 CIS 391 - Fal l 2015 Intro to AI 14

Scope Default Arguments & Memoization § Function sees the most current value of variables § Default parameter values are evaluated only when the def statement they belong to is executed. >>> i = 10 § The function uses the same default object each call def add(x): return x + i def fib(n, fibs={}): if n in fibs: >>> add(5) return fibs[n] 15 if n <= 1: >>> i = 20 fibs[n] = n >>> add(5) else: 25 fibs[n] = fi b(n -1) + f ib(n -2) return fi bs[ n]

CIS 391 - Fal l 2015 Intro to AI 15 CIS 391 - Fal l 2015 Intro to AI 16

First Class Functions Higher Order Functions: Map, Filter § Functions are “first-class citizens” >>> [int(i) for i in ['1', '2']] § Pass functions as arguments to other functions, [1, 2] >>> map(int, ['1', '2']) #equivalent to above § returning functions as the values from other functions, [1, 2] § Assign functions to variables or store them in data structures § Higher order functions: take functions as input def is_even(x): return x % 2 == 0 def compose(f, g, x): >>> [i for i in [1, 2, 3, 4, 5] i f is_even (i)] return f( g (x)) [2, 4] >>> compose(str, sum, [1,2,3]) >>> filter(is_even , [1, 2, 3, 4, 5]) [2, 4] #equivalent to above '6' >>> t1 = (0, 10) >>> t2 = (100, 2) >>> min([t1, t2], key= lambda x: x[1]) (100, 2)

CIS 391 - Fal l 2015 Intro to AI 17 CIS 391 - Fal l 2015 Intro to AI 18

3 Sorted list of n-grams from operator import it emge tte r def calc_ngram(inputstring, nl en): ngram_list = [inpu tst ring [x: x+nl en] for x i n \ xrange(le n(in put stri ng)-nle n+1 )] ngram_freq = {} # dict fo r s tori ng r esu lts for n in ng ram _lis t: # collect the distinct n-gra ms a nd Classes and Inheritance count if n in ngram_freq: ngram_freq[n] + = 1 else: ngram_freq[n] = 1 # h uma n co unt ing n um bers st art a t 1 # reverse = False to change order of sort (ascending/descending) return sorted(ngra m_f req. ite rite ms(), \ key=itemgetter(1 ), r eve rse =Tru e) http://times.jayliew.com/2010/05/20/a-simple-n-gram-calculator-pyn gram/ CIS 391 - Fal l 2015 Intro to AI 19

Called when an Creating a class object is Subclasses instantiated Class Student: § A class can extend the definition of another class univ = ”upenn” # class attribute Every method begins with the § Allows use (or extension ) of methods and attributes already defined in the previous one. variable self def __init__(self, name, dept): § New class: subclass. Original: parent, ancestor or superclass self.student_name = name self.student_dept = dept § To define a subclass, put the name of the def print_details(self): Another member superclass in parentheses after the subclass’s print "Name: " + self.student_name method name on the first line of the definition. print "Dept: " + self.student_dept cl ass ai_ stu dent (st uden t): Creating an instance, student1 = Student(”john", "cis") note no self § Python has no ‘extends’ keyword like Java. student1.print_details() Student.print_details(student1) Calling methods § Multiple inheritance is supported. Student.univ of an object

CIS 391 - Fal l 2015 Intro to AI 21 CIS 391 - Fal l 2015 Intro to AI 22

Redefining Methods __init__constructors in subclasses: § Very similar to over-riding methods in Java § UNLIKE Java: To execute the ancestor’s __init__ § To redefine a method of the parent class, include a new method the ancestor’s __init__ must be called explicitly definition using the same name in the subclass. (if the descendants __init__ is specified) § The old code won’t get executed.

§ To execute the method in the parent class in addition to § The first line of the __init__ method of a subclass will new code for some method, explicitly call the parent’s often be: version of the method. parentClass.__init__(x, y) super(se lf._ _cl ass__, self).__ini t__ (x, y ) # equ iva lent parentClass.methodName(self, a , b , c ) § The only time you ever explicitly pass self as an argument is when calling a method of an ancestor.

So: myOwnClass.methodName(a,b,c)

CIS 391 - Fal l 2015 Intro to AI 23 CIS 391 - Fal l 2015 Intro to AI 24

4 Multiple Inheritance class A(object): def foo(self): print 'Foo!' class B(object): def foo(self): Special Built-In print 'Foo?' Methods and Attributes def bar(sel f): print 'Bar!'

class C(A, B): def foobar(self): super(C, self).foo() # Foo! super(C, self).bar() # Bar!

CIS 391 - Fal l 2015 Intro to AI 25

Magic Methods and Duck Typing Other “Magic” Methods § Magic Methods allow user-defined classes to behave § Used to implement operator overloading like built in types § Most operators trigger a special method, dependent on class § Duck typing establishes suitability of an object by determining presence of methods __init__: The constructor for the class. § Does it swim like a duck and quack like a duck? It’s a duck __len__ : Define how len( obj ) works. § Not to be confused with ‘rubber ducky debugging’ __copy__: Define how to copy a class. class student: __cmp__ : Define how == works for class. ... __add__ : Define how + works for class def __repr__(s elf) : return “I ’m n ame d ” + self.full_name + “ – age: , ”, __neg__ : Define how unary negation works for class self.age ... § Other built-in methods allow you to give a class the >>> f = student(“Bob Sm ith” , 2 3) >>> print f ability to use [ ] notation like an array or ( ) notation I’m named Bob Smith – age: 23 like a function call.

CIS 391 - Fal l 2015 Intro to AI 27 CIS 391 - Fal l 2015 Intro to AI 28

A directed graph class A directed graph class

>>> d = D iG r ap h ([ ( 1, 2 ), ( 1, 3 ), ( 2, 4 ), ( 4, 3 ), ( 4, 1 )] ) >>> d = D iG r ap h ([ ( 1, 2 ), ( 1, 3 ), ( 2, 4 ), ( 4, 3 ), ( 4, 1 )] ) >>> print d >>> [v for v in d.search(1)] 1 -> 2 [1, 2, 4, 3] 1 -> 3 2 2 1 >>> [v for v in d.search(4)] 1 2 -> 4 [4, 3, 1, 2] 4 -> 3 4 -> 1 >>> [v for v in d.search(2)] 3 [2, 4, 3, 1] 3 4 >>> [v for v in d.search(3)] 4 [3]

search meth o d retu rn s a generator for the nodes that can be reached from a given node by following arrows “from tail to head” CIS 391 - Fal l 2015 Intro to AI 29 CIS 391 - Fal l 2015 Intro to AI 30

5 The DiGraph constructor The search method 1 2 class DiGraph: 1 2 de f _ _ini t__ (sel f, edge s): class DiGraph: self.adj = {} ... 3 for u,v in edge s: 3 4 if u no t in se lf.a dj: sel f.a dj[u ] = [v] 4 de f search(self, u, visited=set()): else : self.adj[u].append(v) # If we haven't already visited this node... if u not in vis ite d: de f _ _str __( self ): # yiel d i t return '\n' .joi n([ '%s -> %s'% (u, v) \ yi eld u for u i n se lf. adj for v i n s elf. adj [u]] ) # and rem embe r w e've vi site d i t no w. .. . vi site d.a dd(u ) # Then , i f th ere are an y ad jac ent nod es.. . >>> d = Di Gra ph([ (1, 2),( 1,3 ),(2 ,4) ,(4, 3), (4,1 )]) if u in self.adj: >>> d.adj # fo r e ach adj acen t n ode. .. {1: [2, 3], 2: [4], 4: [3, 1]} for v in se lf. adj[ u]: # sea rch for all no des rea chab le from *i t*.. . The constructor builds a dictionary (self.adj) fo r w in sel f.se arc h(v, visited): mapping each node name to a list of node names that can # a nd y iel d ea ch one. yie ld w be reached by following one edge (an “adjacency list”) `

CIS 391 - Fal l 2015 Intro to AI 31 CIS 391 - Fal l 2015 Intro to AI 32

Profiling, function level Profiling, script level § Rudimentary #to_time.py >>> import ti me >>> t0 = time.time() def get_number() : >>> code_block for x in xrange(500000): >>> t1 = time.time() yield x >>> total = t 1-t0 § Timeit (more precise) def exp_fn(): >>> import ti mei t for x in get_number(): >>> t = timeit.Timer(”< stat eme nt t o t ime> ", ” ") return 's ome res ult !’ >>> t.timeit() § The second argument is usually an import that sets up a if __name__ == '__main__': virtual environment for the statement exp_fn() § timeit calls the statement 1 million times and returns the total elapsed time

CIS 391 - Fal l 2015 Intro to AI 33 CIS 391 - Fal l 2015 Intro to AI 34

Profiling, script level Idioms #python interactive interpreter (REPL) § Many frequently-written tasks should be written Python-style even though you could write them $ python -m cProfile to_time.py Java-style in Python 500004 function calls in 0.203 seconds Ordered by: standard name § Remember beauty and readability! ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.203 0.203 to_time.py:1() 500001 0.071 0.000 0.071 0.000 to_time.py:1(get_number) § http://safehammad.c om/downloads/python- 1 0.133 0.133 0.203 0.203 to_time.py:5(exp_fn) idioms-2014-01-16.pdf 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}

§ If you need real speed (eg real time voice recognition), write C++

CIS 391 - Fal l 2015 Intro to AI 35 CIS 391 - Fal l 2015 Intro to AI 36

6 Review § Types, Objects, Mutability, References § Data Types: § Sequences: list, string, tuple; dictionary, set § Looping § Comprehensions § Iterators, Generators, Generator expressions § Functions § *args, **kwargs, first-class functions § Classes § Inheritance, “magic” methods § Profiling § timeit, cProfile § Idioms

CIS 391 - Fal l 2015 Intro to AI 37

7