diff --git a/Examples/Session01/schedule.py b/Examples/Session01/schedule.py index 7dcb1300..4bdb59db 100644 --- a/Examples/Session01/schedule.py +++ b/Examples/Session01/schedule.py @@ -8,16 +8,17 @@ # remove the header line del students[0] +# strip the whitespace +students = [line.strip() for line in students] + # remove the languages, colon, etc. students = [line.split(":")[0] for line in students] # reverse the first, last names - # separate them: students = [line.split(",") for line in students] - # put them back together -students = ["{} {}".format(first, last) for last, first in students] +students = ["{} {}".format(first.strip(), last) for last, first in students] # put them in random order random.shuffle(students) @@ -26,7 +27,7 @@ weeks = list(range(2, 11)) # make three of them... -weeks = weeks * 3 +weeks = weeks * 4 # put the students together with the weeks schedule = zip(weeks, students) diff --git a/Examples/Session01/schedule.txt b/Examples/Session01/schedule.txt deleted file mode 100644 index 2325408f..00000000 --- a/Examples/Session01/schedule.txt +++ /dev/null @@ -1,26 +0,0 @@ -week 2: Brendan Fogarty -week 2: Bruce Bauman -week 2: Michelle Yu -week 3: Eric Rosko -week 3: Michael Waddle -week 3: Robert Stevens Alford -week 4: Andrey Gusev -week 4: Cheryl Ohashi -week 4: Maxwell MacCamy -week 5: Michael Cimino -week 5: Pei Lin -week 5: Tiffany Ku -week 6: Gabriel Meringolo -week 6: Joseph Cardenas -week 6: Marc Teale -week 7: Eric Starr Vegors -week 7: Ian Cote -week 7: Masako Tebbetts -week 8: Kathleen Devlin (Moved to week 9) -week 8: Robert Ryan Leslie -week 8: Ryan Morin -week 9: Erica Winberry -week 9: Robert Jenkins -week 9: Kathleen Devlin -week 10: Austin Scara -week 10: Marty Pitts diff --git a/Examples/Session01/students.txt b/Examples/Session01/students.txt deleted file mode 100644 index 2f992dfd..00000000 --- a/Examples/Session01/students.txt +++ /dev/null @@ -1,26 +0,0 @@ -name: languages -Alford, Robert Stevens: javascript php -Bauman, Bruce: chemstation macro fortran, java -Cardenas, Joseph: python C html CSS lisp javascript -Cimino, Michael: C C++ Java SQL -Cote, Ian: bash ruby perl python -Devlin, Kathleen: 4D -Fogarty, Brendan: SQL -Gusev, Andrey: perl java bash -Jenkins, Robert: assm pascal -Ku, Tiffany: python SQL -Leslie, Robert Ryan: python -Lin, Pei: SQL java R -MacCamy, Maxwell: C C++ C# assm java -Meringolo, Gabriel: python -Morin, Ryan: python sql -Ohashi, Cheryl: -Pitts, Marty: python, similink and matlab -Rosko, Eric: C C++ -Scara, Austin: VBA SQL -Teale, Marc: perl bash -Tebbetts, Masako: SQL -Vegors, Eric Starr: bash perl -Waddle, Michael: -Winberry, Erica: python -Yu, Michelle: ruby objectiveC diff --git a/Examples/Session01/test.py b/Examples/Session01/test.py index 1466c954..8a557325 100644 --- a/Examples/Session01/test.py +++ b/Examples/Session01/test.py @@ -1,9 +1,12 @@ x = 5 y = 55 -print x, y +print(x, y) def f(): x = 5 return x + +def f2(): + 5 + "5" diff --git a/Examples/Session03/mailroom_start.py b/Examples/Session03/mailroom_start.py new file mode 100644 index 00000000..9605afe7 --- /dev/null +++ b/Examples/Session03/mailroom_start.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + + +def print_report(): + print("This will print a report") + + +def send_thanks(): + print("This will write a thank you note") + +# here is where triple quoted strings can be helpful +msg = """ +What would you like to do? + +To send a thank you: type "s" +To print a report: type "p" +To exit: type "x" +""" + + +def main(): + """ + run the main interactive loop + """ + + response = '' + # keep asking until the users responds with an 'x' + while True: # make sure there is a break if you have infinite loop! + print(msg) + response = input("==> ").strip() # strip() in case there are any spaces + + if response == 'p': + print_report() + elif response == 's': + send_thanks() + elif response == 'x': + break + else: + print('please type "s", "p", or "x"') + +if __name__ == "__main__": + main() diff --git a/Examples/Session04/__main__example.py b/Examples/Session04/__main__example.py new file mode 100755 index 00000000..603f2e57 --- /dev/null +++ b/Examples/Session04/__main__example.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +print("every module has a __name__") + +print("What it is depends on how it is used") + +print("right now, this module's __name__ is: {}".format(__name__)) + +# so if you want coce to run only when a module is a top level script, +# you use this clause: +#if __name__ == "__main__": + +print("I must be running as a top-level script") diff --git a/Examples/Session06/cigar_party.py b/Examples/Session06/cigar_party.py new file mode 100644 index 00000000..992d99bd --- /dev/null +++ b/Examples/Session06/cigar_party.py @@ -0,0 +1,15 @@ + +""" +When squirrels get together for a party, they like to have cigars. +A squirrel party is successful when the number of cigars is between +40 and 60, inclusive. Unless it is the weekend, in which case there +is no upper bound on the number of cigars. + +Return True if the party with the given values is successful, +or False otherwise. +""" + + +def cigar_party(num, weekend): + return num >= 40 and (num <= 60 or weekend) + diff --git a/Examples/Session06/codingbat.py b/Examples/Session06/codingbat.py new file mode 100644 index 00000000..25865839 --- /dev/null +++ b/Examples/Session06/codingbat.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +""" +Examples from: http://codingbat.com + +Put here so we can write unit tests for them ourselves +""" + +# Python > Warmup-1 > sleep_in + +# The parameter weekday is True if it is a weekday, and the parameter +# vacation is True if we are on vacation. +# +# We sleep in if it is not a weekday or we're on vacation. +# Return True if we sleep in. + + +def sleep_in(weekday, vacation): + return not weekday or vacation + + +# We have two monkeys, a and b, and the parameters a_smile and b_smile +# indicate if each is smiling. + +# We are in trouble if they are both smiling or if neither of them is +# smiling. + +# Return True if we are in trouble. + +def monkey_trouble(a_smile, b_smile): + return a_smile is b_smile diff --git a/Examples/Session06/safe_input.py b/Examples/Session06/safe_input.py new file mode 100644 index 00000000..81785375 --- /dev/null +++ b/Examples/Session06/safe_input.py @@ -0,0 +1,25 @@ +def safe_input(): + try: + the_input = input("\ntype something >>> ") + except (KeyboardInterrupt, EOFError) as error: + print("the error: ", error) + error.extra_info = "extra info for testing" + # raise + return None + return the_input + +def main(): + safe_input() + +def divide(x,y): + try: + return x/y + except ZeroDivisionError as err: + print("you put in a zero!!!") + print("the exeption:", err) + err.args = (("very bad palce for a zero",)) + err.extra_stuff = "all kinds of things" + raise + +# if __name__ == '__main__': +# main() \ No newline at end of file diff --git a/Examples/Session06/test_cigar_party.py b/Examples/Session06/test_cigar_party.py index b3d76446..80bc0920 100644 --- a/Examples/Session06/test_cigar_party.py +++ b/Examples/Session06/test_cigar_party.py @@ -61,3 +61,4 @@ def test_10(): def test_11(): assert cigar_party(39, True) is False + diff --git a/Examples/Session06/test_codingbat.py b/Examples/Session06/test_codingbat.py new file mode 100755 index 00000000..354dcb34 --- /dev/null +++ b/Examples/Session06/test_codingbat.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +""" +test file for codingbat module + +This version can be run with nose or py.test +""" + +from codingbat import sleep_in, monkey_trouble + + +# tests for sleep_in +def test_false_false(): + assert sleep_in(False, False) + + +def test_true_false(): + assert not (sleep_in(True, False)) + + +def test_false_true(): + assert sleep_in(False, True) + + +def test_true_true(): + assert sleep_in(True, True) + + +# put tests for monkey_trouble here +# monkey_trouble(True, True) → True +# monkey_trouble(False, False) → True +# monkey_trouble(True, False) → False + +def test_monkey_true_true(): + assert monkey_trouble(True, True) + +def test_monkey_false_false(): + assert monkey_trouble(False, False) + +def test_monkey_true_false(): + assert monkey_trouble(True, False) is False + +# more! diff --git a/Examples/Session06/test_pytest_parameter.py b/Examples/Session06/test_pytest_parameter.py new file mode 100644 index 00000000..4e82a3ab --- /dev/null +++ b/Examples/Session06/test_pytest_parameter.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +""" +pytest example of a parameterized test + +NOTE: there is a failure in here! can you fix it? + +""" +import pytest + + +# a (really simple) function to test +def add(a, b): + """ + returns the sum of a and b + """ + return a + b + +# now some test data: + +test_data = [((2, 3), 5), + ((-3, 2), -1), + ((2, 0.5), 2.5), + (("this", "that"), "this that"), + (([1, 2, 3], [6, 7, 8]), [1, 2, 3, 6, 7, 8]), + ] + + +@pytest.mark.parametrize(("input", "result"), test_data) +def test_add(input, result): + assert add(*input) == result diff --git a/Examples/Session06/test_random_pytest.py b/Examples/Session06/test_random_pytest.py new file mode 100644 index 00000000..441f239a --- /dev/null +++ b/Examples/Session06/test_random_pytest.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +""" +port of the random unit tests from the python docs to py.test +""" + +import random +import pytest + + +seq = list(range(10)) + + +def test_shuffle(): + # make sure the shuffled sequence does not lose any elements + random.shuffle(seq) + # seq.sort() # commenting this out will make it fail, so we can see output + print("seq:", seq) # only see output if it fails + assert seq == list(range(10)) + + +def test_shuffle_immutable(): + """should get a TypeError with an imutable type """ + with pytest.raises(TypeError): + random.shuffle((1, 2, 3)) + + +def test_choice(): + """make sure a random item selected is in the original sequence""" + element = random.choice(seq) + assert (element in seq) + + +def test_sample(): + """make sure all items returned by sample are there""" + for element in random.sample(seq, 5): + assert element in seq + + +def test_sample_too_large(): + """should get a ValueError if you try to sample too many""" + with pytest.raises(ValueError): + random.sample(seq, 20) diff --git a/Examples/Session06/test_random_unitest.py b/Examples/Session06/test_random_unitest.py new file mode 100644 index 00000000..f825be5b --- /dev/null +++ b/Examples/Session06/test_random_unitest.py @@ -0,0 +1,30 @@ +import random +import unittest + + +class TestSequenceFunctions(unittest.TestCase): + + def setUp(self): + self.seq = list(range(10)) + + def test_shuffle(self): + # make sure the shuffled sequence does not lose any elements + random.shuffle(self.seq) + self.seq.sort() + self.assertEqual(self.seq, list(range(10))) + + # should raise an exception for an immutable sequence + self.assertRaises(TypeError, random.shuffle, (1, 2, 3)) + + def test_choice(self): + element = random.choice(self.seq) + self.assertTrue(element in self.seq) + + def test_sample(self): + with self.assertRaises(ValueError): + random.sample(self.seq, 20) + for element in random.sample(self.seq, 5): + self.assertTrue(element in self.seq) + +if __name__ == '__main__': + unittest.main() diff --git a/Examples/Session07/html_render/run_html_render.py b/Examples/Session07/html_render/run_html_render.py index 663e5ff8..d282fdc9 100644 --- a/Examples/Session07/html_render/run_html_render.py +++ b/Examples/Session07/html_render/run_html_render.py @@ -42,12 +42,16 @@ def render_page(page, filename): page = hr.Element() -page.append("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text") +page.append("Here is a paragraph of text -- there could be more of them, " + "but this is enough to show that we can do some text") page.append("And here is another piece of text -- you should be able to add any number") render_page(page, "test_html_output1.html") +# The rest of the steps have been commented out. +# Uncomment them a you move along with the assignment. + # ## Step 2 # ########## @@ -55,7 +59,8 @@ def render_page(page, filename): # body = hr.Body() -# body.append(hr.P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text")) +# body.append(hr.P("Here is a paragraph of text -- there could be more of them, " +# "but this is enough to show that we can do some text")) # body.append(hr.P("And here is another piece of text -- you should be able to add any number")) @@ -75,7 +80,8 @@ def render_page(page, filename): # body = hr.Body() -# body.append(hr.P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text")) +# body.append(hr.P("Here is a paragraph of text -- there could be more of them, " +# "but this is enough to show that we can do some text")) # body.append(hr.P("And here is another piece of text -- you should be able to add any number")) # page.append(body) @@ -94,7 +100,8 @@ def render_page(page, filename): # body = hr.Body() -# body.append(hr.P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", +# body.append(hr.P("Here is a paragraph of text -- there could be more of them, " +# "but this is enough to show that we can do some text", # style="text-align: center; font-style: oblique;")) # page.append(body) @@ -113,7 +120,8 @@ def render_page(page, filename): # body = hr.Body() -# body.append(hr.P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", +# body.append(hr.P("Here is a paragraph of text -- there could be more of them, " +# "but this is enough to show that we can do some text", # style="text-align: center; font-style: oblique;")) # body.append(hr.Hr()) @@ -134,7 +142,8 @@ def render_page(page, filename): # body = hr.Body() -# body.append(hr.P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", +# body.append(hr.P("Here is a paragraph of text -- there could be more of them, " +# "but this is enough to show that we can do some text", # style="text-align: center; font-style: oblique;")) # body.append(hr.Hr()) @@ -161,7 +170,8 @@ def render_page(page, filename): # body.append( hr.H(2, "PythonClass - Class 6 example") ) -# body.append(hr.P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", +# body.append(hr.P("Here is a paragraph of text -- there could be more of them, " +# "but this is enough to show that we can do some text", # style="text-align: center; font-style: oblique;")) # body.append(hr.Hr()) @@ -200,7 +210,8 @@ def render_page(page, filename): # body.append( hr.H(2, "PythonClass - Class 6 example") ) -# body.append(hr.P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", +# body.append(hr.P("Here is a paragraph of text -- there could be more of them, " +# "but this is enough to show that we can do some text", # style="text-align: center; font-style: oblique;")) # body.append(hr.Hr()) diff --git a/Examples/Session07/simple_classes.py b/Examples/Session07/simple_classes.py index 267f0d5e..4f996061 100644 --- a/Examples/Session07/simple_classes.py +++ b/Examples/Session07/simple_classes.py @@ -46,6 +46,18 @@ def __init__(self, x, y): def get_color(self): return self.color + def get_size(self): + return self.size + +class Rect: + + def __init__(self, w, h): + self.w = w + self.h = h + + def get_size(self): + return self.w * self.h + p3 = Point3(4, 5) print(p3.size) diff --git a/Examples/Session08/circle.py b/Examples/Session08/circle.py index 88ee5240..6d2d6018 100644 --- a/Examples/Session08/circle.py +++ b/Examples/Session08/circle.py @@ -9,4 +9,16 @@ class Circle: - pass + @staticmethod + def a_method(x): + return x**2 + + def regular_method(self): + print(self) + + @classmethod + def class_method(cls): + print(cls) + + + diff --git a/Examples/Session09/capitalize/capitalize/__init__.py b/Examples/Session09/capitalize/capitalize/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/Examples/Session09/capitalize/capitalize/capital_mod.py b/Examples/Session09/capitalize/capitalize/capital_mod.py deleted file mode 100644 index 352f0874..00000000 --- a/Examples/Session09/capitalize/capitalize/capital_mod.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -""" -A really simple module, just to demonstrate disutils -""" - -def capitalize(infilename, outfilename): - """ - reads the contents of infilename, and writes it to outfilename, but with - every word capitalized - - note: very primitive -- it will mess some files up! - - this is called by the capitalize script - """ - infile = open(infilename, 'U') - outfile = open(outfilename, 'w') - - for line in infile: - outfile.write( " ".join( [word.capitalize() for word in line.split() ] ) ) - outfile.write("\n") - - return None \ No newline at end of file diff --git a/Examples/Session09/capitalize/capitalize/test/__init__.py b/Examples/Session09/capitalize/capitalize/test/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/Examples/Session09/capitalize/capitalize/test/test_text_file.txt b/Examples/Session09/capitalize/capitalize/test/test_text_file.txt deleted file mode 100644 index a64b50f7..00000000 --- a/Examples/Session09/capitalize/capitalize/test/test_text_file.txt +++ /dev/null @@ -1,7 +0,0 @@ -This is a really simple Text file. -It is here so that I can test the capitalize script. - -And that's only there to try out distutils. - -So there. - \ No newline at end of file diff --git a/Examples/Session09/capitalize/scripts/cap_script.py b/Examples/Session09/capitalize/scripts/cap_script.py deleted file mode 100755 index 08f999e3..00000000 --- a/Examples/Session09/capitalize/scripts/cap_script.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python - -""" -A really simple script just to demonstrate disutils -""" - -import sys, os -from capitalize import capital_mod - - -if __name__ == "__main__": - try: - infilename = sys.argv[1] - except IndexError: - print "you need to pass in a file to process" - - root, ext = os.path.splitext(infilename) - outfilename = root + "_cap" + ext - - # do the real work: - print "Capitalizing: %s and storing it in %s"%(infilename, outfilename) - capital_mod.capitalize(infilename, outfilename) - - print "I'm done" - \ No newline at end of file diff --git a/Examples/Session09/capitalize/setup.py b/Examples/Session09/capitalize/setup.py deleted file mode 100755 index d7acd8eb..00000000 --- a/Examples/Session09/capitalize/setup.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -""" -This is about as simple a setup.py as you can have - -It installs the capitalize module and script - -""" - -# classic distutils -#from distutils.core import setup - -## uncomment to support "develop" mode -from setuptools import setup - -setup( - name='Capitalize', - version='0.1.0', - author='Chris Barker', - py_modules=['capitalize/capital_mod',], - scripts=['scripts/cap_script.py',], - description='Not very useful capitalizing module and script', -) - diff --git a/Examples/Session09/closure.py b/Examples/Session09/closure.py new file mode 100644 index 00000000..a7e7d07d --- /dev/null +++ b/Examples/Session09/closure.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +""" +Example code for closures / currying +""" + +from functools import partial + + +def counter(start_at=0): + count = [start_at] + + def incr(): + count[0] += 1 + return count[0] + return incr + + +def power(base, exponent): + """returns based raised to the given exponent""" + return base ** exponent + +# now some specialized versions: + +square = partial(power, exponent=2) +cube = partial(power, exponent=3) diff --git a/Examples/Session10/p_wrapper.py b/Examples/Session10/p_wrapper.py new file mode 100644 index 00000000..f80c4d15 --- /dev/null +++ b/Examples/Session10/p_wrapper.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +""" +p_wrapper decorator +""" + + +def p_wrapper(function): + def func(*args, **kwargs): + string = function(*args, **kwargs) + string = "

