Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Python Programming by Chris Seddon Copyright ©2000-15 CRS Enterprises Ltd 1 Python Programming 1.Introduction to Python 2.The Basics 3.More on Data Types 4.Functions 5.Classes and Objects 6.Modules and Packages 7.Installing Packages 8.Files 9.Attribute Lookup 10. Advanced Techniques 11. Decorators 12. Regular Expressions Copyright ©2000-15 CRS Enterprises Ltd 13.Exception Handling 14.Unit Test 15.Inheritance 16.Threading 17.Extending and Embedding 18.Meta Classes 19.Oracle Database 20.Operator Overloading 21.Web Application Frameworks 22.JSON and XML 23.Miscellaneous Topics 3 1 Introduction to Python IronPython Copyright ©2000-15 CRS Enterprises Ltd 6 What is Python? Python is a Dynamic Scripting Language not a static language like C++, C# and Java easy to learn no compile step can be run a line at a time inside an interpreter (REPL) Supports both Object Oriented and Functional styles often described as an agile language ideal for rapid prototyping and testing often used as a plug-in to a C++ or Java system extensive library Python Virtual Machine garbage collection reference counted objects Copyright ©2000-15 CRS Enterprises Ltd 7 Advantages of Python Python is often used ... to develop small programs and scripts simple programs can be created very quickly ... but can be used for large-scale programming projects sophisticated module and packaging scheme extensive object oriented support Python has a modern design more natural coding style than other languages highly portable Copyright ©2000-15 CRS Enterprises Ltd 8 What is Jython? Jython is an implementation of Python that compiles to Java byte code runs on any JVM highly portable thread safe Jython currently supports the Python syntax at level 2.5 Jython Libraries uses Java libraries because of the JVM NOT standard Python libraries Copyright ©2000-15 CRS Enterprises Ltd 9 What is Iron Python? .NET framework version of Python runs in the CLR only used on Windows systems (and mono) Iron Python currently supports the Python syntax at level 2.7 Iron Python Libraries uses .NET libraries and Python libraries Copyright ©2000-15 CRS Enterprises Ltd 10 Everything is Interpreted Python is an interpreted language no compile step as in Java and C++ each time Python code is run it is interpreted afresh into byte code unless byte code cached internally Code can also be entered interactively in the REPL myfile.py compile Python byte code interpret Python interpreter Target Hardware Copyright ©2000-15 CRS Enterprises Ltd 11 Performance Python is interpreted much slower than a compiled language such as C/C++ increased design and coding flexibility more than makes up for performance loss Python libraries usually written in C/C++ a large proportion of the Python library is written in C/C++ as is the interpreter itself mitigates poor performance of pure Python Python has modules to measure performance profile, cProfile Copyright ©2000-15 CRS Enterprises Ltd 12 Invoking Python 1. From the Command Line code is entered one line at a time see the results immediately ideal way to learn Python 2. Use Python Script files interpreted by the Python runtime source files can be combined using modules for larger applications 3. IDEs e.g. PyDev plug-in for Eclipse PyDev is very mature (10+ years development) full debugging support Copyright ©2000-15 CRS Enterprises Ltd 13 Python Distributions Python home page http://www.python.org/ Major Releases Python 3.4.3 February, 2015 Python 3.4.2 October, 2014 Python 3.4.1 May, 2014 Python 3.4.0 March, 2014 Python 2.7.9 December, 2014 Python 2.7.8 July, 2014 Python 2.7.7 June, 2014 Python 2.7.6 November, 2013 Jython 2.7 Beta 4 February, 2015 Jython 2.7 Beta 3 August, 2014 Iron Python 2.7.5 December, 2014 Copyright ©2000-15 CRS Enterprises Ltd 14 Python Resources Python docs http://www.python.org/doc/ http://docs.python.org/modindex.html ActiveState Python http://www.activestate.com/activepython/ Python Tutorial by Guido van Rossum http://www.python.org/doc/2.2.3/tut/tut.html Python Cookbook http://oreilly.com/catalog/9780596007973/ Copyright ©2000-15 CRS Enterprises Ltd 15 Books Python Essential Reference, Fourth Edition By: David M. Beazley Publisher: Addison-Wesley Professional The Definitive Guide to Jython: Python for the Java™ Platform By: Josh Juneau; Jim Baker; Victor Ng; Leo Soto; Frank Wierzbicki Publisher: Apress Expert Python Programming: Learn best practices to designing, coding, and distributing your Python software By: Tarek Ziadé Publisher: Packt Publishing Copyright ©2000-15 CRS Enterprises Ltd 16 2 The Basics Copyright ©2000-15 CRS Enterprises Ltd 20 A "Hello World" Example Trivial one liner in Python you don’t even require a semi-colon! print "Hello World!" Copyright ©2000-15 CRS Enterprises Ltd 21 Comments and Indentation # for comments Indentation instead of braces # this is a comment x = 100 y = 200 if x + y < 500: print "sum is less than 500" colon indent Copyright ©2000-15 CRS Enterprises Ltd 22 Input Input is converted to a string may need to use a cast x = int(raw_input("Please enter an integer: ")) x=x+1 Please enter an integer: -5 Copyright ©2000-15 CRS Enterprises Ltd 23 if Statements x = int(raw_input("Please enter an integer: ")) if x < 0: print 'Negative' Please enter an integer: -5 Negative Copyright ©2000-15 CRS Enterprises Ltd 24 if Statements x = int(raw_input("Please enter a positive integer: ")) if x > 0: print 'x is positive' print 'the square of x is', x * x print 'the cube of x is', x * x * x print 'End of if-statement' Please enter a positive integer: 66 x is positive the square of x is 4356 the cube of x is 287496 End of if-statement Copyright ©2000-15 CRS Enterprises Ltd 25 if-else Statements x = int(raw_input("Please enter an integer: ")) if x < 0: print 'Negative' else: print 'Not negative' Please enter an integer: 5 Not negative Please enter an integer: -5 Negative Copyright ©2000-15 CRS Enterprises Ltd 26 if-elif-else Statements x = int(raw_input("Please enter an integer: ")) if x < 0: print 'Negative' elif x == 0: print 'Zero' elif x == 1: print 'One' else: print 'Greater than one' Copyright ©2000-15 CRS Enterprises Ltd Please enter an integer: -3 Negative Please enter an integer: 0 Zero Please enter an integer: 1 One Please enter an integer: 7 Greater than one 27 Conditional if Statements x = 100 result = (-1 if x < 0 else 1) print result x = -200 result = (-1 if x < 0 else 1) print result 1 -1 Copyright ©2000-15 CRS Enterprises Ltd 28 for Statements for x in (10,17,24,31,38,45,52,59,66,73,80,87,94): print x, print for x in range(10,100,7): print x, 10 17 24 31 38 45 52 59 66 73 80 87 94 10 17 24 31 38 45 52 59 66 73 80 87 94 Copyright ©2000-15 CRS Enterprises Ltd 29 for-else Statements for x in (1,2,3,4,5,6): print x, else: print "only get here if all iterations succeed ..." for x in (1,2,3,4,5,6): print x, if x > 3: break else: print "only get here if all iterations succeed ..." 1 2 3 4 5 6 only get here if all iterations succeed ... 1234 Copyright ©2000-15 CRS Enterprises Ltd 30 while Statements formula = 0 x=0 while formula < 1000: x=x+1 formula = 2*x*(x + 1) print x, formula Copyright ©2000-15 CRS Enterprises Ltd 1 4 2 12 3 24 4 40 5 60 6 84 7 112 8 144 9 180 10 220 11 264 12 312 13 364 14 420 15 480 16 544 17 612 18 684 19 760 20 840 21 924 22 1012 31 Integers/Long Unlimited precision decimals, octal and hexadecimal x = 300 x = 053 x = 0xFF # decimal # octal # hex x=1 for n in range(1,50000): ... x=x*n 8640372151906087336721162787027740701980046703537693007160454743 print x 0881028943029710890094952575983102831942332098801078767873403184 3812303645836587362298825375962390412214818730218601896401786005 4217856498897415140571330537697495383717507271695713173805885868 6051525163484354006340593710441714431751346890331014890001250991 3262093824861142024508385572268159407796321465886842319191296757 8078562876393851213501459437877878620141455136735126924004144819 7911187026793326350625732189630574843722324400961845552066777053 7106542144272488920866258356532973475712072964180507234862689087 6456030420157452090095580448550503063205853759254527374217561203 7061462858200453655527745928196559852331864722970592646723758606 ... Copyright ©2000-15 CRS Enterprises Ltd 32 Booleans Values True, False Operators and, or x = True y = False z = x or y print z True z = x and y print z print type(z) False <type 'bool'> Copyright ©2000-15 CRS Enterprises Ltd 33 Floating Point 13 significant figures on 32 bit implementation no exact representation # floating point x = 1e6 + 0.000001e-4 format = "%32.20g" print type(x) print (format % x) <type 'float'> 1000000.0000000001 Copyright ©2000-15 CRS Enterprises Ltd 34 Complex Numbers floating types real and imaginary parts can be extracted separately x = (+2.5-3.4j) - (-1.4+1.0j) print type(x) print x print x.real print x.imag Copyright ©2000-15 CRS Enterprises Ltd <type 'complex'> (3.9-4.4j) 3.9 -4.4 35 None special type NoneType x = 120 print type(x) print x x = None # not defined print type(x) print x <type 'int'> 120 <type 'NoneType'> None 240 if (x == None): x = 240 print x Copyright ©2000-15 CRS Enterprises Ltd 36 3 More On Data Types Immutable Types int/long float tuple frozen set Mutable Types list dict set Copyright ©2000-15 CRS Enterprises Ltd 40 Object References All data types are objects x is an object reference (pointer) can point to any type of object int float bool NoneType str str list tuple dict x = 200 x = 5.734 x = True x = None x = 'Hello' x = "Goodbye" x = [2,3,5,7,11,13,17] x = (2,3,5,7,11,13,17) x = { 'Tom':23000, 'Sue':24500, 'Zoe':21800} Copyright ©2000-15 CRS Enterprises Ltd 41 Immutable Types Several types are immutable int, float, str, NoneType, tuple state cannot be modified after object is created Immutable objects are often useful because they are inherently thread-safe What happens when you try to change an immutable object? id(x) = unique id of object pointed at by x x = 100 print id(x) 10053412 x=x+1 print id(x) 10053400 x points to a different object Copyright ©2000-15 CRS Enterprises Ltd 42 Mutable Types Several types are mutable list, dict, class Operations change state id of object doesn't change x = [2,3,5,7,11,13,17] print id(x) x.append(23) print id(x) print x Copyright ©2000-15 CRS Enterprises Ltd 43143336 43143336 [2, 3, 5, 7, 11, 13, 17, 23] 43 Strings ... immutable single or double quotes triple quoting for multi-line strings x = 'hello' y = "from" z = """the planet earth""" print type(x) print x, y, z <type 'str'> hello from the planet earth HELLO FROM THE PLANET EARTH phrase = x + " " + y + " " + z print phrase.upper() Copyright ©2000-15 CRS Enterprises Ltd 44 ... Strings Many string manipulation methods available original string is unchanged new string returned s = "---abc:xyz:123---" t = s.lower() t = s.lstrip("-") t = s.replace(":","@") t = s.rstrip("-") t = s.split(":") t = s.strip("-") t = s.swapcase() t = s.upper() Copyright ©2000-15 CRS Enterprises Ltd ---abc:xyz:123--abc:XYZ:123-----abc@XYZ@123-----abc:XYZ:123 ['---abc', 'XYZ', '123---'] abc:XYZ:123 ---ABC:xyz:123-----ABC:XYZ:123--- 45 Printing Use the format method on strings x = 6.5 y = 1208.5632 z = 200 x=6.5, y=1208.5632, z=200 x= 6.5000, y=1208.5632, z=200.0000 print "x={0}, y={1}, z={2}".format(x, y, z) print "x={0:8.4f}, y={1:8.4f}, z={2:8.4f}".format(x, y, z) Copyright ©2000-15 CRS Enterprises Ltd 46 Tuple immutable can be nested note syntax for a single item tuple x1 = () x2 = (1,) x3 = (1,2,3) x4 = (1, "mixed", 2, "tuple") x5 = ((1,2),(3,4)) Copyright ©2000-15 CRS Enterprises Ltd 47 List mutable can be nested x1 = [ ] x2 = [1] x3 = [1,2,3] x4 = [1, 'mixed', 2, 'tokens'] x5 = [[1,2],[3,4]] Copyright ©2000-15 CRS Enterprises Ltd 48 Memory Layout mylist = [ (10,20), [30,40] ] list mylist tuple 10 Copyright ©2000-15 CRS Enterprises Ltd list 20 30 40 49 Using range use range to iterate a fixed number of times for x in range(1,10): print x, 123456789 Copyright ©2000-15 CRS Enterprises Ltd 50 Modifying Lists Lists can be extended with another list List can be appended adds an element to a list list1 = [10, 20, 30] list2 = [55, 56, 57] list2.extend(list1) print list [55, 56, 57, 10, 20, 30] list2.append(list1) print list2 [55, 56, 57, 10, 20, 30, [10, 20, 30]] Copyright ©2000-15 CRS Enterprises Ltd 51 Accessing Lists and Tuples only lists can be modified tuples are immutable mylist = [10, 20, 30] mytuple = (10, 20, 30) y = mytuple[0] y = mytuple[1] y = mytuple[2] x = mylist[0] x = mylist[1] x = mylist[2] mylist[1] = 99 mylist.append(40) print mylist [10, 99, 30, 40] Copyright ©2000-15 CRS Enterprises Ltd 52 Casting between Lists and Tuples use a cast to convert tuple( ... ) list( ...) theList = [2, 3, 5, 7, 11, 13, 17] myTuple = tuple(theList) myList = list(myTuple) print myTuple print myList Copyright ©2000-15 CRS Enterprises Ltd (2, 3, 5, 7, 11, 13, 17) [2, 3, 5, 7, 11, 13, 17] 53 List Methods To remove an element use del or pop() To check for existence use in myList = [1,2,3,4,5,6] del myList[3] item = myList.pop(3) print myList [1, 2, 3, 6] a=3 if a in myList: print "list contains a" list contains a Copyright ©2000-15 CRS Enterprises Ltd 54 Slices Sequences support slicing selects a range of elements x[1:3] selects the second through third elements of x the end index is always one past the selection assignment slicing replaces multiple elements x[3:5] = (5,4) colors = ["red", "blue", "green", "white", "black"] print colors[1] print colors[1:3] print colors[1:] print colors[-3:-1] print colors[4:1:-1] colors[2:4] = ("purple", "cyan") print colors[0:]; Copyright ©2000-15 CRS Enterprises Ltd blue ['blue', 'green'] ['blue', 'green', 'white', 'black'] ['green', 'white'] ['black', 'white', 'green'] ['red', 'blue', 'purple', 'cyan', 'black'] 55 Dictionary like a database table also called hash, associative array key:value pairs keys usually a string keys must be immutable very efficient lookups empty = { } months = {"Jan":1, "Feb":2, "May":5, "Dec":12} seasons = {"Spring":("Mar","Apr","May"), "Summer":("Jun","Jul","Aug")} print type(empty) print months["Dec"] print seasons["Summer"] Copyright ©2000-15 CRS Enterprises Ltd <type 'dict'> 12 ('Jun', 'Jul', 'Aug') 56 Working with Dictionaries Dictionaries are mutable modify existing entries add new entries Key Order is indeterminate because of hashing algorithm salary = { "zak": 34000, "sara": 27000, "pedro": 52000, "jo": 12500, "zoe": 66000 } print salary["pedro"] salary["jo"] = 15000; # modify existing salary["peter"] = 35000 # add new entry Copyright ©2000-15 CRS Enterprises Ltd 57 Initialization Use { } or constructor salary1 = { "zak": 34000, "sara": 27000, "pedro": 52000, "kilas": 12500, "zoe": 66000 } salary2 = dict( zak = 34000, sara = 27000, pedro = 52000, kilas = 12500, zoe = 66000) Copyright ©2000-15 CRS Enterprises Ltd 58 Inserting or Updating New elements ... are added salary["sara"] = 28000 Existing elements ... are updated salary["sara"] = 29000 Copyright ©2000-15 CRS Enterprises Ltd 59 Removing Keys Use del statement del salary["zak"] or Use pop salary.pop("zak") Copyright ©2000-15 CRS Enterprises Ltd 60 Removing Values Assign key to None previous value gets garbage collected salary["sara"] = None Copyright ©2000-15 CRS Enterprises Ltd 61 Common Functions ... Extract all the keys, and all the values # create list of keys theKeys = salary.keys() # create list of values theValues = salary.values() # get key value pairs as a list list_of_key_value_pairs = salary.items() Copyright ©2000-15 CRS Enterprises Ltd 62 ... Common Functions Work with keys, values or both # print all the keys for key in salary.iterkeys(): print key, print # print all the values for value in salary.itervalues(): print value, print # print all <key,value> pairs for key, value in salary.iteritems(): print key, value Copyright ©2000-15 CRS Enterprises Ltd 63 Set and FrozenSet ... unordered collections of unique elements Set (mutable) FrozenSet (immutable) myset = set(("Monday", "Tuesday")) myset.add("Wednesday") myset.add("Thursday") myset.add("Friday") print myset if "Wednesday" in myset: print "member" myset.remove("Wednesday") if "Wednesday" not in myset: print "not a member" Copyright ©2000-15 CRS Enterprises Ltd set(['Friday', 'Tuesday', 'Thursday', 'Wednesday', 'Monday']) member not a member 64 ... Set and FrozenSet Set supports mathematical operations union, intersection and symmetric difference sequence1 = 1, 3, 5, 7, 5, 4, 3, 2, 1 sequence2 = 2, 4, 6, 8, 6, 4, 3, 2, 1 set1 = set(sequence1) set2 = set(sequence2) print(set1) set([1, 2, 3, 4, 5, 7]) print(set2) set([1, 2, 3, 4, 6, 8]) unionSet = set1.union(set2) intersectionSet = set1.intersection(set2) differenceSet = set1.symmetric_difference(set2) print(unionSet) set([1, 2, 3, 4, 5, 6, 7, 8]) print(intersectionSet) set([1, 2, 3, 4]) print(differenceSet) set([5, 6, 7, 8]) Copyright ©2000-15 CRS Enterprises Ltd 65 4 Functions Copyright ©2000-15 CRS Enterprises Ltd 68 Functions square is an object reference not the name of the function the function is an object all objects are anonymous def square(n): print n * n square(5) square(6) square(7) square Copyright ©2000-15 CRS Enterprises Ltd 25 36 49 print n * n 69 Function Aliases You can point two or more references at a function or point the reference elsewhere as in fib = 42 def fib(n): a, b = 0, 1 while b < n: print b, a, b = b, a+b print fib(1000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 f = fib f(100) fib = 42 1 1 2 3 5 8 13 21 34 55 89 Copyright ©2000-15 CRS Enterprises Ltd 70 return Statements use return statements to ... pass data back to the calling program return a tuple or list if you need to return more than one piece of data def average(a, b): return (a + b)/2.0 x = average(5, 7) print x 6.0 x = average(5.5, 7.7) print x 6.6 print average(10.5, 12.5) 11.5 Copyright ©2000-15 CRS Enterprises Ltd 71 Function with Mutable Data With mutable data ... no need to use a return statement no need to assign the return in the calling program Mutable data can be modified in the function changes are seen in the calling program def addOneElement(m): m.append(99) mylist = [12, 15, 18] addOneElement(mylist) print mylist [12, 15, 18, 99] Copyright ©2000-15 CRS Enterprises Ltd 72 Function with Immutable Data Object references are copied when a function is called the addresses are copied and copied on return With immutable data you must ... use a return statement assign the return in the calling program def swap(a,b): return b,a x = 100 y = 200 x,y = swap(x,y) print x, y 200 100 Copyright ©2000-15 CRS Enterprises Ltd 73 How not to Swap no_swap fails because no return statement no assignment in the calling program def no_swap(a,b): temp = a a=b b = temp x = 100 y = 200 no_swap(x,y) print x, y 100 200 Copyright ©2000-15 CRS Enterprises Ltd 74 Swapping Lists Lists are mutable data, so ... no need to use a return statement no need to assign in the calling program def swap(theList): theList [0], theList[1] = theList[1],theList[0] mylist = [100,200] swap(mylist) print mylist [200, 100] Copyright ©2000-15 CRS Enterprises Ltd 75 Default Parameter Values Default parameters can be either: positional or named def Display(a, b=10, c=100): print ("a=%6.1f " % a), ("b=%6.1f " % b), ("c=%6.1f" % c) Display(19, 6.2, 4.8) Display(17) Display(17, 21) Display(17, c=0) Copyright ©2000-15 CRS Enterprises Ltd a= a= a= a= 19.0 17.0 17.0 17.0 b= b= b= b= 6.2 10.0 21.0 10.0 c= 4.8 c= 100.0 c= 100.0 c= 0.0 76 Variadic Functions ... Use * to define a variable number of positional parameters get packed into a tuple Use * in call flatten positional parameters def f(*args): print 'args:', args a = (3,4,7,8) b = [3,4,7,8] args: (1, 3, 4, 7, 8, 9) args: (1, (3, 4, 7, 8), 9) args: (1, [3, 4, 7, 8], 9) args: (1, 3, 4, 7, 8) args: (1, 3, 4, 7, 8) f(1,3,4,7,8,9) # pass multiple args f(1,a,9) # pass int, tuple, int f(1,b,9) # pass int, list, int f(1,*a) # treat tuple as multiple args f(1,*b) # treat list as multiple args Copyright ©2000-15 CRS Enterprises Ltd 77 ... Variadic Functions Use ** to define a variable number of named parameters get packed into a dict Use ** in call flatten named parameters def f(x,y,**params): print 'x,y:', x, y print 'params:', params print params['Dec'] hash = { 'a':1, 'b':2 } f(13,7, May=5, Jan=1, Feb=2, Dec=12, **hash) x,y: 13 7 params: {'a': 1, 'b': 2, 'Feb': 2, 'May': 5, 'Jan': 1, 'Dec': 12} 12 Copyright ©2000-15 CRS Enterprises Ltd 78 Lambda Functions Alternative to using def but is an expression not a statement Often used to defined functions in line that will not be called from elsewhere sum = lambda x, y: x + y print sum(1,2) print sum(5,9) print sum(10,20) 3 14 30 Copyright ©2000-15 CRS Enterprises Ltd equivalent definition def sum(x, y): return x + y 79 Stub Functions Use stub functions when ... you are not ready to define the function often used in test driven development def myStub(x, y): pass function will be defined later myStub(5,6) myStub(1,10) myStub(0,7) Copyright ©2000-15 CRS Enterprises Ltd 80 5 Classes and Objects Classes what is a class? what is an object? Methods defining calling Attributes for objects for classes Copyright ©2000-15 CRS Enterprises Ltd 84 The Object Model Object-oriented programming modeling real-world objects model described by classes model implemented by creating objects Copyright ©2000-15 CRS Enterprises Ltd 85 Classes Methods are functions Attributes are object references superclass reference to self operations methods class Yacht(object): attributes def __init__(self, bearing, speed): self.bearing = bearing self.speed = speed def display(self): print self.bearing, self.speed Copyright ©2000-15 CRS Enterprises Ltd 86 The Object Class object All classes have a single root class object but only for new style classes Person Object defines methods inherited by all Python classes Employee SalesPerson Copyright ©2000-15 CRS Enterprises Ltd 87 Creating Objects Use the class name to create a new object returns an object reference the object is not directly accessible Object destroyed by the VM when no references exist class Person: ... object references Copyright ©2000-15 CRS Enterprises Ltd john = Person() mary = Person() 88 Object Attributes Object attributes can be defined on the fly can apply to different objects Object b1 has height width color Object b2 has height width Use pass to define a empty class useful for trying things out Copyright ©2000-15 CRS Enterprises Ltd class Box: pass b1 = Box( ) b2 = Box( ) b1.height = 100 b1.width = 50 b1.color = "red" b2.height = 100 b2.width = 50 89 Manipulating Objects ... constructor create objects call methods class Point: def __init__(self, x = 0, y = 0): self.x = x self.y = y def display(self): print "Point is at", self.x, self.y def moveBy(self, dx, dy): self.x += dx self.y += dy p1 = Point(5,7) p2 = Point(15,17) p3 = Point(25,27) p1.moveBy(1,1) p2.moveBy(1,10) p3.moveBy(1,100) p1.display() p2.display() p3.display() Copyright ©2000-15 CRS Enterprises Ltd Point is at 6 8 Point is at 16 27 Point is at 26 127 90 Class Attributes Shared by all objects in class class attribute class Point: count = 0 object attribute def __init__(self, x = 0, y = 0): self.x = x self.y = y Point.count = Point.count + 1 def display(self): print "Point({0}) is at {1},{2}".format(id(self), self.x, self.y) normal method static(class) method def moveBy(self, dx, dy): self.x += dx self.y += dy def HowManyPoints(self): print "There are {0} Point object(s)\n".format(Point.count) Copyright ©2000-15 CRS Enterprises Ltd 91 Memory Layout Point K __bases__ __dict__ V ‘count’ 3 K p1 V __class__ __dict__ Copyright ©2000-15 CRS Enterprises Ltd ‘x’ 100 ‘y’ 200 92 6 Modules and Packages Copyright ©2000-15 CRS Enterprises Ltd 96 Modules and Packages Programs can be organized into modules and packages many modules are available in the Python and Java libraries Modules single file usually Python code but can be written in other languages such as C/C++ Packages collection of modules grouped using a common package name helps resolve namespace conflicts A package is defined by creating a directory with the same name as the package place modules in this directory can be extended to include sub-packages within sub-directories Copyright ©2000-15 CRS Enterprises Ltd 97 What is a Module Importing a file executes all the code in that file often just defines functions myfunctions.py import myfunctions myfunctions.f1() myfunctions.f2() myfunctions.f3() myfunctions.f4() def f1(): pass def f2(): pass def f3(): pass def f4(): pass Copyright ©2000-15 CRS Enterprises Ltd 98 Module Test Code Importing a file ... causes all code to executed but what about test code? Wrap all test code ... inside a __name__ test __name__ is only set to __main__ if we are the main program code will not be executed via an import Copyright ©2000-15 CRS Enterprises Ltd def f1(): def f2(): def f3(): def f4(): pass pass pass pass if __name__ == "__main__": f1() f2() f3() f4() 99 Importing 4 ways to import mypackage mysubpackage import mypackage.mysubpackage.MyClass x1 = mypackage.mysubpackage.MyClass() x1.f1() from mypackage import mysubpackage x2 = mysubpackage.MyClass() x2.f2() public class MyClass { public MyClass() { ... } public void f1() { ... } public void f2() { ... } public void f3() { ... } public void f4() { ... } } import mypackage.mysubpackage.MyClass as theClass x3 = theClass() x3.f3() from mypackage.mysubpackage import MyClass as theClass x4 = theClass() x4.f4() Copyright ©2000-15 CRS Enterprises Ltd 100 Packages Import loads all modules together executes __init__.py for each package import sys sys.path.append("lib") # load both packages together import mypackage.mysubpackage x = mypackage.mysubpackage.ModuleA.A() x.f(); loading mypackage x.g(); loading mysubpackage x.h() this is A.f() ... this is A.g() ... this is A.h() ... Copyright ©2000-15 CRS Enterprises Ltd mypackage/__init__.py mysubpackage/__init__.py ModuleA.py 101 Module Search Path When loading modules the interpreter searches the list of directories in sys.path first entry in sys.path can be an empty string refers to the current working directory other entries in sys.path may consist of directory names, .zip archive files, and .egg files order determines which modules are loaded import sys sys.path.append('mylib') Copyright ©2000-15 CRS Enterprises Ltd 102 Displaying Symbol Tables ... To display symbol table of main program use the global dictionary Iterate through the dictionary using iteritems() # use globals to get a list of symbols in main module # Python returns a StringMap which needs to be # converted to a dictionary symbols = dict(globals()) #print all the symbols in module for key, value in symbols.iteritems(): print key, value Copyright ©2000-15 CRS Enterprises Ltd 103 ... Displaying Symbol Tables To display symbol table of a module use the module's dictionary Iterate through the dictionary using iteritems() #print all the symbols in myfunctions module for key, value in myfunctions.__dict__.iteritems(): print key, value Copyright ©2000-15 CRS Enterprises Ltd 104 7 Installing Packages Copyright ©2000-15 CRS Enterprises Ltd 108 Installing Third-Party Libraries Definitive resource for locating third-party libraries and extensions to Python is the Python Package Index (PyPI) http://pypi.python.org Installing third-party modules is usually straightforward use pip or easy_install use platform-native installer use a download a zip that comes with setup.py file Copyright ©2000-15 CRS Enterprises Ltd 109 Python Module Downloads Pypi repository (cheese shop) http://pypi.python.org/pypi Download package, extract and then run e.g. install pip wget https://pypi.python.org/packages/source/p/pip/pip-6.0.8.tar.gz gunzip pip-6.0.8.tar.gz tar xvf pip-6.0.8.tar cd pip-6.0.8 python setup.py install Copyright ©2000-15 CRS Enterprises Ltd 110 Pip Pip is a package management system used to install and manage software packages Installation Python 2.7.9+ and Python 3.4+ include pip by default earlier versions had separate installers pip install requirements Collecting requirements Downloading requirements-0.1.tar.gz Installing collected packages: requirements Running setup.py install for requirements Successfully installed requirements-0.1 Copyright ©2000-15 CRS Enterprises Ltd 111 Install Packages with Dependencies Pip works with package versions: $ pip install SomePackage $ pip install SomePackage==1.0.4 $ pip install 'SomePackage>=1.0.4' # latest version # specific version # minimum version Wheel is a pre-built archive: greatly speeds up installation compared to building and installing from source archives Pip prefers Wheels where they are available, but otherwise defaults to source archives $ pip install SomePackage-1.0-py2.py3-none-any.whl Copyright ©2000-15 CRS Enterprises Ltd 112 Pip Commands Uninstall a package pip uninstall SomePackage List installed packages pip list Show details of a package pip show sphinx Query for Packages pip search "query" Copyright ©2000-15 CRS Enterprises Ltd 113 Compiling from Source Some packages need to be compiled before installation may need to control which C++ compiler is used 1. Create a config file in distutils directory called distutils.cfg 2. Edit file to specify compiler distutils.cfg [build] compiler=mingw32 Copyright ©2000-15 CRS Enterprises Ltd 114 Pip behind a Proxy install behind a proxy use HTTP_PROXY or HTTPS_PROXY environment variables HTTP_PROXY = http://<myproxyhost>:<port> HTTPS_PROXY = https://<myproxyhost>:<port> e.g. export HTTP_PROXY = http://www.mydomain.com:8080 pip install somepackage Copyright ©2000-15 CRS Enterprises Ltd 115 8 Files Opening and closing Reading and writing Modes read only read-write append Iterating through Random Access seek Copyright ©2000-15 CRS Enterprises Ltd 118 File Objects open creates a file object close destroys a file object myFile = open('myfile.txt', 'w') myFile.close() Copyright ©2000-15 CRS Enterprises Ltd 119 Iterating through a File Use for-in statement to process every line loop terminates on end of file f = open("hello.txt") for line in f: print line Copyright ©2000-15 CRS Enterprises Ltd 120 Using with Statement with statement automatic clean up avoid forgetting to close a file old way f = open("hello.txt") try: for line in f: print line finally: f.close() from __future__ import with_statement # This isn't required in Python 2.6+ with ("hello.txt") as f: for line in f: print line Copyright ©2000-15 CRS Enterprises Ltd 121 Coping with Errors If file I/O fails Error object thrown belongs to IOError class try: f = open("data/unknown.txt", "r+t") except IOError,error: print "File open failed!" error object print error error class Copyright ©2000-15 CRS Enterprises Ltd 122 Read Methods Simple to read from files f = open('myfile.txt', 'r') data = f.read() f.close() read entire file f = open('myfile.txt', 'r') data = f.read(100) f.close() f = open('myfile.txt', 'r') f.readline() f.readline() f.readline() f.close() read a line at a time (empty string returned on EOF) read 100 bytes from file Copyright ©2000-15 CRS Enterprises Ltd 123 Write Methods Simple to write to files f = open("data/out1.txt", "w") f.write("line 1\nline 2\n") f.close() write a string sequence = ("line 1\n", "line 2\n", "line 3\n", "line 4\n") f = open("data/out2.txt", "w") f.writelines(sequence) f.close() write a sequence of lines Copyright ©2000-15 CRS Enterprises Ltd 124 File Modes read only use "r" read and write use "r+" or "w+" to empty file on opening write only use "w" file will be empty on opening appending use "a" binary use "b" for binary and "t" for text (default) random access choose appropriate mode and then use seek() Copyright ©2000-15 CRS Enterprises Ltd 125 Writing Binary Data Open file with mode 'b' myFile = open('data/myfile2.bin', 'wb') myFile.write("\x5F\x9D\x3E"); myFile.close() Copyright ©2000-15 CRS Enterprises Ltd 126 Reading Binary Data Use ord() and hex(ord()) for conversions myFile = open('data/myfile2.bin', 'rb') # read bytes ch1 = myFile.read(1) # read 1 byte ch2 = myFile.read(1) ch3 = myFile.read(1) # convert to ascii (decimal) d1 = ord(ch1) d2 = ord(ch2) d3 = ord(ch3) # convert to ascii (hex) h1 = hex(ord(ch1)) h2 = hex(ord(ch2)) h3 = hex(ord(ch3)) myFile.close() Copyright ©2000-15 CRS Enterprises Ltd 127 Random Access seek(offset, whence) whence = 0 whence = 1 whence = 2 => from start of file => from current position => from end of file myFile = open('myfile.txt', 'w') myFile.seek(40, 0) myFile.write("ABCDEFGH"); myFile.seek(140, 0) myFile.write("ABCDEFGH"); myFile.seek(240, 0) myFile.write("ABCDEFGH"); myFile.close() Copyright ©2000-15 CRS Enterprises Ltd 128 Reading a File into a Dictionary You can read an entire file into a Dictionary and then perform lookups stdcodes = {} f = open("codes.txt", "r+t") read a file line by line, splitting each line and then adding to dictionary for line in f: [code, place] = line.rstrip().split(' ', 1) stdcodes[place] = code now try searching the dictionary placeRequested = raw_input("Enter place: ") try: print "The code for " + placeRequested + \ " is " + stdcodes[placeRequested] Town: Washington except KeyError: The code for Washington is 0191 print "code not found" Copyright ©2000-15 CRS Enterprises Ltd 129 Sorting a File stdcodes = {} f = open("codes.txt", "r+t") read a file line by line, splitting each line and then adding to dictionary for line in f: [code, place] = line.rstrip().split(' ', 1) stdcodes[place] = code list = [ ] list = stdcodes.keys() list.sort() for place in list: print place, stdcodes[place] Copyright ©2000-15 CRS Enterprises Ltd extract the keys into an array then sort the array now step through the sorted list looking up each entry in the original dictionary 130 9 Attribute Lookup Copyright ©2000-15 CRS Enterprises Ltd 134 Attribute Lookup ... 1. __getattribute__() always called if present 2. direct dictionary lookup use dictionaries 3. non direct dictionary lookup if descriptor protocol used call descriptor methods else search dictionaries print A.x # dotted class lookup o = A() print o.x # dotted attribute lookup print o.__dict__['x'] # direct dictionary lookup 4. lookup failure call __getattr__ or __setattr__ Copyright ©2000-15 CRS Enterprises Ltd 135 ... Getting Algorithm for Objects a.__getattribute__() exists no object.__getattribute__() gets called yes a.__class__[‘x’] is a descriptor call a.__getattribute() a = A() a.x no yes a.__dict__[‘x’] exists invoke one of a.__class__[‘x].__get__() a.__class__[‘x’].__set__() a.__class__[‘x’].__del__() no yes a.__class__.__dict__[‘x’] exists invoke a.__dict__[‘x’] no yes a.__getattr__() exists invoke a.__class__.__dict__[‘x’] Copyright ©2000-15 CRS Enterprises Ltd yes no invoke a.__getattr__() raise AttributeException 136 __getattribute__ Method Only works with new style classes not used by old style classes Called unconditionally to implement attribute accesses for instances of the class __getattr__() not called unless you raise an AttributeError To avoid infinite recursion call the base class method to access any attributes: object.__getattribute__(self, name) class Point(object): def __getattribute__(self, name): print "*** getting", name return object.__getattribute__(self, name) Copyright ©2000-15 CRS Enterprises Ltd 137 Direct Dictionary Lookup Look up via the class dictionary always direct - no overrides Look up via the instance dictionary always direct - no overrides class A: ... A.__dict__['x'] # class dictionary lookup o = A() o.__dict__['x'] # attribute dictionary lookup Copyright ©2000-15 CRS Enterprises Ltd 138 Dotted Lookup without Descriptors Look up class attribute search class dictionary (A.__dict__) search __mro__ base classes dictionaries Look up instance attribute search instance dictionary search class dictionary (A.__dict__) search __mro__ base classes dictionaries A.x o = A() o.x Copyright ©2000-15 CRS Enterprises Ltd # dotted class lookup # dotted attribute lookup 139 Descriptors ... The descriptor protocol defines 3 methods: __get__() __set__() __delete__() Any class implementing any of the above methods is a descriptor define the attributes of your class to be references to instances of a descriptor do not try to use descriptors with object attribute nothing happens Copyright ©2000-15 CRS Enterprises Ltd 140 ... Descriptors Define the class implementing the descriptor interface no all methods are required class Trace(object): def __init__(self, name): self.name = name def __get__(self, obj, objtype): print "GET:" + self.name + " = " + str(obj.__dict__[self.name]) return obj.__dict__[self.name] def __set__(self, obj, value): obj.__dict__[self.name] = value print "SET:" + self.name + " = " + str(obj.__dict__[self.name]) Copyright ©2000-15 CRS Enterprises Ltd 141 ... Descriptors Use the descriptor interface in your class descriptor invoked by dotted attribute access: A.x or a.x descriptor reference must be stored in the class dict, not instance dict descriptor not invoked by dictionary access: Point.__dict__['x'] class Point(object): x = Trace("x") y = Trace("y") def __init__(self, x0, y0): self.__dict__['x'] = x0 self.__dict__['y'] = y0 def moveBy(self, dx, dy): self.x = self.x + dx self.y = self.y + dy Copyright ©2000-15 CRS Enterprises Ltd 142 ... Descriptors Layout in memory Trace name K Point V __bases__ __dict__ Trace ‘x’ name ‘y’ K p1 ‘x’ ‘y’ V __class__ __dict__ Copyright ©2000-15 CRS Enterprises Ltd ‘x’ 100 ‘y’ 200 143 ... Descriptors Invoking the descriptor object class will redirect attribute lookup only if ... class defines descriptors otherwise object's dictionary is used Direct access to object's __dict__ bypasses descriptor p1 = Point(15, 25) p1.x = 20 p1.y = 35 result = p1.x p2 = Point(16, 26) p2.x = 30 p2.moveBy(1, 1) Copyright ©2000-15 CRS Enterprises Ltd SET:x = 20 SET:y = 35 GET:x = 20 SET:x = 30 GET:x = 30 SET:x = 31 GET:y = 26 SET:y = 27 144 Property Descriptors Allow you to define methods as properties property implements the interface behind the scenes getter and setter methods invoked by assignment class Point(object): def getX(self): print "getting x" return self._x def setX(self, value): print "setting x" self._x = value p = Point() p.x = 55 # calls setX() a = p.x # calls getX() del p.x # calls delX() def delX(self): print "deleting x" del self._x x = property(getX, setX, delX) Copyright ©2000-15 CRS Enterprises Ltd 145 Handling Undefined Methods Calling an undefined method causes ... an exception to be thrown ... Unless a class defines a __getattr__() method called by Python interpreter class MyClass: def __getattr__(self, method): print "method not found" return self.myDefault def myDefault(self): print "default()" def f(self): print "f..." def g(self): print "g..." a = MyClass() a.f() a.g() a.dummy() f... g... method not found default() # method doesn't exist Copyright ©2000-15 CRS Enterprises Ltd 146 Get Attribute Lookup Failures If class or instance attribute lookup fails __getattr__ is called if it exists class A(object): x = 100 # used if attribute not found by lookup def __getattr__(self, name): self.__dict__[name] = 0 # used to avoid recursion return self.__dict__[name] a1 = A() a1.x = 200 a2 = A() print a1.x print a2.x print a2.y # attribute found in instance # attribute found in class # attribute not found Copyright ©2000-15 CRS Enterprises Ltd 147 Attribute Assignment 1. __setattr__() exists ... call when an attribute assignment is attempted 2. otherwise instance dictionary is updated __setattr__() can assign to an instance attribute using: use self.__dict__[name] = value for old style classes use object.__setattr__(self, name, value) for new style classes but don't execute ... self.name = value ... causes a recursive call Copyright ©2000-15 CRS Enterprises Ltd X def __setattr__(self, name): self.name = name # recursive call 148 The 5 Intrinsic Class Attributes __name__ __doc__ __module__ __dict__ __bases__ name of the class (read only) class documentation string module in which the class is defined map of all class attributes tuple of all base classes class Derived(Base): "This is the Derived class" def Display(self): pass print Derived.__name__ print Derived.__doc__ print Derived.__module__ print Derived.__dict__ print Derived.__bases__ Copyright ©2000-15 CRS Enterprises Ltd Derived This is the Derived class __main__ {'Display': <function Display at ... (<class __main__.Base at ... 149 The 2 Intrinsic Object Attributes __class__ the object's class __dict__ map of all the object's attributes class Derived(Base): "This is the Derived class" def Display(self): pass x = Derived() x.color = "red" x.width = 10 print x.__class__ print x.__dict__ __main__.Derived {'color': 'red', 'width': 10} Copyright ©2000-15 CRS Enterprises Ltd 150 10 Advanced Language Techniques Copyright ©2000-15 CRS Enterprises Ltd 154 Lambda functions Used to build on the fly methods builds a function at run time only input parameters and return allowed no function body def do_operation(op, a, b): return {'+': '-': '*': '/': }[op]() lambda: a + b, lambda: a - b, lambda: a * b, lambda: a / b print do_operation('+', 2, 5) Copyright ©2000-15 CRS Enterprises Ltd 155 Decorators Decorators allow you to inject or modify code in functions and classes Introduced with @ symbol @staticmethod @classmethod @myFunction @myClass def trace(fn): def enhance(x): print "calling function with parameter x =", x return fn(x) return enhance @trace def h(x): return x * x print h(7) Copyright ©2000-15 CRS Enterprises Ltd calling function with parameter x = 7 49 156 Iterators Create a class with __iter__() and next() methods behave like built in iterator objects __iter__() called at start of iteration normally returns self next() called for each iteration for f in Fibonacci(): print f, class Fibonacci: def __init__(self): self.x,self.y = 0,1 def __iter__(self): return self def next(self): if self.x > 10000: raise StopIteration # end of iteration self.x, self.y = self.y, self.x + self.y return self.x Copyright ©2000-15 CRS Enterprises Ltd 157 Generators Generators are used to generate a sequence of objects often used as iterators uses the yield keyword Create a class with __iter__() method and your generator method generator uses yield to return an object and suspend generation ends when function returns (no yields left) class Fibonacci: def __init__(self): f = Fibonacci() self.x,self.y = 0,1 def __iter__(self): # get generator return self g = f.myGenerator() def myGenerator(self): # call the generators next() method while self.x < 10000: print g.next() yield self.x self.x, self.y = self.y, self.x + self.y return Copyright ©2000-15 CRS Enterprises Ltd 158 Filters Filters define a predicate function returns True/False allow filtering of a sequence def primesFilter(x): result = True if x % 2 == 0: result = False if x % 3 == 0: result = False if x % 5 == 0: result = False if x % 7 == 0: result = False if x % 11 == 0: result = False if x % 13 == 0: result = False return result sequence = range(14, 200) # filter out all non primes primes = filter(primesFilter, sequence) print primes Copyright ©2000-15 CRS Enterprises Ltd 159 Maps Maps apply a function to every item in a sequence def cube(x): return x * x * x # set up a sequence sequence = range(1, 20) # apply a map to entire sequence cubes = map(cube, sequence) for value in cubes: print "%6i" % value, Copyright ©2000-15 CRS Enterprises Ltd 160 Comprehensions List comprehensions provide a concise way to create lists without resorting to use of map(), filter() and/or lambda def cube(x): return x * x * x # set up a sequence sequence = range(1, 20) # apply a comprehension to entire sequence cubes = [cube(x) for x in sequence] for value in cubes: print "%6i" % value, # just print the sequence cubes = [x for x in sequence] for value in cubes: print "%6i" % value, Copyright ©2000-15 CRS Enterprises Ltd 161 Introspection Introspection allows you to investigate methods and attributes of a class at runtime dir(obj) returns all methods and attributes callable(method) checks if a method p = MyClass() print "methods and attributes:", dir(p) methodList = [method for method in dir(p) if callable(getattr(p, method))] print "methods:", methodList print "attributes: ", p.__dict__ print "class:", p.__class__ print "doc string:", p.__class__.__doc__ Copyright ©2000-15 CRS Enterprises Ltd 162 Pickling Pickling allows serializing objects to and from disk persistent objects import pickle # pickle object foo = Foo(66) f = open("test.dat", "w") pickle.dump(foo, f) f.close() class Foo: def display(self): print self.x def __init__(self, x0): self.x = x0 # unpickle object f = open("test.dat", "r") x = pickle.load(f) x.display() f.close() Copyright ©2000-15 CRS Enterprises Ltd 163 exec and eval Statements exec x = 10 y = 20 codeFragment = raw_input("Please enter some code (e.g. 'print x + y'): ") exec codeFragment Please enter some code (e.g. 'print x + y'): print x * y + 1 201 eval x = 10 y = 20 codeFragment = str(input("Please enter an expression (e.g. 'x + y'): ")) result = eval(codeFragment) print "result is: ", result Please enter an expression (e.g. 'x + y'): x * y result is: 200 Copyright ©2000-15 CRS Enterprises Ltd 164 11 Decorators built-in decorators user defined decorators Copyright ©2000-15 CRS Enterprises Ltd 168 Static Methods @staticmethod used with class attributes and methods can be called either on the class or on an instance avoid having to pass self as first parameter class MyClass: # static data hits = 0 @staticmethod def hit(): MyClass.hits = MyClass.hits + 1 m = MyClass() MyClass.hit() # call through class m.hit() # call through an instance Copyright ©2000-15 CRS Enterprises Ltd 169 Class Method @classmethod can be used as an alternative way of defining a constructor permits multiple constructors class passed as first parameter - instead of self class Point: @classmethod def initialize1(theClass, x, y): p = theClass() p.x = x p1 = Point.initialize1(11, 26) p.y = y p2 = Point.initialize2(20) return p @classmethod def initialize2(theClass, a): p = theClass() p.x = a p.y = a return p Copyright ©2000-15 CRS Enterprises Ltd 170 Property Decorator @property used to define a computed read only property class Circle(object): def __init__(self, radius): self.radius = radius # computed properties (and hence read only) @property def area(self): circle = Circle(10.0) return math.pi*self.radius**2 @property def perimeter(self): return 2*math.pi*self.radius Copyright ©2000-15 CRS Enterprises Ltd print circle.radius print circle.area print circle.perimeter 171 Property Setter Decorator @property.setter make a method appear to be a property class Circle(object): def __init__(self, radius): self.theRadius = radius @property def radius(self): return self.theRadius circle1 = Circle(10.0) circle2 = Circle(20.0) circle3 = Circle(30.0) @radius.setter circle1.radius = 15.0 def radius(self, value): if not isinstance(value, float): raise TypeError("Must be a float") self.theRadius = value Copyright ©2000-15 CRS Enterprises Ltd 172 User Defined Decorators Decorators ... take an input function and return a different function modifying the behavior of the input function def trace(fn): def enhance(x): print "calling " + fn.func_name + "(" + str(x) + ")" return fn(x) return enhance @trace def square(x): return x * x print square(4) Copyright ©2000-15 CRS Enterprises Ltd calling square(4) 16 # calls trace, not square 173 Decorators with Parameters Decorators can have parameters def log(level): def logit(fn): def enhance(x): message = "calling " + fn.func_name + "(" + str(x) + ")" if(level == logging.DEBUG): logging.debug(message) if(level == logging.INFO): logging.info(message) if(level == logging.WARNING): logging.warning(message) if(level == logging.ERROR): logging.error(message) if(level == logging.CRITICAL): logging.critical(message) return fn(x) @log(logging.WARNING) return enhance def square(x): return logit return x * x logging.basicConfig(level=logging.WARNING) print square(4) WARNING:root:calling square(4) 16 Copyright ©2000-15 CRS Enterprises Ltd 174 Nested Decorators Decorators can be nested def bold(fn): def decorate(): return "<b>" + fn() + "</b>" return decorate def uk(fn): def decorate(): fields = fn().split('/') date = fields[1] + "/" + fields[0] + "/" + fields[2] return date return decorate @bold def getBoldDate(): return getDate() @uk def getUkDate(): return getDate() @bold @uk def getBoldUkDate(): return getDate() <b>6/16/2013</b> print getBoldUkDate() def getDate(): now = datetime.datetime.now() return "%d/%d/%d" % (now.day, now.month, now.year) Copyright ©2000-15 CRS Enterprises Ltd 175 12 Regular Expressions Copyright ©2000-15 CRS Enterprises Ltd 178 Anchors and Selections selection indicates which characters to match [abc] any one character from list (a OR b OR c) [a-m] any one character from range (a OR b OR ... OR m) [^abc] any one character not in list (NOT a NOR b NOR c) . any one character \s any white space character \S any NON white space character \d any digit \D any NON digit \w any alphanumeric \W any NON alphanumeric anchors indicate context ^ start of string $ end of string \b on a word boundary \B NOT on a word boundary Copyright ©2000-15 CRS Enterprises Ltd 179 Repeat Counts repeat counts apply to the previous expression * 0 or more repeats + 1 or more repeats ? 0 or 1 repeats {n,m} n to m repeats {n,} at least n repeats {n} exactly n repeats Examples [aeiou]* [0-9]+ [0-9]{3,5} \.? 0 or more vowels 1 or more digits (\d+) 3 to 5 digits 0 or 1 periods \. matches a period the backslash negates the special meaning of the pattern that follows Copyright ©2000-15 CRS Enterprises Ltd 180 Pattern Matching Functions match match from the start of text search match anywhere in the text import re test = "-------ABC------------" pattern = r"\w+" pattern = re.compile(pattern) match = pattern.match(test) print match None match = pattern.search(test) print match.group() ABC Copyright ©2000-15 CRS Enterprises Ltd 181 Splitting Perhaps we want to split a string using a regular expression as a delimiter pattern.split(text) import re pattern = re.compile(r"\s*;\s*") text = "aaa ; bbb ;ccc ; ddd ; eee" list = pattern.split(text) print list ['aaa', 'bbb', 'ccc', 'ddd', 'eee'] Copyright ©2000-15 CRS Enterprises Ltd 182 Substitution Perhaps we want to substitute something for the matched pattern? Use pattern.sub(replacement, text) import re pattern = re.compile(r"\s*;\s*") text = "aaa ; bbb ;ccc ; ddd ; eee" newText = pattern.sub("---", text) print newText aaa---bbb---ccc---ddd---eee Copyright ©2000-15 CRS Enterprises Ltd 183 Using Comments Always a good idea to use comments regular expressions are difficult to read at the best of times import re string = "AAAA1111BBBB2222CCCC3333DDDD"; pattern = r""" ^ # start of line (.*?) # 0 or more characters # non greedy (\d+) # 1 or more digits (.*) # 0 or more characters $ # end of line """ compiledPattern = re.compile(pattern, re.VERBOSE) result = compiledPattern.search(string) Copyright ©2000-15 CRS Enterprises Ltd 184 More Advanced Searches Use ( ) in pattern to capture data import re text = "---111122223333333333334444555566667777---" pattern = "2+(3+)4+(5+)6+" # search for pattern pattern = re.compile(pattern) result = pattern.search(text) # print results print "full match: ", result.group(0) print "capture pattern 1: ", result.group(1) print "capture pattern 2: ", result.group(2) print "all captures: ", result.groups() Copyright ©2000-15 CRS Enterprises Ltd 185 Repeating Patterns Use findall() and finditer() to repeat searches import re text = "AB12CD34EF56GH" pattern = r"(\d+)" # find all occurrences of pattern matcher = re.findall(pattern, text) print matcher # iterate through finding the pattern for matcher in re.finditer(pattern, text): print matcher.groups(0) Copyright ©2000-15 CRS Enterprises Ltd ['12', '34', '56'] ('12',) ('34',) ('56',) 186 Greedy Patterns Greedy Patterns are the default Use ? to use non greedy matching text = "AAAA1111BBBB2222CCCC3333DDDD" greedyPattern = r"^(.+)(\d+)(.+)$" nonGreedyPattern = r"^(.+?)(\d+)(.+)$" ^(.+)(\d+)(.+)$ Greedy: <AAAA1111BBBB2222CCCC333><3><DDDD> ^(.+?)(\d+)(.+)$ Non-Greedy: <AAAA><1111><BBBB2222CCCC3333DDDD> Copyright ©2000-15 CRS Enterprises Ltd 187 Look Ahead and Look Behind (?= ) (?! ) (?<= ) (?<! ) peek ahead matching RE peek ahead not matching RE peek behind matching RE peek behind not matching RE \w+[.](?!bat)\w+$ ?!bat not "bat" filename.ext Copyright ©2000-15 CRS Enterprises Ltd 188 Building Patterns Translation patterns can be built from hashes e.g. translate all occurrences of mon to Monday, tue to Tuesday etc import re def replaceGroup(matcher): key = matcher.groups(1) return days[key[0]] days = { 'mon' : 'Monday', 'tue' : 'Tuesday', 'wed' : 'Wednesday', 'thu' : 'Thursday', 'fri' : 'Friday' } pattern = "(" + "|".join(days.keys()) + ")" compiledPattern = re.compile(pattern) print "pattern: ", pattern text = '''The course starts on mon, continues on tue, but wed is the last day''' for matcher in re.finditer(compiledPattern, text): text = compiledPattern.sub(replaceGroup, text, 1) print text Copyright ©2000-15 CRS Enterprises Ltd 189 13 Exception Handling Copyright ©2000-15 CRS Enterprises Ltd 192 try-except Statements array = [1,2,3,4,5,6] exception thrown here try: for x in array: print x, array[x] exception type print "Exiting try block" except IndexError,target: print "... entering except block" print target this is never executed object reference 23 34 45 56 6 ... entering except block list index out of range Copyright ©2000-15 CRS Enterprises Ltd 193 try-except-else Statements from math import sqrt x = int(raw_input("Enter positive integer: ")) try: root = sqrt(x) except: print "... entering except block" else: print "... entering else block" print root exception occurs no exception Enter positive integer: 25 ... entering else block 5.0 Enter positive integer: -25 ... entering except block Copyright ©2000-15 CRS Enterprises Ltd 194 try-finally Statements array = [1,2,3,4,5,6] 1 2 3 4 5 6 ... entering finally block 3 5 ... entering finally block IndexError: list index out of range try: for x in array: print array[x - 1], finally: print "... entering finally block" guaranteed to be called even if exception occurs try: for x in array: print array[x * 2], finally: print "... entering finally block" Copyright ©2000-15 CRS Enterprises Ltd 195 raise Statements array = [1,2,3,-4,5,6] try: exception type for x in array: if x < 0: raise ValueError, "array index is negative!" print x, object reference except ValueError, value: print print "... entering except block: " + str(value) 123 ... entering except block: array index is negative! Copyright ©2000-15 CRS Enterprises Ltd 196 Unified try except finally In Python 2.5+ you can combine finally and except not allowed in previous versions try: block-1 ... except Exception1: handler-1 ... except Exception2: handler-2 ... else: else-block finally: final-block Copyright ©2000-15 CRS Enterprises Ltd 197 Nested Exceptions def f1(): print "Entering f1" f2() print "Leaving f1" never executed def f2(): print "Entering f2" f3() print "Leaving f2" regarded as part of the try block Entering f1 Entering f2 Entering f3 Some exception def f3(): print "Entering f3" raise Exception("Some exception") print "Leaving f3" try: f1() except Exception, reason: print reason Copyright ©2000-15 CRS Enterprises Ltd 198 Standard Exceptions Exception StopIteration StandardError BufferError ArithmeticError FloatingPointErro OverflowError ZeroDivisionError AssertionError AttributeError EnvironmentError IOError OSError EOFError ImportError LookupError IndexError KeyError Copyright ©2000-15 CRS Enterprises Ltd MemoryError NameError UnboundLocalError ReferenceError RuntimeError NotImplementedError SyntaxError IndentationError TabError SystemError TypeError ValueError UnicodeError UnicodeDecodeError UnicodeEncodeError UnicodeTranslateError 199 User Defined Exceptions Always subclass Exception class MyError(Exception): def __init__(self, value): self.value = value try: My exception occurred, value: 4 raise MyError(2*2) except MyError as e: print 'My exception occurred, value:', e.value Copyright ©2000-15 CRS Enterprises Ltd 200 Controlling Tracebacks Use the traceback module provides a standard interface to extract, format and print stack traces of Python programs exactly mimics the behavior of the Python interpreter when it prints a stack trace traceback.print_exc(limit, file) prints limit entries in a stack trace to a file. If the parameters are omitted the full traceback is output to the console Copyright ©2000-15 CRS Enterprises Ltd 201 When Cleanup Raises ... What happens if exception is raised in handler? original exception can get lost def doit(): # some nested function encounters a problem raise RuntimeError('original error ...') def myfunct(): try: doit() except: # if errorCorrection() fails # it will mask out the original exception errorCorrection() Copyright ©2000-15 CRS Enterprises Ltd 202 ... When Cleanup Raises Perform the cleanup in a finally block the original exception gets preserved def doit(): # some nested function encounters a problem raise RuntimeError('original error ...') def doit(): def myfunct(): # some nested function encounters a problem try: raise RuntimeError('original error ...') doit() except: try: # re-raise the original error raise finally: # handle any problems locally try: errorCorrection() except: traceback.print_exc() Copyright ©2000-15 CRS Enterprises Ltd 203 Logging Exceptions Always wise to log an exception don't swallow exceptions sometimes it is best to log and then rethrow def do_work(): # if exception encountered in library code # we might not know what to do about it, # so log error and rethrow raise Exception('do_work() failed') try: # perform some work do_work() except Exception, e: # handle the error in your code # because you know what you want to do about it logging.error('problem in library code ...') print "handling exception generated by library code ..." Copyright ©2000-15 CRS Enterprises Ltd 204 assert Statements def CalculateQuartile(percent): assert type(percent).__name__ == 'int' assert percent >= 0 and percent <= 100 quartile = 1 if percent > 25: print CalculateQuartile(34) quartile = 2 print CalculateQuartile(104) if percent > 50: quartile = 3 if percent > 75: 2 quartile = 4 assert percent >= 0 and percent <= 100 return quartile AssertionError Copyright ©2000-15 CRS Enterprises Ltd 205 14 Testing Unittest framework DocTest PyTest Nose Copyright ©2000-15 CRS Enterprises Ltd 208 Components of Unittest test fixture code run to prepare for one or more tests e.g. start a server any associate cleanup actions test case unit of testing implemented as a method of test class test suite a collection of test cases used to aggregate tests that should be executed together. test runner component which orchestrates the execution of tests provides output relating to the success or failure of the tests Copyright ©2000-15 CRS Enterprises Ltd 209 Structure of Test Class derive from unittest.TestCase setUp call before each test tearDown called after each test import unittest execute tests by calling unittest.main() test names must begin with test... class testPoint(unittest.TestCase): def setUp(self): # called before each test executes def testA(self): ... def testB(self): ... def testC(self): ... def testD(self): ... if __name__ == '__main__': unittest.main() Copyright ©2000-15 CRS Enterprises Ltd 210 Structure of a Test Case Use assertEqual() to check the output of a test is correct other functions available def testMoveBy2(self): """moveBy test(2)""" self.point.moveBy(5, 2) self.assertEqual(self.point.display(), "8,7") FAIL: moveBy test(2) ---------------------------------------------------------------------Traceback (most recent call last): File "C:\_Eclipse\Python\Unit Test\unit-testing-1.py", line 29, in testMoveBy2 self.assertEqual(self.point.display(), "8,7") AssertionError: '8,6' != '8,7' Copyright ©2000-15 CRS Enterprises Ltd 211 Test Functions assertEqual() check for an expected result assert_() verify a condition assertRaises() verify that an expected exception gets raised Copyright ©2000-15 CRS Enterprises Ltd 212 Test Suites Tests can be grouped into suites def suite(): suite = unittest.TestSuite() suite.addTest(testPoint('testConstructor')) suite.addTest(testPoint('testMoveBy1')) suite.addTest(testPoint('testDistance1')) return suite if __name__ == '__main__': mySuite = suite() unittest.TextTestRunner(verbosity=0).run(mySuite) Copyright ©2000-15 CRS Enterprises Ltd 213 DocTest DocTest module searches for text that look like interactive Python sessions executes those sessions to verify that they work exactly as shown Tests are embedded in code easy to define tests can cause clutter Copyright ©2000-15 CRS Enterprises Ltd 214 Simple Example Use doctest.testmod(...) many parameters, but usually just use verbose=True def cube(x): """ The cube function returns x * x * x >>> cube(3) 27 >>> cube(-1) -1 """ return x*x*x if __name__ == '__main__': import doctest doctest.testmod(verbose = True) Copyright ©2000-15 CRS Enterprises Ltd 215 Formatting Tests can be fuzzy ... used to omit some results whitespace not relevant if ELLIPIS and NORMALIZE_WHITESPACE specified def squares(a, b): """ returns all the squares in range a..b >>> squares(1,10) # doctest:+ELLIPSIS +NORMALIZE_WHITESPACE [1, 4, ..., 100] """ answer=[] for i in range(a,b+1): answer.append(i*i) return answer Copyright ©2000-15 CRS Enterprises Ltd 216 Failures def sumsquares(n): """ with line numbers 1+4+9+16 = 30 (not 30457) and erroneous result >>> sumsquares( 4 ) 30457 """ Trying: sum = 0 sumsquares( 4 ) for i in range(n+1): Expecting: sum += square(i) 30457 return sum ********************************************************************** Failures reported File "C:\_Eclipse\Advanced Python\src\Unit Test Framework Failed example: sumsquares( 4 ) Expected: 30457 Got: 30 Copyright ©2000-15 CRS Enterprises Ltd 217 Exceptions Exceptions can be catered for in the tests use ... to suppress unnecessary information def square(x): """ This function squares a number >>> square(-3) 9 >>> square(16) Traceback (most recent call last): ... ValueError: input too large """ if x > 10: raise ValueError('input too large') else: return x*x Copyright ©2000-15 CRS Enterprises Ltd 218 PyTest PyTest runs as a separate program inspects code for methods beginning with test_ and runs them If you need to install PyTest, use: easy_install -U py To run tests, go to a command prompt and type: py.test myExample.py Copyright ©2000-15 CRS Enterprises Ltd 219 Simple Example Add tests as methods in your modules use assert statements def square(x): return x * x def test_squares(): assert square(6) == 36 # succeeds assert square(10) == 99 # fails Copyright ©2000-15 CRS Enterprises Ltd 220 Multiple Tests Use iterators to create multiple tests Use setup_class() class TestSquare: for initial test conditions def setup_class(self): self.m = maths.Maths() def is_square(self, n, expected): self.m.setX(n) assert self.m.square() == expected def test_squares(self): # set up 5 tests (the last one fails!) inputs = ( 4, 7, 10, 20, 25) outputs = (16, 49, 100, 400, -1) for i, o in zip(inputs, outputs): yield self.is_square, i, o Copyright ©2000-15 CRS Enterprises Ltd 221 Nose Nose is not a test methodology simplifies calling other tests Nose will search out and run tests defined as functions methods of a class unit tests python script command line import nose nose.run() nosetests -v Copyright ©2000-15 CRS Enterprises Ltd 222 15 Inheritance Inheritance new style classes and object subtyping Abstract Classes interfaces OO contracts Polymorphism the good the bad (duck typing) Copyright ©2000-15 CRS Enterprises Ltd 226 Subclassing A class can inherit methods and state from another class the new class is called the subclass or derived class the original class is called the superclass or base class The subclass is a superset of the superclass inherits all the methods and state of the superclass can add extra methods and state of its own cannot remove and methods and state of the superclass methods in the superclass can be overridden by the subclass the subclass is defined in the terms of the differences from the superclass Copyright ©2000-15 CRS Enterprises Ltd 227 The Object Class object All classes have a single root object only for new style classes Person Object defines methods inherited by all Python classes Employee SalesPerson Copyright ©2000-15 CRS Enterprises Ltd 228 Constructors Subclass makes explicit call to CTORs in superclass class Person(object): def __init__(self, name): self.name = name class Employee(Person): def __init__(self, name, id): Person.__init__(self, name) self.id = id class SalesPerson(Employee): def __init__(self, name, id, region): Employee.__init__(self, name, id) self.region = region Employee IS A Person SalesPerson IS A Employee SalesPerson IS A Person p = Person("Anne") e = Employee("Beth", 7468) s = SalesPerson("Carol", 4712, "NE") Copyright ©2000-15 CRS Enterprises Ltd 229 The Substitution Rule Employee class extends the Person class Person SalesPerson class extends the Employee class Employee substitutes for Person object SalesPerson substitutes for Employee object Person object Copyright ©2000-15 CRS Enterprises Ltd Superclass extends Employee Subclass extends SalesPerson 230 Overriding Superclass Methods Subclass can override any method of the superclass superclass method hidden from client code e = Employee("Beth", 7468) e.display() class Employee(Person): def display(self): Person.display(self) # alternatively search super classes for display method # super(Employee, self).display() # only for new style classes print "id=", self.id, Copyright ©2000-15 CRS Enterprises Ltd 231 Concrete and Abstract Classes Concrete class all methods are fully implemented may have instance variables objects can be instantiated Abstract class some methods are not implemented some methods are implemented may have instance variables objects cannot be instantiated Hoisting abstract classes used to hold "common" code from subclasses A concrete subclass must implement all abstract methods of its superclass Copyright ©2000-15 CRS Enterprises Ltd 232 Abstract Classes ... from abc import ABCMeta, abstractmethod, abstractproperty class Shape: __metaclass__ = ABCMeta @abstractmethod def display(self): pass @abstractproperty def name(self): pass Copyright ©2000-15 CRS Enterprises Ltd 233 ... Abstract Classes class Circle(Shape): def __init__(self, name): self.theName = name def display(self): print "Circle", self.name @property def name(self): return self.theName non abstract methods and instance variables automatically available must implement all abstract methods c = Circle("my-circle") print c.name c.display() Copyright ©2000-15 CRS Enterprises Ltd 234 Interfaces An interface similar to an abstract class, but ... all methods are abstract no instance variables allowed final class variables permitted (constants) Can't be instantiated A concrete class can implemented multiple interfaces multiple inheritance model extend only one class multiple inheritance model Copyright ©2000-15 CRS Enterprises Ltd 235 Interfaces as Contracts Interfaces for the Class Implementer the interface defines all the methods and signatures for which the class designer must provide implementations Interfaces for the Class User the class user can write code assuming that implementations will be provided for all the methods in the interface The Contract each interface defines a contract between the class user and class implementer separates interface from implementation essential for good object oriented design Copyright ©2000-15 CRS Enterprises Ltd 236 Polymorphic Methods An (optional) abstract method defined in interfaces and abstract classes not appropriate for the superclass to provide an implementation implemented by a subclasses Implementations each implementing subclass can provide its own implementation there can be 'many forms' of these implementations each implementation is called a Polymorphic method Copyright ©2000-15 CRS Enterprises Ltd 237 Polymorphism Polymorphic collections include objects of any subclass can call any of the methods of the superclass class Person(object): def Eat(self): pass def Drink(self): pass def Sleep(self): pass class Employee(Person): def Eat(self): pass def Drink(self): pass def Sleep(self): pass def NightOut(p): p.Drink() p.Drink() p.Eat() p.Drink() p.Sleep() class SalesPerson(Employee): def Eat(self): pass def Drink(self): pass def Sleep(self): pass Copyright ©2000-15 CRS Enterprises Ltd 238 Duck Typing Python allows polymorphic methods from classes not in the hierarchy not really sensible drawback of Python's weak (duck) typing class Person(object): def Eat(self): pass def Drink(self): pass def Sleep(self): pass def NightOut(p): p.Drink() p.Drink() p.Eat() p.Drink() p.Sleep() class Employee(Person): ... class SalesPerson(Employee): ... p = Person() e = Employee() s = SalesPerson() class Horse: def Eat(self): pass def Drink(self): pass def Sleep(self): pass NightOut(p) NightOut(e) NightOut(s) h = Horse() NightOut(h) Copyright ©2000-15 CRS Enterprises Ltd 239 16 Threading Copyright ©2000-15 CRS Enterprises Ltd 242 A Thread Multiple executions of the same process ‘parallelism' within a process A thread has its own: Stack Each thread shares Heap Static data Process resources (open files etc) Process Thread A Thread B Thread C Thread scheduling performed by kernel co-operative pre-emptive Copyright ©2000-15 CRS Enterprises Ltd 243 Why Use Multithreading? Most applications need to perform parallel tasks updating complex graphical information waiting for user input writing data to or reading data from sockets performing callback operations Single-threaded programs each task is sequential tasks can't be run together inefficient Multithreaded programs each task is run in parallel harder to program efficient Copyright ©2000-15 CRS Enterprises Ltd 244 Thread Objects and Threads A thread object represents a thread A thread is not the same as the thread object The thread object is a helper object has several methods to facilitate thread management most methods of the thread object are invoked by the calling thread often, only the run() method is executed by the new thread start run Thread Object calling thread Copyright ©2000-15 CRS Enterprises Ltd new thread 245 Python Threads Python has no built in support for threads must use Thread module based on the Java thread model threads have no priorities Two strategies new thread executes a callback managed by the Thread class the callback can be a function or a class with __call__() derive from Thread class and define a run() method for the thread to execute Newly created thread runs on the callback to completion can't be suspended Copyright ©2000-15 CRS Enterprises Ltd 246 01 creating threads use callback managed by Thread class can pass args to the new thread from threading import Thread def myfunc(name): for i in range (1, 50): sys.stdout.write(name) time.sleep(random.random() * 0.1) # define a callback function - to be called via start() thread1 = Thread(target=myfunc, args=("1",)) thread2 = Thread(target=myfunc, args=("2",)) thread1.start() thread2.start() # start the threads thread1.join() # wait for threads to complete thread2.join() Copyright ©2000-15 CRS Enterprises Ltd 247 02 using runnable Inherit from Thread class and define run() method acts as the callback function m1 = MyClass("1") m2 = MyClass("2") from threading import Thread # create a runnable class class MyClass(Thread): def __init__(self, name): Thread.__init__(self) self.name = name # start calls run() m1.start() m2.start() # wait for threads to complete m1.join() m2.join() def run(self): for i in range (1, 50): sys.stdout.write(self.name) time.sleep(random.random() * 0.1) ... Copyright ©2000-15 CRS Enterprises Ltd 248 03 callable classes as callbacks define __call__() as callback from threading import Thread # create a callable class class MyClass: def __call__(self, name): for i in range (1, 50): sys.stdout.write(name) time.sleep(random.random() * 0.1) ... m1 = MyClass() m2 = MyClass() # define a callback class # __call__() to be called via start() t1 = Thread(target = m1, args = ("1",)) t2 = Thread(target = m2, args = ("2",)) t1.start() t2.start() t1.join() t2.join() Copyright ©2000-15 CRS Enterprises Ltd 249 04 comparing techniques Callable classes are the most flexible you can pass parameters to the new thread by position, as a list, or as a dictionary Callback function the simplest t1 = Thread(group = None, target = m1, name = None, args = (), kwargs = {'name':'1'}) t2 = Thread(target = m2, args = ("2",)) t3 = Thread(None, threadFunction, None, ("3",)) Copyright ©2000-15 CRS Enterprises Ltd 250 05 locking locks are required to synchronize threads always release locks in a finally block just in case an exception occurs with construct does this automatically from threading import Lock lock = Lock() # create lock from threading import Lock # locks should be released in finally block lock.acquire() try: for i in range (1, 50): sys.stdout.write(name) time.sleep(random.random() * 0.1) finally: lock.release() lock = Lock() # create lock Copyright ©2000-15 CRS Enterprises Ltd with lock: for i in range (1, 50): sys.stdout.write(name) time.sleep(random.random() * 0.1) 251 06 sharing data shared resources need locking count1 is incremented outside a lock - unreliable count2 is incremented inside a lock - reliable class MyClass: def __call__(self, name): global lock, count1, count2 for i in xrange(0, 20*1000*100): count1 += 1 lock.acquire() count2 += 1 lock.release() Copyright ©2000-15 CRS Enterprises Ltd 252 07 events Use event objects as signals thread can wait() on signal another thread can set() the signal class MyClass: def __call__(self, name): global event print(name + " waiting for event"); event.wait() print("\t" + name + " proceeding after event"); event = Event() # create event object m1 = MyClass() t1 = Thread(target = m1, args = ("1",)) t1.start() time.sleep(15) event.set() Copyright ©2000-15 CRS Enterprises Ltd 253 08 semaphores Semaphore provide a shared lock define a count (number of threads given simultaneous access to a resource) count is decrement each time semaphore acquired (>= 0) from threading import Thread, BoundedSemaphore class MyClass: def __call__(self, name): global semaphore semaphore.acquire() time.sleep(5) semaphore.release() semaphore = BoundedSemaphore(3) m1 = MyClass() t1 = Thread(target = m1, args = ("1",)) t1.start() t1.join() Copyright ©2000-15 CRS Enterprises Ltd 254 Using Immutable Objects An object is considered immutable if its state cannot change after it is constructed. Maximum reliance on immutable objects is widely accepted as a sound strategy for creating simple, reliable multithreaded code. Since they cannot change state they cannot be corrupted by thread interference or observed in an inconsistent state no need to use locks Copyright ©2000-15 CRS Enterprises Ltd 255 Global Interpreter Lock ... Global Interpreter Lock (GIL) is a mutex that ... prevents multiple native threads from executing byte codes at same time necessary mainly because CPython's memory management is not thread-safe other features have grown to depend on the guarantees that the GIL enforces C/C++ extensions must be GIL-aware to be thread safe GIL is controversial and a bottleneck prevents multithreaded CPython programs from taking full advantage of multiprocessor systems in certain situations potentially blocking or long-running operations, such as I/O, image processing, and NumPy number crunching, happen outside the GIL Copyright ©2000-15 CRS Enterprises Ltd 256 ... Global Interpreter Lock GIL degrades performance even when it is not a bottleneck system call overhead is significant, especially on multicore hardware two threads calling a function may take twice as much time as a single thread calling the function twice can cause I/O-bound threads to be scheduled ahead of CPU-bound threads prevents signals from being delivered Stackless Python - no GIL an alternative Python Implementation that does not use the C stack green threads managed by the interpreter - not the O/S can run hundreds of thousands of tiny tasks, called "tasklets", in a single thread completely compatible with Standard Python - just adds some functionality Jython and IronPython - no GIL can fully exploit multiprocessor systems Copyright ©2000-15 CRS Enterprises Ltd 257 17 Extending and Embedding Python C/C++ interface to Python using SWIG Copyright ©2000-15 CRS Enterprises Ltd 260 Calling a C/C++ Module from Python Calling a C Module from Python: C Part 1. Write the C routines 2. Define the Module’s Method Table 3. Define the Initialization Function Python Part 1. Write setup.py 2. Build module: python setup.py build Testing 1. import C module 2. call C methods as in regular Python code Copyright ©2000-15 CRS Enterprises Ltd 261 C Part #include <Python.h> // 1. C routines static PyObject* say_hello(PyObject* self, PyObject* args) { // implementation } // 2. method table static PyMethodDef HelloMethods[] = { {"say_hello", say_hello, METH_VARARGS, "Greet somebody."}, {NULL, NULL, 0, NULL} }; // 3. initialization function PyMODINIT_FUNC inithello(void) { (void) Py_InitModule("hello", HelloMethods); } Copyright ©2000-15 CRS Enterprises Ltd 262 Python Part Write setup.py setup.py from distutils.core import setup, Extension module1 = Extension('hello', sources = ['hellomodule.c']) setup (name = 'PackageName', version = '1.0', description = 'This is a demo package', ext_modules = [module1]) Build Module set PATH=C:\Python25;C:\Program Files\pythonxy\mingw\bin python setup.py build --compiler=mingw32 Copyright ©2000-15 CRS Enterprises Ltd 263 Testing Make C module available in Python code Add build directory to PYTHONPATH import new module C module now behaves as any other module import sys sys.path.append("build/lib.win32-2.5") import hello hello.say_hello("World") Copyright ©2000-15 CRS Enterprises Ltd 264 Using SWIG SWIG is a generator program simplifies creating new modules from C/C++ code use C/C++ data structures don't need to rest to Py* functions Steps Required 1. Write C code (no Python classes required) 2. Write interface file 3. Build module 4. Test module in Python Copyright ©2000-15 CRS Enterprises Ltd 265 Coding Write C code hellomodule.c #include <stdio.h> void say_hello(const char* name) { printf("Hello %s!\n", name); } Write interface file hello.i %module hello extern void say_hello(const char* name); Copyright ©2000-15 CRS Enterprises Ltd 266 Build and Test Build set PATH=C:\Python25;C:\Program Files\pythonxy\swig; C:\Program Files\pythonxy\mingw\bin swig -python hello.i gcc -fpic -c hellomodule.c hello_wrap.c -IC:\Python25\include gcc -shared -LC:\Python25\libs hellomodule.o hello_wrap.o -lpython25 -o _hello.pyd Test import hello hello.say_hello("World") Copyright ©2000-15 CRS Enterprises Ltd 267 18 Meta Classes Copyright ©2000-15 CRS Enterprises Ltd 270 ‘type’ Metaclass type metaclass can create ‘normal’ classes def __init__(self, x): self.x = x def printX(self): print self.x dictionary of the attributes of the class type(name, bases, dict) className = 'TestB' tuple of the base classes of the class bases = (object,) dictionary = { name of the class '__init__': __init__, 'printX' : printX } TestB = type(className, bases, dictionary) Copyright ©2000-15 CRS Enterprises Ltd 271 Class Factories ... Choose your own metaclass to create your classes class MyClassFactory(type): y = 100 def __init__(cls, name, bases, dct): print "Creating class %s using CustomMetaclass" % name print "with dictionary: " displayUserDefinedPartsOfDictionary(dct) bases = (object,) super(MyClassFactory, cls).__init__(name, bases, dct) def __new__(cls, name, bases, dct): print "Allocating memory for class", name dct['y'] = MyClassFactory.y # attribute created dct['f'] = lambda self: self.x + self.y; # method created # use type to allocate return type.__new__(cls, name, bases, dct) Copyright ©2000-15 CRS Enterprises Ltd 272 ... Class Factories __metaclass__ attribute selects the metaclass subclasses inherit metaclass attributes and methods class BaseClass(object): __metaclass__ = MyClassFactory x = 44 # this class will inherit attributes and methods # defined by the meta-class # this uses the class factory of its superclass class SubClass(BaseClass): def h(self): print self.x Copyright ©2000-15 CRS Enterprises Ltd 273 Object Attribute Resolution Order Object lookup ignores meta classes object ClassA ClassB b (object) Copyright ©2000-15 CRS Enterprises Ltd 274 Class Attribute Resolution Order Class lookup includes meta classes object type ClassA Meta=ClassA ClassB MetaClassB Copyright ©2000-15 CRS Enterprises Ltd 275 19 Oracle Database Copyright ©2000-15 CRS Enterprises Ltd 278 Connect Connect to database and retrieve a cursor object import cx_Oracle def ConnectToOracle(): connection = cx_Oracle.connect( user="java", password="oracle", dsn="XE") return connection def GetCursor(connection): cursor = cx_Oracle.Cursor(connection) return cursor Copyright ©2000-15 CRS Enterprises Ltd 279 Cursors Used to parse and execute SQL and fetch results usually only a single cursor is required multiple cursors can be defined Parse cx_Oracle.Cursor.parse(statement) Execute cx_Oracle.Cursor.execute(statement, parameters) Fetch cx_Oracle.Cursor.fetchall( ) cx_Oracle.Cursor.fetchmany(rows) cx_Oracle.Cursor.fetchone( ) Copyright ©2000-15 CRS Enterprises Ltd 280 Data Types ORACLE cx_Oracle Python VARCHAR2 NVARCHAR2 LONG STRING str CHAR FIXED_CHAR str NUMBER NUMBER int FLOAT NUMBER float DATE DATETIME datetime.datetime TIMESTAMP TIMESTAMP datetime.datetime CLOB CLOB cx_Oracle.LOB BLOB BLOB cx_Oracle.LOB Copyright ©2000-15 CRS Enterprises Ltd 281 Select Statements Use cursor to execute a SELECT query on database def PrintSalaryTable(connection): cursor = GetCursor(connection) SQL = "SELECT * FROM SALARY_TABLE" cursor.execute(SQL) for name, salary in cursor.fetchall(): print name, salary connection = ConnectToOracle() PrintSalaryTable(connection) Copyright ©2000-15 CRS Enterprises Ltd 282 Insert Statements Use cursor to execute INSERT on database def InsertRow(connection, name, salary): try: SQL = "INSERT INTO SALARY_TABLE (Name, Salary) " + \ "VALUES ('" + name +"'" + \ " ,'" + str(salary) +"')" cursor = GetCursor(connection) cursor.execute(SQL) cursor.close() connection.commit() except Exception, reason: connection.rollback() print reason connection = ConnectToOracle() InsertRow(connection, "George", 15000.0) Copyright ©2000-15 CRS Enterprises Ltd 283 Stored Procedures Names used in Stored Procedure must be used in Python see next slide create or replace PROCEDURE Increase_Salary (theName IN varchar2, Increase IN float, parameter names NewSalary IN OUT float) AS BEGIN UPDATE SalaryTable SET SALARY = SALARY + Increase WHERE NAME = theName; SELECT SALARY INTO NewSalary FROM SalaryTable WHERE NAME = theName; END; Copyright ©2000-15 CRS Enterprises Ltd 284 Stored Procedures Use cursor to execute StroredProcedure def UseStoredProcedure(connection, name, increase): try: cursor = GetCursor(connection) newSalary = cursor.var(cx_Oracle.NUMBER) result = cursor.callproc('INCREASE_SALARY', \ [name, increase, newSalary]) print "result=", result print "newSalary=", newSalary print "newSalary=", newSalary.getvalue() connection.commit() except Exception, reason: connection.rollback() print reason connection = ConnectToOracle() UseStoredProcedure(connection, name="Charles", increase=10000.0) Copyright ©2000-15 CRS Enterprises Ltd 285 Bind Variables ... Bind Python names to StoredProcedure names def method(cursor, name, salary): named_params = { 'aName':name, 'aSalary':salary } SQL = 'UPDATE SALARY_TABLE SET salary=:aSalary WHERE name=:aName' cursor.execute(SQL, named_params) print cursor.bindnames() def UseBindVariables(connection, name, salary): try: cursor = GetCursor(connection) method(cursor, name, salary) connection.commit() except Exception, reason: connection.rollback() print reason connection = ConnectToOracle() UseBindVariables(connection, "Charles", 10005.0) Copyright ©2000-15 CRS Enterprises Ltd 286 20 Operator Overloading Intrinsic Attributes for classes and objects Dynamic Statements exec and eval Operator Overloading numeric types list types Copyright ©2000-15 CRS Enterprises Ltd 290 Operator Overloading Numeric Types class Time: def __init__(self, hrs, min): self.hrs = hrs self.min = min def __add__(self, other): hrs = self.hrs + other.hrs min = self.min + other.min if min >= 60: hrs = hrs + 1 min = min - 60 return Time(hrs, min) t3 = t1 + t2 def Display(self): print "Time is", self.hrs, self.min Copyright ©2000-15 CRS Enterprises Ltd 291 Operator Overloading Numeric Types class Time: def __init__(self, hrs, min): self.hrs = hrs self.min = min def __iadd__(self, other): self.hrs = self.hrs + other.hrs self.min = self.min + other.min if self.min >= 60: self.hrs = self.hrs + 1 self.min = self.min - 60 return self t1 += t3 def Display(self): print "Time is", self.hrs, self.min Copyright ©2000-15 CRS Enterprises Ltd 292 Operator Overloading Numeric Types class Time: def __init__(self, hrs, min): self.hrs = hrs self.min = min def __add__(self, other): hrs = self.hrs + other.hrs min = self.min + other.min if min >= 60: hrs = hrs + 1 min = min - 60 return Time(hrs, min) t1 = Time(5,30) t2 = Time(3,30) t3 = t1 + t2 t3.Display() def __iadd__(self, other): t1 += t3 self.hrs = self.hrs + other.hrs t1.Display() self.min = self.min + other.min if self.min >= 60: self.hrs = self.hrs + 1 self.min = self.min - 60 return self Time is 9 0 Time is 14 30 def Display(self): print "Time is", self.hrs, self.min Copyright ©2000-15 CRS Enterprises Ltd 293 Operator Overloading other Types Emulate other types Built-In Objects Sequences Slices Emulate Maps Special Methods to be Written e.g. for Maps __len__(self) __getitem__(self,key) __setitem__(self,key,value) __delitem__(self,key) Copyright ©2000-15 CRS Enterprises Ltd 294 Operator Overloading List Types class MyList: def __init__(self, p1, p2): self.theList = [ ] self.theList.append(p1) self.theList.append(p2) t1 = MyList(1,2) t2 = MyList(3,4) t3 = t1 + t2 def __add__(self, other): result = [ ] for item in self.theList: result.append(item) for item in other.theList: result.append(item) return result t1: [1,2] t2: [3,4] t3: [1,2,3,4] Copyright ©2000-15 CRS Enterprises Ltd 295 Overloading [ ] using __getitem__ class mydata: def __init__(self): self.data = "ABCDEFG" def __getitem__(self, i): return self.data[i] B ABCDEFG object = mydata() theChar = object[1] print theChar; for item in object: print item, Copyright ©2000-15 CRS Enterprises Ltd 296 21 Web Application Frameworks Django Pyramid Flask Copyright ©2000-15 CRS Enterprises Ltd 300 Django Good points the most famous Python web framework easy to get started with documentation focused on beginners comes with a lot of integrated functionality can develop large scale applications supports decorators in views has its own templates Jinja2 developed as a superset of Django templates Not so good points has a fixed way of doing things model breaks down somewhat if you want to use other python packages not integrated with Django e.g. possible to use SQLAlchemy instead of the Django ORM, but it’s certainly not straightforward Copyright ©2000-15 CRS Enterprises Ltd 301 Pyramid Good points can develop large scale applications flexible core set of modules if you need anything else, like an ORM you can integrate it yourself ideal for apps which go beyond CRUD supports decorators in views no restrictions on template engines Not so good points not really a framework for the beginner there is a learning curve Copyright ©2000-15 CRS Enterprises Ltd 302 Flask Good points simplicity can develop applications quickly supports decorators in views uses Jinja2 as template engine Not so good points not designed for very large and complex websites can’t use other template engines chameleon, mako Copyright ©2000-15 CRS Enterprises Ltd 303 MVT Model/View/Template Variant of MVC Model used for specifying database schema or other method of gathering data often contains the business logic View used for managing the presentation Django uses this for business logic Template assists with the presentation use one of the many template engines Copyright ©2000-15 CRS Enterprises Ltd 304 Popular Web Template Engines Template engines offer high reusability of markup code Includes: to incorporate snippets of content common to site e.g. footer, scripts, styles, etc. Master Layout: skeleton of the site content with placeholders e.g. sidebar, horizontal menu, content, etc. Widgets: snippets of reusable markup e.g. list item, button, etc. Copyright ©2000-15 CRS Enterprises Ltd chameleon cheetah django jinja2 mako durusworks spitfire tenjin tornado web2py wheezy.template 305 Routing in Pyramid Decorators used to configure routing name specifies what to request on the browser default route has no name from pyramid.view import view_config @view_config(renderer="home.pt") def home(request): return {} @view_config(renderer="pages.pt", name="page1") def view1(request): return { "firstName": "Chris", "lastName": "Seddon“ } @view_config(renderer="pages.pt", name="page2") def view2(request): return { "firstName": "John", "lastName": "Smith“ } Copyright ©2000-15 CRS Enterprises Ltd 306 Templates Template expanded to HTML <h1>Football Teams and Grounds: Grounds</h1> <div> <li> Amsterdam ArenA - Amsterdam </li> <div metal:use-macro="layout"> <li> <div metal:fill-slot="content"> Wembley - London </li> <li tal:repeat="g theGrounds"> <li> ${g.ground} - ${g.city} Nou Camp - Barcelona </li> </li> </div> <li> Hampden Park - Glasgow </div> </li> loop </div> <ul> <li><a href="/">Home</a></li> <li><a href="/teams">Teams</a></li> <li><a href="/grounds">Grounds</a></li> <li><a href="/both">Teams and Grounds</a></li> </ul> Copyright ©2000-15 CRS Enterprises Ltd 307 22 JSON and XML Copyright ©2000-15 CRS Enterprises Ltd 310 JSON Parsing object unordered set of name/value pairs { color: "red", value: "#f00" } array ordered collection of values [ 100, 500, 300, 200, 400 ] Copyright ©2000-15 CRS Enterprises Ltd 311 Working with JSON Object with embedded arrays and objects { "products": [ { "company":"Company1", "name":"Prod1", "prices": [ {"price":123.2},{"price":123.6} ], "serialNumber":"12345" }, { "company":"Company2", "name":"Prod2", "prices": [ {"price":234.2},{"price":234.6} ], "serialNumber":"67890" } ] } Copyright ©2000-15 CRS Enterprises Ltd 312 JSON Encoder For user defined types include class and module names class MyEncoder(json.JSONEncoder): def default(self, obj): # Convert objects to a dictionary of their representation d = {} d['__class__'] = obj.__class__.__name__ d['__module__'] = obj.__module__ d.update(obj.__dict__) return d Copyright ©2000-15 CRS Enterprises Ltd 313 JSON Decoder For user defined types with class and module names included class MyDecoder(json.JSONDecoder): def __init__(self): json.JSONDecoder.__init__(self, object_hook=self.dict_to_object) def dict_to_object(self, d): if '__class__' in d: class_name = d.pop('__class__') module_name = d.pop('__module__') module = __import__(module_name) class_ = getattr(module, class_name) args = dict( (key.encode('ascii'), value) for key, value in d.items()) instance = class_(**args) return instance Copyright ©2000-15 CRS Enterprises Ltd 314 XML Parsing XML is more verbose than JSON but more common in industry <?xml version="1.0"?> <Book> <Title>Sherlock Holmes</Title> <Author>Arthur Conan Doyle</Author> </Book> ElementTree module will parse XML, but has no namespace support Copyright ©2000-15 CRS Enterprises Ltd 315 XML Namespaces Prefix is bound to a URL URL doesn't have to exist you don't have to use a URL Prefix acts as a variable URL is its value the value can change <?xml version="1.0"?> <Book xmlns:lib="http://www.library.com"> <lib:Title>Sherlock Holmes</lib:Title> <lib:Author>Arthur Conan Doyle</lib:Author> </Book> lxml is namespace aware built on top of ElementTree Copyright ©2000-15 CRS Enterprises Ltd 316 Using the Default Namespace defines the namespace for unqualified tags <?xml version="1.0"?> <Book xmlns="http://www.library.com"> <Title>Sherlock Holmes</Title> <Author>Arthur Conan Doyle</Author> </Book> Copyright ©2000-15 CRS Enterprises Ltd 317 ElementTree DOM (in memory) parser namespace support Example shows how to find author's first and last names from xml.etree.ElementTree import * from xml.etree.ElementTree import _namespace_map filename = "../xml/book.xml" tree = parse(filename) root = tree.getroot() author = tree.find("{http://www.demo.com/book}author"); print "first=", author.get("first") print "last=", author.get("last") Copyright ©2000-15 CRS Enterprises Ltd 318 lxml Extension to ElementTree DOM and SAX parsers XPath support XSLT support Example shows DOM parsing from lxml import etree doc = etree.parse('xml/book.xml') print(etree.tostring(doc, pretty_print=True)) Copyright ©2000-15 CRS Enterprises Ltd 319 HTML Parsing from HTMLParser import HTMLParser # create a subclass and override the handler methods class MyHTMLParser(HTMLParser): def handle_starttag(self, tag, attrs): print "Encountered a start tag:", tag def handle_endtag(self, tag): print "Encountered an end tag :", tag def handle_data(self, data): print "Encountered some data :", data # instantiate the parser and fed it some HTML parser = MyHTMLParser() parser.feed('<html><head><title>Test</title></head>' '<body><h1>Parse me!</h1></body></html>') Copyright ©2000-15 CRS Enterprises Ltd 320 Beautiful Soup from BeautifulSoup import BeautifulSoup # use mechanize to scrape spans from BBC news page br = mechanize.Browser() br.open("http://www.bbc.co.uk/news") response = br.follow_link(text_regex=r"UK") data = br.response().read() # pick out anchors that are tagged with the story class soup = BeautifulSoup(data) tags = soup.findAll("a", "story") newSoup = BeautifulSoup() for tag in tags: tag.insert(0, "<br>") newSoup.insert(0, tag) data = str(newSoup) Copyright ©2000-15 CRS Enterprises Ltd 321 23 Miscellaneous Topics PDF files Excel Zip Files GUI Frameworks Plotting Image Processing Copyright ©2000-15 CRS Enterprises Ltd 324 Working with PDF Files PyPDF2 replaces PyPDF open-source pure-Python libraries which concentrate on manipulation of existing PDF instances ReportLab industrial-strength library largely focused on precise creation of PDF open-source, no-charge base, but ... "ReportLab PLUS" extension is not free PDFMiner tool for extracting information from PDF documents focuses entirely on getting and analyzing text data Copyright ©2000-15 CRS Enterprises Ltd 325 Working with Excel Use the modules: xlrd and xlrt works with Linux and Mac not just Windows Best place to start when working with Excel files: http://www.python-excel.org Excellent set of examples: http://www.simplistix.co.uk/presentations/europython2009excel.zip http://www.simplistix.co.uk/presentations/python-excel.pdf Copyright ©2000-15 CRS Enterprises Ltd 326 Zip Files zipfile provides tools to create, read, write, append, and list a ZIP file does not currently handle multi-disk ZIP files handles ZIP files that use the ZIP64 extensions (> 4 GByte) supports decryption of encrypted files in ZIP archives cannot create an encrypted file decryption is extremely slow as it is implemented in native Python rather than C import zipfile zipfile.ZipFile("gp444win32.zip", "r").extractall() Copyright ©2000-15 CRS Enterprises Ltd 327 GUI Frameworks: Tkinter Tkinter is Python's de-facto standard GUI package thin object-oriented layer on top of Tcl/Tk Tkinter wiki: from Tkinter import * http://tkinter.unpythonic.net/wiki/ def main(): root = Tk() root.title("Hello World") root.minsize(width=300, height=300) mainframe = Frame(master=root) mainframe.pack() draw(mainframe) root.mainloop() def draw(frame): Button(frame, text = "Hello World", command = lambda : exit()).pack() main() Copyright ©2000-15 CRS Enterprises Ltd 328 GUI Frameworks: PyQt Python bindings for the Qt cross-platform GUI/XML/SQL C++ framework PyQt provides bindings for Qt 4 and Qt 5 choice of licences: GPL or commercial Contains over 620 classes that cover: graphical user interfaces XML handling network communication SQL databases Web browsing Copyright ©2000-15 CRS Enterprises Ltd 329 GUI Frameworks: wxPython Python bindings implemented as a Python extension module (native code) that wraps the popular wxWidgets cross platform GUI library written in C++ wxPython is Open Source free to use source code is available for anyone to look at and modify wxPython is a cross-platform toolkit same program will run on multiple platforms without modification supported platforms are 32-bit Microsoft Windows, most Unix or unix-like systems, and Macintosh OS X. Copyright ©2000-15 CRS Enterprises Ltd 330 Accessing the Web urllib/urllib2 provides a high-level interface for fetching data across the World Wide Web urlopen() function is similar to the built-in file open() function, but accepts Universal Resource Locators (URLs) can only open URLs for reading no seek operations import urllib Requests f = urllib.urlopen("http://www.ibm.com") print f.read() alternative to urllib claims to be much easier to use quote: ‘Python’s standard urllib2 module provides most of the HTTP capabilities you need, but the API is thoroughly broken. It was built for a different time — and a different web. It requires an enormous amount of work (even method overrides) to perform the simplest of tasks.’ Copyright ©2000-15 CRS Enterprises Ltd 331 More Modules for the Web webbrowser high-level interface to display Web-based documents import webbrowser url = 'http://www.ibm.com' webbrowser.open_new_tab(url) mechanize library is used for automating interaction with websites. automatically stores and sends cookies follows redirects follows links and submits forms keeps track of the sites that you have visited as a history import mechanize br = mechanize.Browser() br.open("http://www.bbc.co.uk/news") response = br.follow_link(text_regex=r"UK") data = br.response().read() Copyright ©2000-15 CRS Enterprises Ltd 332 Selenium Used to write tests for web applications simple API to write functional/acceptance tests using Selenium WebDriver Works with Firefox, IE, Chrome ... from selenium import webdriver from selenium.webdriver.common.keys import Keys driver = webdriver.Firefox() driver.get("http://www.python.org") assert "Python" in driver.title elem = driver.find_element_by_name("q") elem.send_keys("selenium") elem.send_keys(Keys.RETURN) assert "Google" in driver.title driver.close() Copyright ©2000-15 CRS Enterprises Ltd 333 Plotting matplotlib plotting library which producing publication quality figures in a variety of hardcopy formats and interactive environments across platforms see gallery: http://matplotlib.org/gallery.html gnuplot older library with Python bindings very extensive capabilities import matplotlib.pyplot as plt redCircles = "ro" plt.plot([1,2,3,4], [1,4,9,16], redCircles) plt.ylabel("squares") plt.show() Copyright ©2000-15 CRS Enterprises Ltd 334 Python Imaging Library PIL adds image processing capabilities to your Python interpreter library supports many file formats and provides powerful image processing and graphics capabilities http://www.pythonware.com/products/pil/ Python Imaging Library Handbook very useful examples http://effbot.org/imagingbook/pil-index.htm Copyright ©2000-15 CRS Enterprises Ltd 335