{}

".format(string) + return string + return func + + +class tag_wrapper: + def __init__(self, tag): + self.tag = tag + + def __call__(self, orig_func): + def func(*args, **kwargs): + string = orig_func(*args, **kwargs) + string = "<{tag}> {s} ".format(tag=self.tag, s=string) + return string + return func diff --git a/Examples/Session10/test_p_wrapper.py b/Examples/Session10/test_p_wrapper.py index 40ba0fde..12603692 100644 --- a/Examples/Session10/test_p_wrapper.py +++ b/Examples/Session10/test_p_wrapper.py @@ -4,7 +4,7 @@ test code for the p_wrapper assignment """ -from p_wrapper import p_wrapper #, tag_wrapper +from p_wrapper import p_wrapper, tag_wrapper def test_p_wrapper(): @@ -22,7 +22,7 @@ def f_string(a, b, this=45 ): assert f_string(2, 3, this=54) == "

the numbers are: 2, 3, 54

" -#Extra credit: +# #Extra credit: def test_tag_wrapper(): @tag_wrapper('html') diff --git a/Examples/Session10/timer.py b/Examples/Session10/timer.py new file mode 100644 index 00000000..3a07bd75 --- /dev/null +++ b/Examples/Session10/timer.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +""" +timing context manager +""" + +import sys +import time + +class Timer: + def __init__(self, outfile=sys.stdout): + self.outfile = outfile + + def __enter__(self): + self.start = time.time() + + def __exit__(self, exc_type, exc_val, exc_tb): + self.outfile.write("elapsed time:{} seconds".format(time.time() - self.start)) \ No newline at end of file diff --git a/README.rst b/README.rst index 835744c3..9274ab3e 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ IntroToPython Introduction to Python: First in the Python Certification series. -This repository contains the source materials for the first class in the the University of Washington Professional and Continuing Education Program Python Certification Program: +This repository contains the source materials for the first class in the University of Washington Professional and Continuing Education Program Python Certification Program: .. _Certificate in Python Programming : http://www.pce.uw.edu/certificates/python-programming.html diff --git a/Syllabus.rst b/Syllabus.rst index 3257c7fe..86a9b6ef 100644 --- a/Syllabus.rst +++ b/Syllabus.rst @@ -15,7 +15,7 @@ The Python Certificate program is a 9-month curriculum divided into three course First Course: Introduction to Python ===================================== -Tuesdays 6-9 pm: Oct 6 - Dec 8, 2015 (10 Sessions) +Tuesdays 6-9 pm: Sept 27 - Dec 6, 2016 (10 Sessions) --------------------------------------------------- @@ -142,7 +142,7 @@ Reading: There is no assigned text book. However, you may find it beneficial to read other discussions of topics in addition to what I present in class or assign as reading: either to explore a topic more deeply, or to simple get another viewpoint. There are many good books on Python, and many more excellent discussions of individual topics on the web. -Note that mamny books still cover primarily (or only) Python 2. THey can still be very, very useful, the syntax is only a little different, and the concepts the same. +Note that many books still cover primarily (or only) Python 2. THey can still be very, very useful, the syntax is only a little different, and the concepts the same. A few you may want to consider: @@ -233,7 +233,7 @@ Class Schedule: Topics of each week -------------------- -Week 1: Oct 6 +Week 1: September 27 ................ General Introduction to Python and the class. Using the command interpreter and development environment. @@ -245,7 +245,7 @@ Finding and using the documentation. Getting help. Python 2/3 differences. -Week 2: Oct 13 +Week 2: October 4 ................ Introduction to git and gitHub @@ -259,7 +259,7 @@ Modules and import Conditionals and Boolean expressions -Week 3: Oct 20 +Week 3: October 11 ................. Sequences: Strings, Tuples, Lists @@ -269,7 +269,7 @@ Iteration, looping and control flow. String methods and formatting -Week 4: Oct 27 +Week 4: October 18 ................ Dictionaries, Sets and Mutability. @@ -277,47 +277,50 @@ Dictionaries, Sets and Mutability. Files and Text Processing -Week 5: November 3 +Week 5: October 25 ........................ Exceptions -Testing - List and Dict Comprehensions +Week 6: November 1 +.................. -Week 6: November 10 -.................... +Testing Advanced Argument passing -Lambda -Functions as Objects +**No class Nov 8th for election night** + +Week 7: November 15 +................... -Week 7: November 17 -....................... +Object Oriented Programming: -Object Oriented Programming: classes, instances, and methods +classes, instances, methods, inheritance -Week 8: November 24 -.................... +Week 8: November 22 +................... More OO: Multiple inheritance, Properties, Special methods. Emulating built-in types -Week 9: December 1 +Week 9: November 29 ................... +Lambda + +Functions as Objects Iterators and Generators -Week 10: December 8 -.................... +Week 10: December 6 +................... Decorators diff --git a/slides_sources/build_gh_pages.sh b/slides_sources/build_gh_pages.sh index 02ab36d3..6eccd8fb 100755 --- a/slides_sources/build_gh_pages.sh +++ b/slides_sources/build_gh_pages.sh @@ -3,15 +3,26 @@ # simple script to build and push to gh-pages # designed to be run from master +# To use this script you need another copy of the repo, right next this +# one, but named "IntroToPython.gh-pages" +# this script builds the docs, then copies them to the other repo +# then pushes that to gitHub + +GHPAGESDIR=../../IntroToPython.gh-pages/ + +# make sure the Gh pages repo is there and in the right branch +pushd $GHPAGESDIR +git checkout gh-pages +popd + # make the docs make html - # copy to other repo (on the gh-pages branch) -cp -R build/html/ ../../IntroToPython.gh-pages +cp -R build/html/ $GHPAGESDIR -cd ../../IntroToPython.gh-pages -git checkout gh-pages +pushd $GHPAGESDIR git add * # in case there are new files added git commit -a -m "updating presentation materials" -git pull -s ours +git pull -s ours --no-edit git push + diff --git a/slides_sources/source/conf.py b/slides_sources/source/conf.py index f31fc924..ace14544 100644 --- a/slides_sources/source/conf.py +++ b/slides_sources/source/conf.py @@ -36,11 +36,15 @@ 'sphinx.ext.coverage', # 'sphinx.ext.pngmath', 'sphinx.ext.mathjax', + #'sphinx.ext.jsmath', 'sphinx.ext.ifconfig', 'IPython.sphinxext.ipython_console_highlighting', 'IPython.sphinxext.ipython_directive', ] +# this doesn't work. +jsmath_path = "../../../jsMath-3.6e/easy/load.js" # needed for jsmath + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/slides_sources/source/exercises/args_kwargs_lab.rst b/slides_sources/source/exercises/args_kwargs_lab.rst new file mode 100644 index 00000000..2adffc00 --- /dev/null +++ b/slides_sources/source/exercises/args_kwargs_lab.rst @@ -0,0 +1,71 @@ +.. _exercise_args_kwargs_lab: + +******************* +args and kwargs Lab +******************* + +Learning about ``args`` and ``kwargs`` +====================================== + +Goal: +----- + +Develop an understanding of using advanced argument passing and parameter definitons. + +If this is all confusing -- you may want to review this: + +http://stupidpythonideas.blogspot.com/2013/08/arguments-and-parameters.html + +Procedure +--------- + +**Keyword arguments:** + +* Write a function that has four optional parameters (with defaults): + + - `fore_color` + - `back_color` + - `link_color` + - `visited_color` + +* Have it print the colors (use strings for the colors) + +* Call it with a couple different parameters set + + - using just positional arguments: + + - ``func('red', 'blue', 'yellow', 'chartreuse')`` + + - using just keyword arguments: + + - ``func(link_color='red', back_color='blue')`` + + - using a combination of positional and keyword + + - ````func('purple', link_color='red', back_color='blue')`` + + - using ``*some_tuple`` and/or ``**some_dict`` + + - ``regular = ('red', 'blue')`` + + - ``links = {'link_color': 'chartreuse'}`` + + - ``func(*regular, *links)`` + +.. nextslide:: + +**Generic parameters:** + +* Write a the same function with the parameters as: + +``*args`` and ``**kwags`` + +* Have it print the colors (use strings for the colors) + +* Call it with the same various combinations of arguments used above. + +* Also have it print `args` and `kwargs` directly, so you can be sure you understand what's going on. + +* Note that in general, you can't know what will get passed into ``**kwargs`` So maybe adapt your function to be able to do something reasonable with any keywords. + + diff --git a/slides_sources/source/exercises/comprehensions_lab.rst b/slides_sources/source/exercises/comprehensions_lab.rst index 5fac6b40..fb9152e5 100644 --- a/slides_sources/source/exercises/comprehensions_lab.rst +++ b/slides_sources/source/exercises/comprehensions_lab.rst @@ -133,7 +133,7 @@ Dictionary comprehensions 'forth':'fanatical devotion', 'fifth': None} >>> dict_comprehension = \ - { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon} + { k.upper(): weapon for k, weapon in dict_of_weapons.items() if weapon} What is the output of: @@ -164,8 +164,6 @@ https://github.com/gregmalcolm/python_koans/blob/master/python3/koans/about_comp Count Even Numbers ------------------ -Use test-driven development! - This is from CodingBat "count_evens" (http://codingbat.com/prob/p189616) *Using a list comprehension*, return the number of even integers in the given array. @@ -190,7 +188,7 @@ Note: the % "mod" operator computes the remainder, e.g. ``5 % 2`` is 1. ``dict`` and ``set`` comprehensions ------------------------------------ -Let's revisiting the dict/set lab -- see how much you can do with +Revisiting the dict/set lab -- see how much you can do with comprehensions instead. (:ref:`exercise_dict_lab`) @@ -234,11 +232,19 @@ divisible 2, 3 and 4. a. Do this with one set comprehension for each set. - b. What if you had a lot more than 3? -- Don't Repeat Yourself (DRY) + b. What if you had a lot more than 3? -- Don't Repeat Yourself (DRY). - - create a sequence that holds all three sets + - create a sequence that holds all the divisors you might want -- + could be 2,3,4, or could be any other arbitrary divisors. - loop through that sequence to build the sets up -- so no repeated code. + you will end up with a list of sets -- one set for each divisor in your + sequence. + + - The idea here is that when you see three (Or more!) lines of code that + are almost identical, then you you want to find a way to generalize + that code and have it act on a set of inputs, so the actual code is + only written once. c. Extra credit: do it all as a one-liner by nesting a set comprehension inside a list comprehension. (OK, that may be getting carried away!) diff --git a/slides_sources/source/exercises/dict_lab.rst b/slides_sources/source/exercises/dict_lab.rst index 519e1f10..fe4ce49c 100644 --- a/slides_sources/source/exercises/dict_lab.rst +++ b/slides_sources/source/exercises/dict_lab.rst @@ -67,7 +67,7 @@ actions: * Using the dictionary from item 1: Make a dictionary using the same keys but - with the number of 't's in each value. + with the number of 't's in each value as the value. (upper and lower case?). .. nextslide:: Sets diff --git a/slides_sources/source/exercises/fib_and_lucas.rst b/slides_sources/source/exercises/fib_and_lucas.rst index 0181536c..86343f60 100644 --- a/slides_sources/source/exercises/fib_and_lucas.rst +++ b/slides_sources/source/exercises/fib_and_lucas.rst @@ -73,6 +73,14 @@ Calling this function with no optional parameters will produce numbers from the produce values from the *lucas numbers*. Other values for the optional parameters will produce other series. +**Note:** While you *could* check the input arguments, and then call one +of the functions you wrote, the idea of this exercise is to make a general +function, rather than one specialized. So you should re-impliment the code +in this function. + +In fact, you could go back and re-impliment your fibonacci and lucas +functions to call this one with particular arguments. + Ensure that your function has a well-formed ``docstring`` Tests... diff --git a/slides_sources/source/exercises/file_lab.rst b/slides_sources/source/exercises/file_lab.rst new file mode 100644 index 00000000..44b3f656 --- /dev/null +++ b/slides_sources/source/exercises/file_lab.rst @@ -0,0 +1,55 @@ +.. _exercise_file_lab: + +******** +File LAB +******** + +A bit of practice with files +============================ + +Goal: +----- + +Get a little bit of practice with handling files and parsing simple text. + + +Paths and File Processing +-------------------------- + +* write a program which prints the full path to all files in the current + directory, one per line + +* write a program which copies a file from a source, to a destination + (without using shutil, or the OS copy command) + + - advanced: make it work for any size file: i.e. don't read the entire + contents of the file into memory at once. + + - This should work for any kind of file, so you need to open + the files in binary mode: ``open(filename, 'rb')`` (or ``'wb'`` for + writing). Note that for binary files, you can't use ``readline()`` -- + lines don't have any meaning for binary files. + + - Test it with both text and binrary files (maybe jpeg or??) + + +File reading and parsing +------------------------ + + +In the class repo, in: + +``Examples/Session01/students.txt`` + +You will find the list I generated in the first class of all the students in the class, and what programming languages they have used in the past. + +Write a little script that reads that file, and generates a list of all +the languages that have been used. + +Extra credit: keep track of how many students specified each language. + +If you've got git set up right, ``git pull upstream master`` should update +your repo. Otherwise, you can get it from gitHub: + +https://github.com/UWPCE-PythonCert/IntroPython2016/blob/master/Examples/Session01/students.txt + diff --git a/slides_sources/source/exercises/fizz_buzz.rst b/slides_sources/source/exercises/fizz_buzz.rst index 33f0091c..d6f19fe1 100644 --- a/slides_sources/source/exercises/fizz_buzz.rst +++ b/slides_sources/source/exercises/fizz_buzz.rst @@ -35,12 +35,12 @@ Hint: * Look up the ``%`` operator. What do these do? - * ``10 % 7 == 3`` - * ``14 % 7 == 0`` + * ``10 % 7`` + * ``14 % 7`` (try that in iPython) -* Do try to write it without looking it up -- there are a million nifty solutions posted on the web. +* **Do** try to write a solution *before* looking it up -- there are a million nifty solutions posted on the web, but you'll learn a lot more if you figure it out on your own first. Results: -------- diff --git a/slides_sources/source/exercises/grid_printer.rst b/slides_sources/source/exercises/grid_printer.rst index 22619198..41e43f57 100644 --- a/slides_sources/source/exercises/grid_printer.rst +++ b/slides_sources/source/exercises/grid_printer.rst @@ -169,7 +169,7 @@ Even more general... A function with two parameters ------------------------------- -Write a function that draws a similar grid with a specified number of rows and three columns. +Write a function that draws a similar grid with a specified number of rows and columns, and each cell a given size. for example, ``print_grid2(3,4)`` results in:: diff --git a/slides_sources/source/exercises/html_renderer.rst b/slides_sources/source/exercises/html_renderer.rst index eaa1bf73..d38dc6e0 100644 --- a/slides_sources/source/exercises/html_renderer.rst +++ b/slides_sources/source/exercises/html_renderer.rst @@ -39,7 +39,7 @@ You should be able to run that code at each step, uncommenting each new step in It builds up an html tree, and then calls the ``render()`` method of your element to render the page. -It uses a ``cStringIO`` object (like a file, but in memory) to render to memory, then dumps it to the console, and writes a file. Take a look at the code at the end to make sure you understand it. +It uses a ``StringIO`` object (like a file, but in memory) to render to memory, then dumps it to the console, and writes a file. Take a look at the code at the end to make sure you understand it. The html generated at each step will be in the files: ``test_html_ouput?.html`` @@ -93,7 +93,7 @@ It should have a ``render(file_out, ind = "")`` method that renders the tag and The amount of each level of indentation should be set by the class attribute: ``indent`` -NOTE: don't worry too much about indentation at this stage -- the primary goal is to get proper, compliant html. i.e. the opening and closing tags rendered correctly. Worry about cleaning up the indentation once you've got that working. +NOTE: don't worry too much about indentation at this stage -- the primary goal is to get proper, compliant html. i.e. the opening and closing tags rendered correctly. Worry about cleaning up the indentation once you've got that working. See "Note on indentation" below for more explaination. .. nextslide:: @@ -162,6 +162,42 @@ You can now render some ``

`` tags (and others) with attributes See ``test_html_output4.html`` +.. nextslide:: the "class" attribute. + +NOTE: if you do "proper" CSS+html, then you wouldn't specify style directly in element attributes. + +Rather you would set the "class" attribute:: + +

+ This is my recipe for making curry purely with chocolate +

+ +However, if you try this as a keywork argument in Python: + +.. code-block:: ipython + + In [1]: P("some content", class="intro") + File "", line 1 + P("some content", class="intro") + ^ + SyntaxError: invalid syntax + +Huh? + +"class" is a reserved work in Python -- for making classes. +So it can't be used as a keywork argument. + +But it's a fine key in a dict, so you can put it in a dict, and pass it in with ``**``: + +.. code-block:: python + + attrs = {'class': 'intro'} + P("some content", **attrs) + +You could also special-case this in your code -- so your users could use "clas" +with one s, and you could tranlate it in the generated html. + + Step 5: -------- @@ -176,7 +212,7 @@ Create a couple subclasses of ``SelfClosingTag`` for and
and
Note that you now have a couple render methods -- is there repeated code in them? -Can you refactor the common parts into a separate method that all the render methods can call? +Can you refactor the common parts into a separate method that all the render methods can call? And do all your tests still pass (you do have tests for everything, don't you?) after refactoring? See ``test_html_output5.html`` @@ -191,7 +227,7 @@ where ``link`` is the link, and ``content`` is what you see. It can be called li A("http://google.com/", "link to google") -You should be able to subclass from ``Element``, and only override the ``__init__`` --- Calling the ``Element`` ``__init__`` from the ``A __init__`` +You should be able to subclass from ``Element``, and only override the ``__init__`` --- calling the ``Element`` ``__init__`` from the ``A __init__`` You can now add a link to your web page. @@ -235,6 +271,32 @@ new tags, etc.... See ``test_html_output8.html`` +Note on indentation +=================== + +Indentation is not stricly required for html -- html ignores most whitespace. + +But it can make it much easier to read for humans, and it's a nice excercise to see how one might make it nice. + +There is also more than one way to indent html -- so you have a bit of flexibility here. + +So: + +* You probably ``ind`` to be an optional argument to render -- so it will not indent if nothing is passed in. And that lets you write the code without indentation first if you like. + +* But ultimately, you want your code to USE the ind parameter -- it is supposed to indicate how much this entire tag is already indented. + +* When this one gets rendered, you don't know where it is in a potentially deeply nested hierarchy -- it could be at the top level or ten levels deep. passing ``ind`` into the render method is how this is communicated. + +* You have (at least) two options for how to indicate level of indentation: + + - It could be a integer indicating number of levels of indentation + - It could, more simply, be a bunch of spaces. + +* You want to have the amount of spaces per indentation defined as a class attribute of the base class (the ``Element`` class). That way, you could change it in one place, and it would change everywhere an remain consistent. + + + Notes on handling "duck typing" =============================== @@ -266,7 +328,8 @@ You can handle it ahead of time by creating a simple object that wraps a string self.text = text def render(self, file_out, current_ind=""): - file_out.write(current_ind + self.text) + file_out.write(current_ind) + file_out.write(self.text) .. nextslide:: @@ -284,7 +347,7 @@ But this is not very Pythonic style -- it's OO heavy. Strings for text are so co So much easier. -To accomplish this, you can update the ``append()`` method to put this wrapper around plain strings when somethign new is added. +To accomplish this, you can update the ``append()`` method to put this wrapper around plain strings when something new is added. Checking if it's the right type @@ -321,24 +384,28 @@ I think this is a little better -- strings are a pretty core type in python, it' Duck Typing ----------- -The Python model of duck typing is if quacks like a duck, then treat it like a duck. +The Python model of duck typing is: If quacks like a duck, then treat it like a duck. But in this case, we're not actually rendering the object at this stage, so calling the method isn't appropriate. **Checking for an attribute** -Instead of calling the method, see if it's there: +Instead of calling the method, see if it's there. You can do that with ``hasattr()`` -You can check if the passed-in object has a ``render()`` attribute: +check if the passed-in object has a ``render()`` attribute: .. code-block:: python if hasattr(content, 'render'): self.content.append(content) else: - self.content.append(TextWrapper(content)) + self.content.append(TextWrapper(str(content)) + + +Note that I added a ``str()`` call too -- so you can pass in anything -- it will get stringified -- this will be ugly for many objects, but will work fine for numbers and other simple objects. + +This is my favorite. ``html_render_wrap.py`` in Solutions demonstrates some core bits of this approach. -This is my favorite. ``html_render_wrap.py`` in Solutions demonstrates with method. Duck Typing on the Fly ---------------------- @@ -356,7 +423,7 @@ Again, you could type check -- but I prefer the duck typing approach, and EAFP: If content is a simple string then it won't have a render method, and an ``AttributeError`` will be raised. -You can catch that, and simply write the content. +You can catch that, and simply write the content directly instead. .. nextslide:: @@ -376,11 +443,11 @@ If the object doesn't have a ``render`` method, then an AttributeError will be r Depending on what's broken, it could raise any number of exceptions. Most will not get caught by the except clause, and will halt the program. -But if, just by bad luck, it has an bug that raises an ``AttributeError`` -- then this could with catch it, and try to simply write it out instead. So you may get somethign like: ```` in the middle of your html. +But if, just by bad luck, it has an bug that raises an ``AttributeError`` -- then this could catch it, and try to simply write it out instead. So you may get something like: ```` in the middle of your html. **The beauty of testing** -If you have a unit test that calls every render method in your code -- then it should catch that error, and it wil be clear where it is coming from. +If you have a unit test that calls every render method in your code -- then it should catch that error, and in the unit test it will be clear where it is coming from. HTML Primer @@ -388,13 +455,13 @@ HTML Primer .. rst-class:: medium - The very least you need to know about html to do this assigment. + The very least you need to know about html to do this assignment. .. rst-class:: left - If you are familar with html, then this will all make sense to you. If you have never seen html before, this might be a bit intimidating, but you really don't need to know much to do this assignment. + If you are familiar with html, then this will all make sense to you. If you have never seen html before, this might be a bit intimidating, but you really don't need to know much to do this assignment. - First of all, sample output from each step is provided. So all you really need to do is look at that, and make your code do the same thing. But it does help to know a little bit about what you are doing. + First of all, sample output from each step is provided. So all you really need to do is look at that, and make your code do the same thing. But it does help understand a little bit about what you trying to do. HTML ---- @@ -421,15 +488,16 @@ Elements Modern HTML is a particular dialect of XML (eXtensible Markup Language), which is itself a special case of SGML (Standard Generalized Markup Language) -It inherits from SGML a basic structure: each piece of the document is an element. each element is described by a "tag". Each tag has a different meaning, but they all have the same structure:: +It inherits from SGML a basic structure: each piece of the document is an element. Each element is described by a "tag". Each tag has a different meaning, but they all have the same structure:: some content -that is, the tag name is surrounded by < and >, which marks the beginning of +That is, the tag name is surrounded by < and >, which marks the beginning of the element, and the end of the element is indicated by the same tag with a slash. The real power is that these elements can be nested arbitrarily deep. In order to keep that all readable, we often want to indent the content inside the tags, so it's clear what belongs with what. That is one of the tricky bits of this assignment. + Basic tags ---------- @@ -450,7 +518,7 @@ In addition to the tag name and the content, extra attributes can be attached to .. code-block:: html -

+

There can be all sorts of stuff stored in attributes -- some required for specific tags, some extra, like font sizes and colors. Note that since tags can essentially have any attributes, your code will need to support that -- doesn't it kind of look like a dict? And keyword arguments? @@ -471,7 +539,10 @@ To make a link, you use an "anchor" tag: ````. It requires attributes to indi The ``href`` attribute is the link (hyper reference). -To make a bulleted list, you use a