diff --git a/.gitignore b/.gitignore index 6d8b9b0c..200982db 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ slides_sources/build *.pyc *junk* +# testing detritus +.cache + #ignore sublime workspace files *.sublime* @@ -13,3 +16,6 @@ slides_sources/build # editor back-up files *.*~ + +# pycache +__pycache__/* \ No newline at end of file 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 9d7c5ee7..00000000 --- a/Examples/Session01/schedule.txt +++ /dev/null @@ -1,25 +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 -week 8: Robert Ryan Leslie -week 8: Ryan Morin -week 9: Erica Winberry -week 9: Robert Jenkins -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/Session03/slicing_lab.py b/Examples/Session03/slicing_lab.py new file mode 100644 index 00000000..a13c5623 --- /dev/null +++ b/Examples/Session03/slicing_lab.py @@ -0,0 +1,31 @@ +# slicing lab + + +def swap(seq): + return seq[-1:]+seq[1:-1]+seq[:1] + + +assert swap('something') == 'gomethins' +assert swap(tuple(range(10))) == (9,1,2,3,4,5,6,7,8,0) + +def rem(seq): + return seq[::2] + +assert rem('a word') == 'awr' + +def rem4(seq): + return seq[4:-4:2] + +print(rem4( (1,2,3,4,5,6,7,8,9,10,11), ) ) + +def reverse(seq): + return seq[::-1] + +print(reverse('a string')) + +def thirds(seq): + i = len(seq)//3 + #return seq[i*2:i*3+1] + seq[:i] + seq[i:i*2] + return seq[i:-i] + seq[-i:] + seq[:i] + +print (thirds(tuple(range(12)))) 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/Session05/arg_test.py b/Examples/Session05/arg_test.py index c84b5bdf..83c76e80 100644 --- a/Examples/Session05/arg_test.py +++ b/Examples/Session05/arg_test.py @@ -2,5 +2,4 @@ import sys -print sys.argv - +print(sys.argv) diff --git a/Examples/Session05/codingbat.py b/Examples/Session05/codingbat.py index 1dcf82eb..3971c4eb 100644 --- a/Examples/Session05/codingbat.py +++ b/Examples/Session05/codingbat.py @@ -10,6 +10,4 @@ def sleep_in(weekday, vacation): - return not (weekday == True and vacation == False) - - + return not (weekday and vacation) diff --git a/Examples/Session05/test_codingbat.py b/Examples/Session05/test_codingbat.py index 6e845b0e..6681bdc3 100755 --- a/Examples/Session05/test_codingbat.py +++ b/Examples/Session05/test_codingbat.py @@ -14,7 +14,7 @@ def test_false_false(): def test_true_false(): - assert not ( sleep_in(True, False) ) + assert not (sleep_in(True, False)) def test_false_true(): diff --git a/Examples/Session05/test_pytest_parameter.py b/Examples/Session05/test_pytest_parameter.py index 52449af3..4e82a3ab 100644 --- a/Examples/Session05/test_pytest_parameter.py +++ b/Examples/Session05/test_pytest_parameter.py @@ -8,6 +8,7 @@ """ import pytest + # a (really simple) function to test def add(a, b): """ @@ -17,14 +18,14 @@ def add(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]), - ] +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/Session05/test_random_pytest.py b/Examples/Session05/test_random_pytest.py index e8b80f8c..c798efa9 100644 --- a/Examples/Session05/test_random_pytest.py +++ b/Examples/Session05/test_random_pytest.py @@ -8,20 +8,19 @@ import pytest -seq = range(10) +seq = list(range(10)) def test_shuffle(): # make sure the shuffled sequence does not lose any elements random.shuffle(seq) - seq.sort() - print "seq:", seq - ## expect this to fail -- so we can see the output. - assert seq == range(10) + # seq.sort() # this will amke 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(): - pytest.raises(TypeError, random.shuffle, (1,2,3) ) + pytest.raises(TypeError, random.shuffle, (1, 2, 3)) def test_choice(): diff --git a/Examples/Session05/test_random_unitest.py b/Examples/Session05/test_random_unitest.py index 6458e6ce..f825be5b 100644 --- a/Examples/Session05/test_random_unitest.py +++ b/Examples/Session05/test_random_unitest.py @@ -1,19 +1,20 @@ import random import unittest + class TestSequenceFunctions(unittest.TestCase): def setUp(self): - self.seq = range(10) + 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, range(10)) + self.assertEqual(self.seq, list(range(10))) # should raise an exception for an immutable sequence - self.assertRaises(TypeError, random.shuffle, (1,2,3) ) + self.assertRaises(TypeError, random.shuffle, (1, 2, 3)) def test_choice(self): element = random.choice(self.seq) @@ -26,4 +27,4 @@ def test_sample(self): self.assertTrue(element in self.seq) if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Examples/Session06/cigar_party.py b/Examples/Session06/cigar_party.py index 18878463..992d99bd 100644 --- a/Examples/Session06/cigar_party.py +++ b/Examples/Session06/cigar_party.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """ When squirrels get together for a party, they like to have cigars. @@ -11,18 +10,6 @@ """ -def cigar_party(cigars, is_weekend): - """ - basic solution - """ - if ( 40 <= cigars <= 60 ) or ( cigars >= 40 and is_weekend): - return True - else: - return False +def cigar_party(num, weekend): + return num >= 40 and (num <= 60 or weekend) - -def cigar_party3(cigars, is_weekend): - """ - conditional expression - """ - return (cigars >= 40) if is_weekend else (cigars >= 40 and cigars <= 60) diff --git a/Examples/Session06/closure.py b/Examples/Session06/closure.py new file mode 100644 index 00000000..a7e7d07d --- /dev/null +++ b/Examples/Session06/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/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 a03ca3c5..80bc0920 100644 --- a/Examples/Session06/test_cigar_party.py +++ b/Examples/Session06/test_cigar_party.py @@ -1,10 +1,20 @@ #!/usr/bin/env python -import cigar_party +""" +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. -#cigar_party = cigar_party.cigar_party -#cigar_party = cigar_party.cigar_party2 -cigar_party = cigar_party.cigar_party3 +Return True if the party with the given values is successful, +or False otherwise. +""" + + +# you can change this import to test different versions +from cigar_party import cigar_party +# from cigar_party import cigar_party2 as cigar_party +# from cigar_party import cigar_party3 as cigar_party def test_1(): 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/circle.py b/Examples/Session07/circle.py deleted file mode 100644 index a6545632..00000000 --- a/Examples/Session07/circle.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -"""circle class -- - -fill this in so it will pass all the tests. -""" -import math - - -class Circle(object): - pass diff --git a/Examples/Session06/class.py b/Examples/Session07/class.py similarity index 82% rename from Examples/Session06/class.py rename to Examples/Session07/class.py index 1c131142..ac9a99b4 100644 --- a/Examples/Session06/class.py +++ b/Examples/Session07/class.py @@ -1,8 +1,8 @@ -class C(object): +class C: x = 5 + def __init__(self, y): self.y = y + def meth(self, z): return self.x + self.y + z - - \ No newline at end of file diff --git a/Examples/Session06/class_demo.py b/Examples/Session07/class_demo.py similarity index 88% rename from Examples/Session06/class_demo.py rename to Examples/Session07/class_demo.py index 33841a88..e66590d1 100644 --- a/Examples/Session06/class_demo.py +++ b/Examples/Session07/class_demo.py @@ -1,5 +1,5 @@ -class C(object): +class C: x = 5 def __init__(self, y): diff --git a/Examples/Session06/html_render/.DS_Store b/Examples/Session07/html_render/.DS_Store similarity index 100% rename from Examples/Session06/html_render/.DS_Store rename to Examples/Session07/html_render/.DS_Store diff --git a/Examples/Session06/html_render/html_render.py b/Examples/Session07/html_render/html_render.py similarity index 100% rename from Examples/Session06/html_render/html_render.py rename to Examples/Session07/html_render/html_render.py diff --git a/Examples/Session06/html_render/run_html_render.py b/Examples/Session07/html_render/run_html_render.py similarity index 77% rename from Examples/Session06/html_render/run_html_render.py rename to Examples/Session07/html_render/run_html_render.py index 74e5c378..d282fdc9 100644 --- a/Examples/Session06/html_render/run_html_render.py +++ b/Examples/Session07/html_render/run_html_render.py @@ -7,46 +7,51 @@ """ -from cStringIO import StringIO - +from io import StringIO # importing the html_rendering code with a short name for easy typing. import html_render as hr -reload(hr) # reloading in case you are running this in iPython - # -- we want to make sure the latest version is used +# reloading in case you are running this in iPython +# -- we want to make sure the latest version is used +import importlib +importlib.reload(hr) -## writing the file out: +# writing the file out: def render_page(page, filename): """ render the tree of elements - This uses cSstringIO to render to memory, then dump to console and + This uses StringIO to render to memory, then dump to console and write to file -- very handy! """ f = StringIO() page.render(f, " ") - f.reset() + f.seek(0) - print f.read() + print(f.read()) - f.reset() - open(filename, 'w').write( f.read() ) + f.seek(0) + open(filename, 'w').write(f.read()) -## Step 1 -########## +# Step 1 +######### 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 # ########## @@ -54,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")) @@ -74,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) @@ -93,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) @@ -112,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()) @@ -133,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()) @@ -160,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()) @@ -199,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()) @@ -221,7 +233,3 @@ def render_page(page, filename): # page.append(body) # render_page(page, "test_html_output8.html") - - - - diff --git a/Examples/Session06/html_render/sample_html.html b/Examples/Session07/html_render/sample_html.html similarity index 100% rename from Examples/Session06/html_render/sample_html.html rename to Examples/Session07/html_render/sample_html.html diff --git a/Examples/Session07/html_render/test_html_output1.html b/Examples/Session07/html_render/test_html_output1.html new file mode 100644 index 00000000..65c2d86c --- /dev/null +++ b/Examples/Session07/html_render/test_html_output1.html @@ -0,0 +1,5 @@ + + + Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text + And here is another piece of text -- you should be able to add any number + \ No newline at end of file diff --git a/Examples/Session07/html_render/test_html_output2.html b/Examples/Session07/html_render/test_html_output2.html new file mode 100644 index 00000000..d96afdc0 --- /dev/null +++ b/Examples/Session07/html_render/test_html_output2.html @@ -0,0 +1,11 @@ + + + +

+ Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text +

+

+ And here is another piece of text -- you should be able to add any number +

+ + \ No newline at end of file diff --git a/Examples/Session07/html_render/test_html_output3.html b/Examples/Session07/html_render/test_html_output3.html new file mode 100644 index 00000000..fcc9f120 --- /dev/null +++ b/Examples/Session07/html_render/test_html_output3.html @@ -0,0 +1,14 @@ + + + + PythonClass = Revision 1087: + + +

+ Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text +

+

+ And here is another piece of text -- you should be able to add any number +

+ + \ No newline at end of file diff --git a/Examples/Session07/html_render/test_html_output4.html b/Examples/Session07/html_render/test_html_output4.html new file mode 100644 index 00000000..dd891d92 --- /dev/null +++ b/Examples/Session07/html_render/test_html_output4.html @@ -0,0 +1,11 @@ + + + + PythonClass = Revision 1087: + + +

+ Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text +

+ + \ No newline at end of file diff --git a/Examples/Session07/html_render/test_html_output5.html b/Examples/Session07/html_render/test_html_output5.html new file mode 100644 index 00000000..5f160646 --- /dev/null +++ b/Examples/Session07/html_render/test_html_output5.html @@ -0,0 +1,12 @@ + + + + PythonClass = Revision 1087: + + +

+ Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text +

+
+ + \ No newline at end of file diff --git a/Examples/Session07/html_render/test_html_output6.html b/Examples/Session07/html_render/test_html_output6.html new file mode 100644 index 00000000..a99822d7 --- /dev/null +++ b/Examples/Session07/html_render/test_html_output6.html @@ -0,0 +1,15 @@ + + + + PythonClass = Revision 1087: + + +

+ Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text +

+
+ And this is a + link + to google + + \ No newline at end of file diff --git a/Examples/Session07/html_render/test_html_output7.html b/Examples/Session07/html_render/test_html_output7.html new file mode 100644 index 00000000..4f2c23bb --- /dev/null +++ b/Examples/Session07/html_render/test_html_output7.html @@ -0,0 +1,26 @@ + + + + PythonClass = Revision 1087: + + +

PythonClass - Class 6 example

+

+ Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text +

+
+ + + \ No newline at end of file diff --git a/Examples/Session07/html_render/test_html_output8.html b/Examples/Session07/html_render/test_html_output8.html new file mode 100644 index 00000000..3e2f249b --- /dev/null +++ b/Examples/Session07/html_render/test_html_output8.html @@ -0,0 +1,27 @@ + + + + + PythonClass = Revision 1087: + + +

PythonClass - Class 6 example

+

+ Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text +

+
+ + + \ No newline at end of file diff --git a/Examples/Session06/simple_classes.py b/Examples/Session07/simple_classes.py similarity index 70% rename from Examples/Session06/simple_classes.py rename to Examples/Session07/simple_classes.py index b170209d..4f996061 100644 --- a/Examples/Session06/simple_classes.py +++ b/Examples/Session07/simple_classes.py @@ -8,50 +8,66 @@ import math -## create a point class -class Point(object): +# create a point class +class Point: def __init__(self, x, y): self.x = x self.y = y -## create an instance of that class -p = Point(3,4) +# create an instance of that class +p = Point(3, 4) -## access the attributes -print "p.x is:", p.x -print "p.y is:", p.y +# access the attributes +print("p.x is:", p.x) +print("p.y is:", p.y) -class Point2(object): +class Point2: size = 4 - color= "red" + color = "red" + def __init__(self, x, y): self.x = x self.y = y -p2 = Point2(4,5) -print p2.size -print p2.color +p2 = Point2(4, 5) +print(p2.size) +print(p2.color) -class Point3(object): +class Point3: size = 4 - color= "red" + color = "red" + def __init__(self, x, y): self.x = x self.y = y + def get_color(self): return self.color + def get_size(self): + return self.size -p3 = Point3(4,5) -print p3.size -print p3.get_color() +class Rect: + def __init__(self, w, h): + self.w = w + self.h = h -class Circle(object): + def get_size(self): + return self.w * self.h + + +p3 = Point3(4, 5) +print(p3.size) +print(p3.get_color()) + + +class Circle: color = "red" styles = ['dashed'] + def __init__(self, diameter): self.diameter = diameter @@ -78,7 +94,7 @@ def grow(self, factor=2): self.diameter = self.diameter * math.sqrt(2) nc = NewCircle -print nc.color +print(nc.color) class CircleR(Circle): diff --git a/Examples/Session07/vector.py b/Examples/Session07/vector.py deleted file mode 100644 index 56ee2404..00000000 --- a/Examples/Session07/vector.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Vector type with +, * redefined as vector addition and dot product -From Jon Jacky's Intro to Python course: - http://staff.washington.edu/jon/python-course/ -""" - - -class vector(list): - def __repr__(self): - """ - String representation, uses list (superclass) representation - """ - return 'vector(%s)' % super(vector, self).__repr__() - - def __add__(self, v): - """ - redefine + as element-wise vector sum - """ - assert len(self) == len(v) - return vector([x1 + x2 for x1, x2 in zip(self, v)]) - - def __mul__(self, v): - """ - redefine * as vector dot product - """ - assert len(self) == len(v) - return sum([x1 * x2 for x1, x2 in zip(self, v)]) - -l1 = [1, 2, 3] -l2 = [4, 5, 6] -v1 = vector(l1) -v2 = vector(l2) - -if __name__ == '__main__': - print 'l1' - print l1 - print 'l1 + l2' - print l1 + l2 - # print l1 * l2 # TypeError - print 'zip(l1, l2)' - print zip(l1, l2) - print 'v1' - print v1 - print 'v1 + v2' - print v1 + v2 - print 'v1 * v2' - print v1 * v2 diff --git a/Examples/Session08/circle.py b/Examples/Session08/circle.py new file mode 100644 index 00000000..6d2d6018 --- /dev/null +++ b/Examples/Session08/circle.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +""" +circle class -- + +fill this in so it will pass all the tests. +""" +import math + + +class Circle: + @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/Session07/class_method.py b/Examples/Session08/class_method.py similarity index 69% rename from Examples/Session07/class_method.py rename to Examples/Session08/class_method.py index 1d893b94..93fba91f 100644 --- a/Examples/Session07/class_method.py +++ b/Examples/Session08/class_method.py @@ -5,14 +5,14 @@ """ -class C(object): +class C: def __init__(self, x, y): self.x = x self.y = y @classmethod def a_class_method(cls, y): - print "in a_class_method", cls + print("in a_class_method", cls) return cls(y, y**2) @@ -23,10 +23,10 @@ class C2(C): if __name__ == "__main__": c = C(3, 4) - print type(c), c.x, c.y + print(type(c), c.x, c.y) c2 = C.a_class_method(3) - print type(c2), c2.x, c2.y + print(type(c2), c2.x, c2.y) c3 = c2.a_class_method(2) - print type(c3), c3.x, c3.y + print(type(c3), c3.x, c3.y) diff --git a/Examples/Session07/properties_example.py b/Examples/Session08/properties_example.py similarity index 82% rename from Examples/Session07/properties_example.py rename to Examples/Session08/properties_example.py index fa9c732e..f70760e9 100644 --- a/Examples/Session07/properties_example.py +++ b/Examples/Session08/properties_example.py @@ -8,14 +8,16 @@ """ -class C(object): +class C: def __init__(self): self._x = None @property def x(self): + print("in getter") return self._x @x.setter def x(self, value): + print("in setter", value) self._x = value @x.deleter def x(self): @@ -24,5 +26,5 @@ def x(self): if __name__ == "__main__": c = C() c.x = 5 - print c.x + print(c.x) diff --git a/Examples/Session07/static_method.py b/Examples/Session08/static_method.py similarity index 84% rename from Examples/Session07/static_method.py rename to Examples/Session08/static_method.py index 6865408c..ce476ab0 100644 --- a/Examples/Session07/static_method.py +++ b/Examples/Session08/static_method.py @@ -5,7 +5,7 @@ """ -class C(object): +class C: @staticmethod def a_static_method(a, b): @@ -13,7 +13,7 @@ def a_static_method(a, b): return a+b def test(self): - return self.a_static_method(2,3) + return self.a_static_method(2, 3) # if __name__ == "__main__": @@ -24,5 +24,3 @@ def test(self): # print c.a_static_method(4,5) # print c.test() - - diff --git a/Examples/Session08/test_generator.py b/Examples/Session08/test_generator.py deleted file mode 100644 index cf02fae5..00000000 --- a/Examples/Session08/test_generator.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -test_generator.py - -tests the solution to the generator lab - -can be run with py.test or nosetests -""" - -import generator_solution as gen - - -def test_intsum(): - - g = gen.intsum() - - assert g.next() == 0 - assert g.next() == 1 - assert g.next() == 3 - assert g.next() == 6 - assert g.next() == 10 - assert g.next() == 15 - - -def test_intsum2(): - - g = gen.intsum2() - - assert g.next() == 0 - assert g.next() == 1 - assert g.next() == 3 - assert g.next() == 6 - assert g.next() == 10 - assert g.next() == 15 - - -def test_doubler(): - - g = gen.doubler() - - assert g.next() == 1 - assert g.next() == 2 - assert g.next() == 4 - assert g.next() == 8 - assert g.next() == 16 - assert g.next() == 32 - - for i in range(10): - j = g.next() - - assert j == 2**15 - - -def test_fib(): - g = gen.fib() - - assert g.next() == 1 - assert g.next() == 1 - assert g.next() == 2 - assert g.next() == 3 - assert g.next() == 5 - assert g.next() == 8 - assert g.next() == 13 - assert g.next() == 21 - - -def test_prime(): - g = gen.prime() - - assert g.next() == 2 - assert g.next() == 3 - assert g.next() == 5 - assert g.next() == 7 - assert g.next() == 11 - assert g.next() == 13 - assert g.next() == 17 - assert g.next() == 19 - assert g.next() == 23 - diff --git a/Examples/Session08/vector.py b/Examples/Session08/vector.py new file mode 100644 index 00000000..8d9e2eac --- /dev/null +++ b/Examples/Session08/vector.py @@ -0,0 +1,47 @@ +""" +Vector type with +, * redefined as Vector addition and dot product +From Jon Jacky's Intro to Python course: + http://staff.washington.edu/jon/python-course/ +""" + + +class Vector(list): + def __repr__(self): + """ + String representation, uses list (superclass) representation + """ + return 'Vector(%s)' % super(Vector, self).__repr__() + + def __add__(self, v): + """ + redefine + as element-wise Vector sum + """ + assert len(self) == len(v) + return Vector([x1 + x2 for x1, x2 in zip(self, v)]) + + def __mul__(self, v): + """ + redefine * as Vector dot product + """ + assert len(self) == len(v) + return sum([x1 * x2 for x1, x2 in zip(self, v)]) + +l1 = [1, 2, 3] +l2 = [4, 5, 6] +v1 = Vector(l1) +v2 = Vector(l2) + +if __name__ == '__main__': + print('l1') + print(l1) + print('l1 + l2') + print(l1 + l2) + # print(l1 * l2) # TypeError + print('zip(l1, l2)') + print(zip(l1, l2)) + print('v1') + print(v1) + print('v1 + v2') + print(v1 + v2) + print('v1 * v2') + print(v1 * v2) 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/Session09/ipythonlog.txt b/Examples/Session09/ipythonlog.txt deleted file mode 100644 index 52e36c40..00000000 --- a/Examples/Session09/ipythonlog.txt +++ /dev/null @@ -1,180 +0,0 @@ -# IPython log file - - -get_ipython().magic(u'run decorators.py') -add -add(2,3) -get_ipython().magic(u'run decorators.py') -add(2,3) -new_add = substitute(add) -new_add(2,3) -@substitute -def fun(1,2,3) -@substitute -def fun(1,2,3): - print "in fun" - -@substitute -def fun(a,b): - print "in fun" - -fun() -@logged_func -def fun(a,b): - print "in fun" - -fun(2,3) -fun(2,3,fred=4) -get_ipython().magic(u'run decorators.py') -get_ipython().magic(u'timeit sum2x(10)') -get_ipython().magic(u'run decorators.py') -get_ipython().magic(u'timeit sum2x(10)') -sum2x(100000000) -sum2x(100000000) -sum2x(10000000) -sum2x(10000000) -type(sum2x) -sum2x.function -sum2x.function(10) -sum2x.memoized -@Memoize -def other_fun(): -def other_fun(x): - -@Memoize -def fun2(x): - return x**100 - -fun2(4) -fun2(4) -fun2.memoized -@Memoize -def fun2asdf(x): - return x**100 - -get_ipython().magic(u'run decorators.py') -sum2x(1e6) -sum2x(1000000) -get_ipython().magic(u'run decorators.py') -sum2x(1000000) -sum2x(1000000) -sum2x(10000000) -sum2x(10000000) -get_ipython().magic(u'paste') -@Memoize -@timed_func -def sum2x(n): - return sum(2 * i for i in xrange(n)) -sum2x(1000000) -sum2x(1000000) -get_ipython().magic(u'run context_managers.py') -with Context(False): - print something - -with Context(False): - print "something" - -get_ipython().magic(u'paste') -with Context(True) as foo: - print 'This is in the context' - raise RuntimeError('this is the error message') -with Context(False): - raise RuntimeError('this is the error message') - -with context(False): - raise RuntimeError('this is the error message') - -with context(True): - raise RuntimeError('this is the error message') - -get_ipython().magic(u'run timer_context.py') -with Timer as t: - [x^2 for x in range(100000000)] - -get_ipython().magic(u'run timer_context.py') -with Timer as t: - [x^2 for x in range(100000000)] - -with Timer as t: - [x^2 for x in range(100000000)] - -get_ipython().magic(u'run timer_context.py') -with Timer as t: - [x^2 for x in range(100000000)] - -with Timer() as t: - [x^2 for x in range(100000000)] - -with Timer() as t: - [x^2 for x in range(1000000)] - -get_ipython().magic(u'run timer_context.py') -with Timer() as t: - [x^2 for x in range(1000000)] - -get_ipython().magic(u'run timer_context.py') -with Timer() as t: - [x^2 for x in range(1000000)] - -get_ipython().magic(u'run timer_context.py') -with Timer() as t: - [x^2 for x in range(1000000)] - -with Timer() as t: - [x^2 for x in range(10000000)] - -t -t.elapsed -with Timer() as t: - [x^2 for x in range(10000000)] - raise RuntimeError("this is an error") - -with Timer() as t: - [x^2 for x in range(10000000)] - raise RuntimeError("this is an error") - -with Timer() as t: - [x^2 for x in range(10000000)] - raise RuntimeError("this is an error") - -get_ipython().magic(u'run timer_context.py') -with Timer() as t: - [x^2 for x in range(10000000)] - raise RuntimeError("this is an error") - -get_ipython().magic(u'run timer_context.py') -with Timer() as t: - [x^2 for x in range(10000000)] - raise RuntimeError("this is an error") - -get_ipython().magic(u'run timer_context.py') -with Timer() as t: - [x^2 for x in range(10000000)] - raise RuntimeError("this is an error") - -get_ipython().magic(u'pinfo isinstance') -get_ipython().magic(u'run timer_context.py') -with Timer() as t: - [x^2 for x in range(10000000)] - raise RuntimeError("this is an error") - -get_ipython().magic(u'run timer_context.py') -with Timer() as t: - [x^2 for x in range(10000000)] - raise RuntimeError("this is an error") - -with Timer() as t: - [x^2 for x in range(10000000)] - raise RuntimeError("this is an error") -print "after Exception" - -with Timer() as t: - [x^2 for x in range(10000000)] - raise RuntimeError("this is an error") - print "after Exception" - -with Timer() as t: - [x^2 for x in range(10000000)] - raise ValueError("this is an error") - print "after Exception" - diff --git a/Examples/Session08/iterator_1.py b/Examples/Session09/iterator_1.py similarity index 84% rename from Examples/Session08/iterator_1.py rename to Examples/Session09/iterator_1.py index f2402385..6cc9231c 100644 --- a/Examples/Session08/iterator_1.py +++ b/Examples/Session09/iterator_1.py @@ -10,14 +10,14 @@ class IterateMe_1(object): About as simple an iterator as you can get: returns the sequence of numbers from zero to 4 - ( like xrange(4) ) + ( like range(4) ) """ def __init__(self, stop=5): self.current = -1 self.stop = stop def __iter__(self): return self - def next(self): + def __next__(self): self.current += 1 if self.current < self.stop: return self.current @@ -26,7 +26,7 @@ def next(self): if __name__ == "__main__": - print "Testing the iterator" + print("Testing the iterator") for i in IterateMe_1(): - print i + print(i) diff --git a/Examples/Session08/my_for.py b/Examples/Session09/my_for.py similarity index 93% rename from Examples/Session08/my_for.py rename to Examples/Session09/my_for.py index fd43ac6d..6023ad9f 100644 --- a/Examples/Session08/my_for.py +++ b/Examples/Session09/my_for.py @@ -26,7 +26,7 @@ def my_for(an_iterable, func): iterator = iter(an_iterable) while True: try: - i = iterator.next() + i = next(iterator) except StopIteration: break func(i) @@ -35,7 +35,7 @@ def my_for(an_iterable, func): if __name__ == "__main__": def print_func(x): - print x + print(x) l = [1,2,3,4,5,] my_for(l, print_func) diff --git a/Examples/Session09/test_generator.py b/Examples/Session09/test_generator.py new file mode 100644 index 00000000..d88255f7 --- /dev/null +++ b/Examples/Session09/test_generator.py @@ -0,0 +1,78 @@ +""" +test_generator.py + +tests the solution to the generator lab + +can be run with py.test or nosetests +""" + +import generator_solution as gen + + +def test_intsum(): + + g = gen.intsum() + + assert next(g) == 0 + assert next(g) == 1 + assert next(g) == 3 + assert next(g) == 6 + assert next(g) == 10 + assert next(g) == 15 + + +def test_intsum2(): + + g = gen.intsum2() + + assert next(g) == 0 + assert next(g) == 1 + assert next(g) == 3 + assert next(g) == 6 + assert next(g) == 10 + assert next(g) == 15 + + +def test_doubler(): + + g = gen.doubler() + + assert next(g) == 1 + assert next(g) == 2 + assert next(g) == 4 + assert next(g) == 8 + assert next(g) == 16 + assert next(g) == 32 + + for i in range(10): + j = next(g) + + assert j == 2**15 + + +def test_fib(): + g = gen.fib() + + assert next(g) == 1 + assert next(g) == 1 + assert next(g) == 2 + assert next(g) == 3 + assert next(g) == 5 + assert next(g) == 8 + assert next(g) == 13 + assert next(g) == 21 + + +def test_prime(): + g = gen.prime() + + assert next(g) == 2 + assert next(g) == 3 + assert next(g) == 5 + assert next(g) == 7 + assert next(g) == 11 + assert next(g) == 13 + assert next(g) == 17 + assert next(g) == 19 + assert next(g) == 23 + diff --git a/Examples/Session08/yield_example.py b/Examples/Session09/yield_example.py similarity index 83% rename from Examples/Session08/yield_example.py rename to Examples/Session09/yield_example.py index bbccb79f..81c9590d 100644 --- a/Examples/Session08/yield_example.py +++ b/Examples/Session09/yield_example.py @@ -1,9 +1,9 @@ def counter(): - print 'counter: starting counter' + print('counter: starting counter') i = -3 while i < 3: i = i + 1 - print 'counter: yield', i + print('counter: yield', i) yield i return None diff --git a/Examples/Session09/context_managers.py b/Examples/Session10/context_managers.py similarity index 60% rename from Examples/Session09/context_managers.py rename to Examples/Session10/context_managers.py index 326b66d3..ecf3ee54 100644 --- a/Examples/Session09/context_managers.py +++ b/Examples/Session10/context_managers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- import sys -from StringIO import StringIO +from io import StringIO from contextlib import contextmanager @@ -9,30 +9,34 @@ class Context(object): http://pymotw.com/2/contextlib/#module-contextlib """ def __init__(self, handle_error): - print '__init__(%s)' % handle_error + print('__init__({})'.format(handle_error)) self.handle_error = handle_error def __enter__(self): - print '__enter__()' + print('__enter__()') return self def __exit__(self, exc_type, exc_val, exc_tb): - print '__exit__(%s, %s, %s)' % (exc_type, exc_val, exc_tb) - return self.handle_error + print('__exit__({}, {}, {})'.format(exc_type, exc_val, exc_tb)) + if exc_type == ZeroDivisionError: + return True + else: + return False +# return self.handle_error @contextmanager def context(boolean): - print "__init__ code here" + print("__init__ code here") try: - print "__enter__ code goes here" + print("__enter__ code goes here") yield object() except Exception as e: - print "errors handled here" + print("errors handled here") if not boolean: - raise + raise e finally: - print "__exit__ cleanup goes here" + print("__exit__ cleanup goes here") @contextmanager @@ -46,4 +50,4 @@ def print_encoded(encoding): buff.seek(0) raw = buff.read() encoded = raw.encode(encoding) - print encoded + print(encoded) diff --git a/Examples/Session09/decorators.py b/Examples/Session10/decorators.py similarity index 69% rename from Examples/Session09/decorators.py rename to Examples/Session10/decorators.py index fc6bd80b..2b4539f4 100644 --- a/Examples/Session09/decorators.py +++ b/Examples/Session10/decorators.py @@ -9,21 +9,21 @@ def new_function(*args, **kwargs): def add(a, b): -# print "Function 'add' called with args: %r" % locals() + print("Function 'add' called with args: {}, {}".format(a, b) ) result = a + b -# print "\tResult --> %r" % result + print("\tResult --> {}".format(result)) return result def logged_func(func): def logged(*args, **kwargs): - print "Function %r called" % func.__name__ + print("Function {} called".format(func.__name__)) if args: - print "\twith args: %r" % (args, ) + print("\twith args: {}".format(args)) if kwargs: - print "\twith kwargs: %r" % kwargs + print("\twith kwargs: {}".format(kwargs)) result = func(*args, **kwargs) - print "\t Result --> %r" % result + print("\t Result --> {}".format(result)) return result return logged @@ -49,29 +49,28 @@ def __call__(self, *args): # runs when memoize instance is called return self.memoized[args] -#@Memoize +@Memoize def sum2x(n): - return sum(2 * i for i in xrange(n)) -sum2x = Memoize(sum2x) - - + return sum(2 * i for i in range(n)) +# sum2x = Memoize(sum2x) +@Memoize +def prod2(a,b): + return sum( a * b**2 for a,b in zip(range(a), range(b))) import time - def timed_func(func): def timed(*args, **kwargs): start = time.time() result = func(*args, **kwargs) elapsed = time.time() - start - print "time expired: %s" % elapsed + print("time expired: {}".format(elapsed)) return result return timed + @timed_func @Memoize def sum2x(n): - return sum(2 * i for i in xrange(n)) - - + return sum(2 * i for i in range(n)) diff --git a/Examples/Session09/memoize.py b/Examples/Session10/memoize.py similarity index 85% rename from Examples/Session09/memoize.py rename to Examples/Session10/memoize.py index 7c9650f1..25b0ee60 100644 --- a/Examples/Session09/memoize.py +++ b/Examples/Session10/memoize.py @@ -17,7 +17,7 @@ def __call__(self, *args): # runs when memoize instance is called @Memoize def sum2x(n): - return sum(2 * i for i in xrange(n)) + return sum(2 * i for i in range(n)) import time @@ -27,11 +27,12 @@ def timed(*args, **kwargs): start = time.time() result = func(*args, **kwargs) elapsed = time.time() - start - print "time expired: %s" % elapsed + print("time expired: {}".format(elapsed)) return result return timed + @timed_func @Memoize def sum2x(n): - return sum(2 * i for i in xrange(n)) + return sum(2 * i for i in range(n)) 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/Session09/property_ugly.py b/Examples/Session10/property_ugly.py similarity index 100% rename from Examples/Session09/property_ugly.py rename to Examples/Session10/property_ugly.py diff --git a/Examples/Session09/test_p_wrapper.py b/Examples/Session10/test_p_wrapper.py similarity index 74% rename from Examples/Session09/test_p_wrapper.py rename to Examples/Session10/test_p_wrapper.py index c73b6ef6..12603692 100644 --- a/Examples/Session09/test_p_wrapper.py +++ b/Examples/Session10/test_p_wrapper.py @@ -14,7 +14,15 @@ def return_a_string(string): assert return_a_string('this is a string') == '

this is a string

' -#Extra credit: +def test_with_args(): + @p_wrapper + def f_string(a, b, this=45 ): + return "the numbers are: {}, {}, {}".format(a,b,this) + + assert f_string(2, 3, this=54) == "

the numbers are: 2, 3, 54

" + + +# #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/Examples/Session10/timer_context.py b/Examples/Session10/timer_context.py new file mode 100644 index 00000000..ee327dcd --- /dev/null +++ b/Examples/Session10/timer_context.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +""" +Timer context manager +""" +import time + + +class Timer: + def __init__(self, file_like): + self.file_like = file_like + + def __enter__(self): + self.start = time.clock() + + def __exit__(self, *args): + elapsed = time.clock() - self.start + msg = "Elapsed time: {} seconds".format(elapsed) + self.file_like.write(msg) + return False diff --git a/Examples/Session10/ICanEatGlass.utf16.txt b/Examples/Suppliments/ICanEatGlass.utf16.txt similarity index 100% rename from Examples/Session10/ICanEatGlass.utf16.txt rename to Examples/Suppliments/ICanEatGlass.utf16.txt diff --git a/Examples/Session10/ICanEatGlass.utf8.txt b/Examples/Suppliments/ICanEatGlass.utf8.txt similarity index 100% rename from Examples/Session10/ICanEatGlass.utf8.txt rename to Examples/Suppliments/ICanEatGlass.utf8.txt diff --git a/Examples/Session10/add_book_data.py b/Examples/Suppliments/add_book_data.py similarity index 100% rename from Examples/Session10/add_book_data.py rename to Examples/Suppliments/add_book_data.py diff --git a/Examples/Session10/add_book_data_flat.py b/Examples/Suppliments/add_book_data_flat.py similarity index 100% rename from Examples/Session10/add_book_data_flat.py rename to Examples/Suppliments/add_book_data_flat.py diff --git a/Examples/Session10/example.cfg b/Examples/Suppliments/example.cfg similarity index 100% rename from Examples/Session10/example.cfg rename to Examples/Suppliments/example.cfg diff --git a/Examples/Session10/hello_unicode.py b/Examples/Suppliments/hello_unicode.py similarity index 100% rename from Examples/Session10/hello_unicode.py rename to Examples/Suppliments/hello_unicode.py diff --git a/Examples/Session10/latin1_test.py b/Examples/Suppliments/latin1_test.py similarity index 100% rename from Examples/Session10/latin1_test.py rename to Examples/Suppliments/latin1_test.py diff --git a/Examples/Session10/text.utf16 b/Examples/Suppliments/text.utf16 similarity index 100% rename from Examples/Session10/text.utf16 rename to Examples/Suppliments/text.utf16 diff --git a/Examples/Session10/text.utf32 b/Examples/Suppliments/text.utf32 similarity index 100% rename from Examples/Session10/text.utf32 rename to Examples/Suppliments/text.utf32 diff --git a/Examples/Session10/text.utf8 b/Examples/Suppliments/text.utf8 similarity index 100% rename from Examples/Session10/text.utf8 rename to Examples/Suppliments/text.utf8 diff --git a/Examples/Session10/unicode_exception_test.py b/Examples/Suppliments/unicode_exception_test.py similarity index 100% rename from Examples/Session10/unicode_exception_test.py rename to Examples/Suppliments/unicode_exception_test.py diff --git a/Examples/Session10/unicodify.py b/Examples/Suppliments/unicodify.py similarity index 100% rename from Examples/Session10/unicodify.py rename to Examples/Suppliments/unicodify.py 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 1d171f87..86a9b6ef 100644 --- a/Syllabus.rst +++ b/Syllabus.rst @@ -15,8 +15,8 @@ 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) +--------------------------------------------------- NOTE: in the spirit of the dynamic nature of Python, this Syllabus (and the class) will be a dynamic document -- evolving as the class progresses. The general structure is fixed, but the details will change to meet the evolving needs of the class. @@ -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,61 +269,62 @@ Iteration, looping and control flow. String methods and formatting -Week 4: Oct 27 +Week 4: October 18 ................ Dictionaries, Sets and Mutability. -Exceptions. - Files and Text Processing -Week 5: November 3 +Week 5: October 25 ........................ -Advanced Argument passing - -Testing +Exceptions List and Dict Comprehensions -Week 6: November 10 -.................... +Week 6: November 1 +.................. -Lambda and Functions as Objects +Testing -Object Oriented Programming: classes, instances, and methods +Advanced Argument passing -Week 7: November 17 -....................... -More OO -- Multiple inheritance, Properties, special methods +**No class Nov 8th for election night** +Week 7: November 15 +................... -Week 8: November 24 -.................... +Object Oriented Programming: -More OO -- Emulating built-in types +classes, instances, methods, inheritance -Iterators and Generators +Week 8: November 22 +................... +More OO: Multiple inheritance, Properties, Special methods. -Week 9: December 1 +Emulating built-in types + + +Week 9: November 29 ................... +Lambda -Decorators +Functions as Objects -Context Managers +Iterators and Generators -Packages and packaging +Week 10: December 6 +................... -Week 10: December 8 -.................... +Decorators -Unicode +Context Managers Wrap Up / Students Code review diff --git a/exercises/circle_class.html b/exercises/circle_class.html deleted file mode 100644 index 341bc5c0..00000000 --- a/exercises/circle_class.html +++ /dev/null @@ -1,438 +0,0 @@ - - - - - - - - - - - Circle Class Excercise — Introduction To Python 1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - -
- -
-
-
-
- -
-

Circle Class Excercise

-
-

Circle Class

-
-

Goal:

-

The goal is to create a class that represents a simple circle.

-

A Circle can be defined by either specifying the radius or the diameter, -and the user can query the circle for either its radius or diameter.

-

Other abilities of a Circle instance:

-
-
    -
  • Compute the circle’s area
  • -
  • Print the circle and get something nice
  • -
  • Be able to add two circles together
  • -
  • Be able to compare two circles to see which is bigger
  • -
  • Be able to compare to see if there are equal
  • -
  • (follows from above) be able to put them in a list and sort them
  • -
-
-

This exercise should use “new style classes” i.e. inherit from object

-

You will also use:

-
-
    -
  • properties
  • -
  • a classmethod
  • -
  • a define a bunch of “special methods”
  • -
-
-
-
-

General Instructions:

-
    -
  1. For each step, write a couple of unit tests that test the new features.
  2. -
  3. Run these tests (and they will fail the first time)
  4. -
  5. Add the code required for your tests to pass.
  6. -
-
-
-

Step 1:

-

create class called Circle – it’s signature should look like:

-
c = Circle(the_radius)
-
-
-

The radius is a required parameter (can’t have a circle without one!)

-

the resulting circle should have a attribute for the radius:

-
c.radius
-
-
-

So you can do:

-
>> c = Circle(4)
->> print c.radius
-4
-
-
-

Remember: tests first!

-
-
-

Step 2:

-

Add a “diameter” property, so the user can get the diameter of the circle:

-
>> c = Circle(4)
->> print c.diameter
-8
-
-
-
-
-

Step 3:

-

Set up the diameter property so that the user can set the diameter of the circle:

-
>> c = Circle(4)
->> c.diameter = 2
->> print c.diameter
-2
->> print c.radius
-1
-
-
-

NOTE that the radius has changed!

-
-
-

Step 4:

-

Add an area property so the user can get the area of the circle:

-
>> c = Circle(2)
->> print c.area
-12.566370
-
-
-

(pi can be found in the math module)

-

The user should not be able to set the area:

-
>> c = Circle(2)
->> c.area = 42
-AttributeError
-
-
-
-
-

Step 5:

-

Add an “alternate constructor” that lets the user create a Circle directly -with the diameter:

-
>> c = Circle.from_diameter(8)
->> print c.diameter
-8
->> print c.radius
-4
-
-
-
-
-

Step 6:

-

Add __str__ and __repr__ methods to your Circle class.

-

Now you can print it:

-
In [2]: c = Circle(4)
-
-In [3]: print c
-Circle with radius: 4.000000
-
-In [4]: repr(c)
-Out[4]: 'Circle(4)'
-
-In [5]: d = eval(repr(c))
-
-In [6]: d
-Out[6]: Circle(4)
-
-
-
-
-

Step 7:

-

Add some of the numeric protocol to your Circle:

-

You should be able to add two circles:

-
In [7]: c1 = Circle(2)
-
-In [8]: c2 = Circle(4)
-
-In [9]: c1 + c2
-Out[9]: Circle(6)
-
-
-

and multiply one times a number:

-
In [16]: c2 * 3
-Out[16]: Circle(12)
-
-
-

(what happens with 3 * c2 ? – can you fix that?)

-
-
-

Step 8:

-

add the ability to compare two circles:

-
In [10]: c1 > c2
-Out[10]: False
-
-In [11]: c1 < c2
-Out[11]: True
-
-In [12]: c1 == c2
-Out[12]: False
-
-In [13]: c3 = Circle(4)
-
-In [14]: c2 == c3
-Out[14]: True
-
-
-

Once the comparing is done, you should be able to sort a list of circles:

-
In [18]: print circles
-[Circle(6), Circle(7), Circle(8), Circle(4), Circle(0), Circle(2), Circle(3), Circle(5), Circle(9), Circle(1)]
-
-In [19]: circl
-circle      circle.py   circle.pyc  circles
-
-In [19]: circles.sort()
-
-In [20]: print circles
-[Circle(0), Circle(1), Circle(2), Circle(3), Circle(4), Circle(5), Circle(6), Circle(7), Circle(8), Circle(9)]
-
-
-

NOTE: make sure to write unit tests for all of this! Ideally before writing the code.

-
-
-

Step 8: Optional Features:

-
    -
  • See if you can make “reflected” numerics do the right thing:
  • -
-
a_circle * 3 == 3 * a_circle
-
-
-
    -
  • What else makes sense: division? others?
  • -
  • Add the “augmented assignment” operators, where they make sense:
  • -
-
a_circle += another_circle
-
-a_circle *= 2
-
-
-
    -
  • look through all the “magic methods” and see what makes sense for circles
  • -
-
-
-
- - -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/exercises/fib_and_lucas.html b/exercises/fib_and_lucas.html deleted file mode 100644 index d2706e3d..00000000 --- a/exercises/fib_and_lucas.html +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - - - - - - Fibonacci Series Exercise — Introduction To Python 1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - -
- -
-
-
-
- -
-

Fibonacci Series Exercise

-
-

Computing the Fibonacci and Lucas Series

-
-

Goal:

-

The Fibonacci Series is a numeric series starting with the integers 0 and 1.

-

In this series, the next integer is determined by summing the previous two.

-

This gives us:

-
0, 1, 1, 2, 3, 5, 8, 13, ...
-
-
-

We will write a function that computes this series – then generalize it.

-
-
-

Step 1

-
    -
  • Create a new module series.py in the session02 folder in your student folder.
      -
    • In it, add a function called fibonacci.
    • -
    • The function should have one parameter n.
    • -
    • The function should return the nth value in the fibonacci series.
    • -
    -
  • -
  • Ensure that your function has a well-formed docstring
  • -
-

Note that the fibinacci series is naturally recusive – the value is -defined by previous values:

-

fib(n) = fib(n-2) + fib(n-1)

-
-
-

Lucas Numbers

-

The Lucas Numbers are a related series of integers that start with the -values 2 and 1 rather than 0 and 1. The resulting series looks like this:

-
2, 1, 3, 4, 7, 11, 18, 29, ...
-
-
-

In your series.py module, add a new function lucas that returns the -nth value in the lucas numbers series.

-

Ensure that your function has a well-formed docstring

-
-
-

Generalizing

-

Both the fibonacci series and the lucas numbers are based on an identical -formula.

-

Add a third function called sum_series with one required parameter and two -optional parameters. The required parameter will determine which element in the -series to print. The two optional parameters will have default values of 0 and -1 and will determine the first two values for the series to be produced.

-

Calling this function with no optional parameters will produce numbers from the -fibonacci series. Calling it with the optional arguments 2 and 1 will -produce values from the lucas numbers. Other values for the optional -parameters will produce other series.

-

Ensure that your function has a well-formed docstring

-
-
-

Tests...

-

Add an if __name__ == "__main__": block to the end of your series.py -module. Use the block to write a series of assert statements that -demonstrate that your three functions work properly.

-

Use comments in this block to inform the observer what your tests do.

-

Add your new module to your git clone and commit frequently while working on -your implementation. Include good commit messages that explain concisely both -what you are doing and why.

-

When you are finished, push your changes to your fork of the class repository -in GitHub and make a pull request.

-
-
-
- - -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/exercises/grid_printer.html b/exercises/grid_printer.html deleted file mode 100644 index 0f9c5f70..00000000 --- a/exercises/grid_printer.html +++ /dev/null @@ -1,341 +0,0 @@ - - - - - - - - - - - Grid Printer Exercise — Introduction To Python 1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - -
- -
-
-
-
- -
-

Grid Printer Exercise

-
-

Printing a Grid

-

(adapted from Downey, “Think Python”, ex. 3.5)

-
-

Goal:

-

Write a function that draws a grid like the following:

-
+ - - - - + - - - - +
-|         |         |
-|         |         |
-|         |         |
-|         |         |
-+ - - - - + - - - - +
-|         |         |
-|         |         |
-|         |         |
-|         |         |
-+ - - - - + - - - - +
-
-
-
-
-

hints

-

A couple features to get you started...

-
-
-

printing

-

To print more than one value on a line, you can pass multiple names into the print function:

-
print('+', '-')
-
-
-

If you don’t want a newline after something is printed, you tell python what you want the print to end with like so:

-
print('+', end=' ')
-print('-')
-
-
-

The output of these statements is '+ -'.

-

(that end parameter defaults to a newline...)

-

A print function with no arguments ends the current line and goes to the next line:

-
print()
-
-
-
-
-

Simple string manipulation:

-

You can put two strings together with the plus operator:

-
In [20]: "this" + "that"
-Out[20]: 'thisthat
-
-
-

Particularly useful if they have been assigned names:

-
In [21]: plus = '+'
-
-In [22]: minus = '-'
-
-In [23]: plus+minus+plus
-Out[23]: '+-+'
-
-
-

Note that you can string any number of operations together in an expression.

-

You can also multiply strings:

-
In [24]: '+' * 10
-Out[24]: '++++++++++'
-
-
-

And combine that with plus in a complex expression:

-
In [29]: first_name = 'Chris'
-
-In [30]: last_name = 'Barker'
-
-In [31]: 5 * '*' + first_name +' ' + last_name + 5 * '*'
-Out[31]: '*****Chris Barker*****'
-
-
-

Note that there are better ways to build up complex strings – we’ll get to that later.

-

Now you’ve got what you need to print that grid...

-
-
-
-

Part 2

-

Making it more general

-
-

Make it a function

-

One of the points of writing functions is so you can write code that does similar things, but customized to input parameters. So what if we want to be able to print that grid at an arbitrary size?

-

Write a function print_grid(n) that takes one integer argument -and prints a grid like the picture above, BUT the size of the -grid is given by the argument.

-

For example, print_grid(11) prints the grid in the above picture.

-

This problem is underspecified. Do something reasonable.

-
-
-
-

Part 3:

-

Even more general...

-
-

A function with two parameters

-

Write a function that draws a similar grid with three rows and three columns.

-

(what to do about rounding?)

-

And while you are at it – n rows and columns...

-
-
-
- - -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/exercises/html_renderer.html b/exercises/html_renderer.html deleted file mode 100644 index 87a7865d..00000000 --- a/exercises/html_renderer.html +++ /dev/null @@ -1,458 +0,0 @@ - - - - - - - - - - - HTML Renderer Exercise — Introduction To Python 1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - -
- -
-
-
-
- -
-

HTML Renderer Exercise

-
-

HTML Renderer

-
-

Goal:

-

The goal is to create a set of classes to render html pages – in a “pretty printed” way. i.e nicely indented and human readable. We’ll try to get to all the features required to render:

-

sample_html.html

-

The exercise is broken down into a number of steps – each requiring a few more OO concepts in Python.

-
-
-

General Instructions:

-

For each step, add the required functionality. There is example code to run your code for each step in: code\session06\run_html_render.py

-

name your file: html_render.py – so it can be imported by run_html_render.py

-

You should be able to run that code at each step, uncommenting each new step in run_html_render.py as you go.

-

It builds up a 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.

-

The html generated at each step is in the files: test_html_ouput?.html

-

At each step, your results should look similar that those (maybe not identical...)

-
-
-

Step 1:

-

Create an Element class for rendering an html element (xml element).

-

It should have class attributes for the tag name (“html” first) and the indentation (spaces to indent for pretty printing)

-

The constructor signature should look like

-
Element(content=None)
-
-
-

where content is a string

-

It should have an append method that can add another string to the content.

-

It should have a render(file_out, ind = "") method that renders the tag and the strings in the content.

-

file_out could be any file-like object ( i.e. have a write() method ).

-

ind is a string with the indentation level in it: the amount that the tag should be indented for pretty printing.

-
-
    -
  • This is a little tricky: ind will be the amount that this element should be indented already. It will be from zero (an empty string) to a lot of spaces, depending on how deep it is in the tree.
  • -
-
-

The amount 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.

-

You should now be able to render an html tag with text in it as contents.

-

See: step 1. in run_html_render.py

-
-
-

Step 2:

-

Create a couple subclasses of Element, for a html, <body>, and <p> tag. All you should have to do is override the tag class attribute (you may need to add a tag class attribute to the Element class first...).

-

Now you can render a few different types of element.

-

Extend the Element.render() method so that it can render other elements inside the tag in addition to strings. Simple recursion should do it. i.e. it can call the render() method of the elements it contains. You’ll need to be smart about setting the ind optional parameter – so that the nested elements get indented correctly.

-

Figure out a way to deal with the fact that the contained elements could be either simple strings or Element s with render methods (there are a few ways to handle that...).

-

You should now be able to render a basic web page with an html tag around -the whole thing, a <body> tag inside, and multiple <p> tags inside that, with text inside that. And all indented nicely.

-

See test_html_output2.html

-

NOTE: when you run step 2 in run_html_render.py, you will want o comment out step 1 – that way you’ll only get one set of output.

-
-
-

Step 3:

-

Create a <head> element – simple subclass.

-

Create a OneLineTag subclass of Element:

-
    -
  • It should override the render method, to render everything on one line – for the simple tags, like:

    -
    <title> PythonClass - Session 6 example </title>
    -
    -
    -
  • -
-

Create a Title subclass of OneLineTag class for the title.

-

You should now be able to render an html doc with a head element, with a -title element in that, and a body element with some <P> elements and some text.

-

See test_html_output3.html

-
-
-

Step 4:

-

Extend the Element class to accept a set of attributes as keywords to the -constructor, ie. (run_html_render.py)

-
Element("some text content", id="TheList", style="line-height:200%")
-
-
-

( remember **kwargs? )

-

The render method will need to be extended to render the attributes properly.

-

You can now render some <p> tags (and others) with attributes

-

See test_html_output4.html

-
-
-

Step 5:

-

Create a SelfClosingTag subclass of Element, to render tags like:

-
<hr /> and <br /> (horizontal rule and line break).
-
-
-

You will need to override the render method to render just the one tag and -attributes, if any.

-

Create a couple subclasses of SelfClosingTag for and <hr /> and <br />

-

See test_html_output5.html

-
-
-

Step 6:

-

Create a A class for an anchor (link) element. Its constructor should look like:

-
A(self, link, content)
-
-
-

where link is the link, and content is what you see. It can be called like so:

-
A(u"http://google.com", u"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 can now add a link to your web page.

-

See test_html_output6.html

-
-
-

Step 7:

-

Create Ul class for an unordered list (really simple subclass of Element)

-

Create Li class for an element in a list (also really simple)

-

Add a list to your web page.

-

Create a Header class – this one should take an integer argument for the -header level. i.e <h1>, <h2>, <h3>, called like

-
H(2, "The text of the header")
-
-
-

for an <h2> header

-

It can subclass from OneLineTag – overriding the __init__, then calling the superclass __init__

-

See test_html_output7.html

-
-
-

Step 8:

-

Update the Html element class to render the “<!DOCTYPE html>” tag at the head of the page, before the html element.

-

You can do this by subclassing Element, overriding render(), but then calling the Element render from the new render.

-

Create a subclass of SelfClosingTag for <meta charset="UTF-8" /> (like for <hr /> and <br /> and add the meta element to the beginning of the head element to give your document an encoding.

-

The doctype and encoding are HTML 5 and you can check this at: http://validator.w3.org.

-

You now have a pretty full-featured html renderer – play with it, add some -new tags, etc....

-

See test_html_output8.html

-
-
-
-

HTML Primer

-

The very least you need to know about html to do this assigment.

-

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.

-

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.

-
-

HTML

-

HTML is “Hyper Text Markup Language”. Hypertext, because it can contain links -to other pages, and markup language means that text is “marked up” with -instructions about how to format the text, etc.

-

Here is a good basic intro:

-

http://www.w3schools.com/html/html_basic.asp

-

And there are countless others online.

-

But here is a tiny intro of just what you need to know for this project.

-
-
-

Elements

-

Modern HTML is a particular dialect of XML (eXrensible 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:

-
<some_tag> some content </some_tag>
-
-
-

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

-
<html> is the core tag indicating the entire document </html>
-
-<p> is a single paragraph of text </p>
-
-<body> is the tag that indicated the text of the document </body>
-
-<head> defines the header of the document -- a place for metadata </head>
-
-
-
-
-

Attributes:

-

In addition to the tag name and the content, extra attributes can be attached to a tag. These are added to the “opening tag”, with name=”something”, another_name=”somethign else” format:

-
<p style="text-align: center; font-style: oblique;">
-
-
-

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?

-
-
-

Special Elements

-

The general structure is everything is between and opening and closing tag. But some elements don’t really have content – just attributes. So the slash goes at the end of the tag, after the attributes. We can call these self-closing tags:

-
<meta charset="UTF-8" />
-
-
-

To make a link, you use an “anchor” tag: <a>. It required attributes to indicate what the link is:

-
<a href="http://google.com">link</a>
-
-
-

the href attribute is the link (hyper reference).

-

To make a bulleted list, you use a <ul> tag (unordered list), and inside that, you put individual list elements <li>:

-
<ul style="line-height:200%" id="TheList">
-    <li>
-        The first item in a list
-    </li>
-    <li style="color: red">
-        This is the second item
-    </li>
-</ul>
-
-
-

Note that the list itself, and the list items can both take various attributes (all tags can...)

-

Section Headers are created with “h” tags: <h1> is the biggest (highest level), and there is <h2>, <h3>, etc. for sections, sub sections, subsub sections.

-
<h2>PythonClass - Class 6 example</h2>
-
-
-

I think that’s all you need to know!

-
-
-
- - -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/exercises/index.html b/exercises/index.html deleted file mode 100644 index f8f23bed..00000000 --- a/exercises/index.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - Homework Materials — Introduction To Python 1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - -
- -
-
- - - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/exercises/kata_fourteen.html b/exercises/kata_fourteen.html deleted file mode 100644 index 0f0ce847..00000000 --- a/exercises/kata_fourteen.html +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - - - - - Kata Fourteen: Tom Swift Under Milk Wood — Introduction To Python 1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - -
- -
-
-
-
- -
-

Kata Fourteen: Tom Swift Under Milk Wood

-

Adapted from Dave Thomas’s work:

-

http://codekata.com/kata/kata14-tom-swift-under-the-milkwood/

-
-

Trigrams

-

Trigrams can be used to mutate text into new, surreal, forms. But what -heuristics do we apply to get a reasonable result?

-
-

The Problem

-

As a boy, one of my treats was go to the shops on a Saturday and spend part -of my allowance on books; for a nine-year old, I had quite a collection of -Tom Swift and Hardy Boys. Wouldn’t it be great to be able to create -more and more of these classic books, to be able to generate a new Tom -Swift adventure on demand?

-

OK, perhaps not. But that won’t stop us trying. I coded up a quick -program to generate some swash-buckling scientific adventure on demand. It -came up with:

-
-

... it was in the wind that was what he thought was his companion. I -think would be a good one and accordingly the ship their situation -improved. Slowly so slowly that it beat the band! You’d think no one -was a low voice. “Don’t take any of the elements and the -inventors of the little Frenchman in the enclosed car or cabin completely -fitted up in front of the gas in the house and wringing her hands. -“I’m sure they’ll fall!”

-

She looked up at them. He dug a mass of black vapor which it had -refused to accept any. As for Mr. Swift as if it goes too high I’ll -warn you and you can and swallow frequently. That will make the airship was -shooting upward again and just before the raid wouldn’t have been -instrumental in capturing the scoundrels right out of jail.”

-
-

Stylistically, it’s Victor Appleton meets Dylan Thomas. Technically, -it’s all done with trigrams.

-

Trigram analysis is very simple. Look at each set of three adjacent words -in a document. Use the first two words of the set as a key, and remember -the fact that the third word followed that key. Once you’ve finished, -you know the list of individual words that can follow each two word -sequence in the document. For example, given the input:

-
I wish I may I wish I might
-
-
-

You might generate:

-
"I wish" => ["I", "I"]
-"wish I" => ["may", "might"]
-"may I"  => ["wish"]
-"I may"  => ["I"]
-
-
-

This says that the words “I wish” are twice followed by the word -“I”, the words “wish I” are followed once by -“may” and once by “might” and so on.

-

To generate new text from this analysis, choose an arbitrary word pair as a -starting point. Use these to look up a random next word (using the table -above) and append this new word to the text so far. This now gives you a -new word pair at the end of the text, so look up a potential next word -based on these. Add this to the list, and so on. In the previous example, -we could start with “I may”. The only possible next word is -“I”, so now we have:

-
I may I
-
-
-

The last two words are “may I”, so the next word is -“wish”. We then look up “I wish”, and find our choice -is constrained to another “I”.:

-
I may I wish I
-
-
-

Now we look up “wish I”, and find we have a choice. Let’s -choose “may”:

-
I may I wish I may
-
-
-

Now we’re back where we started from, with “I may.” -Following the same sequence, but choosing “might” this time, we -get:

-
I may I wish I may I wish I might
-
-
-

At this point we stop, as no sequence starts “I might.”

-

Given a short input text, the algorithm isn’t too interesting. Feed -it a book, however, and you give it more options, so the resulting output -can be surprising.

-

For this kata, try implementing a trigram algorithm that generates a couple -of hundred words of text using a book-sized file as input. -Project Gutenberg is a good source of online -books (Tom Swift and His Airship is here.)

-

Be warned that these files have DOS line endings (carriage return followed by -newline).

-

There is a copy of sherlock holmes right here:

-

sherlock.txt.

-

And a shorter copy for testing:

-

sherlock_small.txt.

-
-
-

Objectives

-

Kata’s are about trying something many times. In this one, what -we’re experimenting with is not just the code, but the heuristics of -processing the text. What do we do with punctuation? Paragraphs? Do we have -to implement backtracking if we chose a next word that turns out to be a -dead end?

-

I’ll fire the signal and the fun will commence...

-
-
-
- - -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/slides_sources/ToDo.txt b/slides_sources/ToDo.txt index 0d9e8636..e51851c8 100644 --- a/slides_sources/ToDo.txt +++ b/slides_sources/ToDo.txt @@ -1,8 +1,15 @@ Things to do for the UWPCE Intro to Python class: +Notes about homework: + +" ".join(dict.keys()) + +no need to make a list first. + +NEED to do more with iterators vs iterables vs sequences. + Future Sessions: -Sorting! add pathlib examples diff --git a/slides_sources/build_gh_pages.sh b/slides_sources/build_gh_pages.sh index a29edd82..6eccd8fb 100755 --- a/slides_sources/build_gh_pages.sh +++ b/slides_sources/build_gh_pages.sh @@ -3,14 +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 --no-edit git push + diff --git a/slides_sources/source/conf.py b/slides_sources/source/conf.py index db0a95c6..ace14544 100644 --- a/slides_sources/source/conf.py +++ b/slides_sources/source/conf.py @@ -35,12 +35,16 @@ 'sphinx.ext.todo', 'sphinx.ext.coverage', # 'sphinx.ext.pngmath', - #'sphinx.ext.mathjax', + '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/circle_class.rst b/slides_sources/source/exercises/circle_class.rst index a8c3edd2..51a3f8ee 100644 --- a/slides_sources/source/exercises/circle_class.rst +++ b/slides_sources/source/exercises/circle_class.rst @@ -26,9 +26,7 @@ Other abilities of a Circle instance: .. nextslide:: -This exercise should use "new style classes" i.e. inherit from ``object`` - -You will also use: +You will use: - properties - a classmethod diff --git a/slides_sources/source/exercises/comprehensions_lab.rst b/slides_sources/source/exercises/comprehensions_lab.rst new file mode 100644 index 00000000..fb9152e5 --- /dev/null +++ b/slides_sources/source/exercises/comprehensions_lab.rst @@ -0,0 +1,250 @@ +.. _exercise_comprehensions: + +****************** +Comprehensions Lab +****************** + +Playing with Comprehensions +============================ + + +.. rst-class:: large left + + Goal: + +.. rst-class:: medium left + + Getting Familiar with list, set and dict comprehensions + + +List comprehensions +-------------------- + +Note: this is a bit of a "backwards" exercise -- +we show you code, you figure out what it does. + +As a result, not much to submit -- don't worry about it -- you'll have +a chance to use these in other exercises. + +.. code-block:: python + + >>> feast = ['lambs', 'sloths', 'orangutans', + 'breakfast cereals', 'fruit bats'] + + >>> comprehension = [delicacy.capitalize() for delicacy in feast] + +What is the output of: + +.. code-block:: python + + >>> comprehension[0] + ??? + + >>> comprehension[2] + ??? + +(figure it out before you try it) + +Filtering lists with list comprehensions +---------------------------------------- + +.. code-block:: python + + >>> feast = ['spam', 'sloths', 'orangutans', 'breakfast cereals', + 'fruit bats'] + + >>> comp = [delicacy for delicacy in feast if len(delicacy) > 6] + +What is the output of: + +.. code-block:: python + + >>> len(feast) + ??? + + >>> len(comp) + ??? + +(figure it out first!) + + +Unpacking tuples in list comprehensions +--------------------------------------- + +.. code-block:: python + + >>> list_of_tuples = [(1, 'lumberjack'), (2, 'inquisition'), (4, 'spam')] + + >>> comprehension = [ skit * number for number, skit in list_of_tuples ] + +What is the output of: + +.. code-block:: python + + >>> comprehension[0] + ??? + + >>> len(comprehension[2]) + ??? + +Double list comprehensions +--------------------------- +.. code-block:: python + + >>> eggs = ['poached egg', 'fried egg'] + + >>> meats = ['lite spam', 'ham spam', 'fried spam'] + + >>> comprehension = \ + [ '{0} and {1}'.format(egg, meat) for egg in eggs for meat in meats] + +What is the output of: + +.. code-block:: python + + >>> len(comprehension) + ??? + + >>> comprehension[0] + ??? + +Set comprehensions +------------------ + +.. code-block:: python + + >>> comprehension = { x for x in 'aabbbcccc'} + +What is the output of: + +.. code-block:: python + + >>> comprehension + ??? + +Dictionary comprehensions +------------------------- + +.. code-block:: python + + >>> dict_of_weapons = {'first': 'fear', + 'second': 'surprise', + 'third':'ruthless efficiency', + 'forth':'fanatical devotion', + 'fifth': None} + >>> dict_comprehension = \ + { k.upper(): weapon for k, weapon in dict_of_weapons.items() if weapon} + +What is the output of: + +.. code-block:: python + + >>> 'first' in dict_comprehension + ??? + >>> 'FIRST' in dict_comprehension + ??? + >>> len(dict_of_weapons) + ??? + >>> len(dict_comprehension) + ??? + +Other resources +--------------- + + +See also: + +https://github.com/gregmalcolm/python_koans + +Specifically (for comprehensions): + +https://github.com/gregmalcolm/python_koans/blob/master/python3/koans/about_comprehension.py + + +Count Even Numbers +------------------ + +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. + +Note: the % "mod" operator computes the remainder, e.g. ``5 % 2`` is 1. + +.. code-block:: python + + count_evens([2, 1, 2, 3, 4]) == 3 + + count_evens([2, 2, 0]) == 3 + + count_evens([1, 3, 5]) == 0 + + +.. code-block:: python + + def count_evens(nums): + one_line_comprehension_here + + +``dict`` and ``set`` comprehensions +------------------------------------ + +Revisiting the dict/set lab -- see how much you can do with +comprehensions instead. + +(:ref:`exercise_dict_lab`) + +Specifically, look at these: + +First a slightly bigger, more interesting (or at least bigger..) dict: + +.. code-block:: python + + food_prefs = {"name": "Chris", + "city": "Seattle", + "cake": "chocolate", + "fruit": "mango", + "salad": "greek", + "pasta": "lasagna"} + +.. nextslide:: Working with this dict: + +1. Print the dict by passing it to a string format method, so that you +get something like: + + "Chris is from Seattle, and he likes chocolate cake, mango fruit, + greek salad, and lasagna pasta" + +2. Using a list comprehension, build a dictionary of numbers from zero +to fifteen and the hexadecimal equivalent (string is fine). +(the ``hex()`` function gives you the hexidecimal representation of a number.) + +3. Do the previous entirely with a dict comprehension -- should be a one-liner + +4. Using the dictionary from item 1: Make a dictionary using the same +keys but with the number of 'a's in each value. You can do this either +by editing the dict in place, or making a new one. If you edit in place, +make a copy first! + +.. nextslide:: + +5. Create sets s2, s3 and s4 that contain numbers from zero through twenty, +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). + + - 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 new file mode 100644 index 00000000..fe4ce49c --- /dev/null +++ b/slides_sources/source/exercises/dict_lab.rst @@ -0,0 +1,89 @@ +.. _exercise_dict_lab: + +********************** +Dictionary and Set Lab +********************** + +Learning about dictionaries and sets +==================================== + +Goal: +----- + +Learn the basic ins and outs of Python dictionaries and sets. + +Procedure +--------- + +In your student dir in the IntroPython2015 repo, create a ``session04`` dir and put in a new ``dict_lab.py`` file. + +The file should be an executable python script. That is to say that one +should be able to run the script directly like so: + +.. code-block:: bash + + $ ./dict_lab.py + +(At least on OS-X and Linux) + +-- you do that with this command: + +.. code-block:: bash + + $ chmod +x dict_lab.py + +(The +x means make this executable) + +.. nextslide:: + +Add the file to your clone of the repository and commit changes frequently +while working on the following tasks. When you are done, push your changes to +GitHub and issue a pull request. + +(if you are struggling with git -- just write the code for now) + +When the script is run, it should accomplish the following four series of +actions: + +.. nextslide:: Dictionaries 1 + +* Create a dictionary containing "name", "city", and "cake" for "Chris" from "Seattle" who likes "Chocolate". + +* Display the dictionary. + +* Delete the entry for "cake". + +* Display the dictionary. + +* Add an entry for "fruit" with "Mango" and display the dictionary. + + - Display the dictionary keys. + - Display the dictionary values. + - Display whether or not "cake" is a key in the dictionary (i.e. False) (now). + - Display whether or not "Mango" is a value in the dictionary (i.e. True). + + +.. nextslide:: Dictionaries 2 + + +* Using the dictionary from item 1: Make a dictionary using the same keys but + with the number of 't's in each value as the value. (upper and lower case?). + +.. nextslide:: Sets + +* Create sets s2, s3 and s4 that contain numbers from zero through twenty, + divisible 2, 3 and 4. + +* Display the sets. + +* Display if s3 is a subset of s2 (False) + +* and if s4 is a subset of s2 (True). + +.. nextslide:: Sets 2 + +* Create a set with the letters in 'Python' and add 'i' to the set. + +* Create a frozenset with the letters in 'marathon' + +* display the union and intersection of the two sets. diff --git a/slides_sources/source/exercises/exceptions_lab.rst b/slides_sources/source/exercises/exceptions_lab.rst new file mode 100644 index 00000000..5ff5b16b --- /dev/null +++ b/slides_sources/source/exercises/exceptions_lab.rst @@ -0,0 +1,25 @@ +.. _exercise_exceptions_lab: + +************** +Exceptions Lab +************** + +Learning Exceptions +=================== + +Just a little bit for the basics. + +Exceptions Lab +--------------- + +Improving ``input`` + +* The ``input()`` function can generate two exceptions: ``EOFError`` + or ``KeyboardInterrupt`` on end-of-file(EOF) or canceled input. + +* Create a wrapper function, perhaps ``safe_input()`` that returns ``None`` + rather rather than raising these exceptions, when the user enters ``^C`` for Keyboard Interrupt, or ``^D`` (``^Z`` on Windows) for End Of File. + +* Update your mailroom program to use exceptions (and IBAFP) to handle + malformed numeric input + 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 63409276..d6f19fe1 100644 --- a/slides_sources/source/exercises/fizz_buzz.rst +++ b/slides_sources/source/exercises/fizz_buzz.rst @@ -17,7 +17,7 @@ The Classic Fizz Buzz Problem (http://c2.com/cgi/wiki?FizzBuzzTest) - Now that I've psyced you out -- it's really pretty straightforward. + Now that I've psyched you out -- it's really pretty straightforward. Goal: ----- @@ -35,11 +35,35 @@ 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: +-------- + +Running your code should result in something like:: + + 1 + 2 + Fizz + 4 + Buzz + Fizz + 7 + 8 + Fizz + Buzz + 11 + Fizz + 13 + 14 + FizzBuzz + 16 + .... + diff --git a/slides_sources/source/exercises/grid_printer.rst b/slides_sources/source/exercises/grid_printer.rst index 42e3ea17..41e43f57 100644 --- a/slides_sources/source/exercises/grid_printer.rst +++ b/slides_sources/source/exercises/grid_printer.rst @@ -122,13 +122,44 @@ Make it a function One of the points of writing functions is so you can write code that does similar things, but customized to input parameters. So what if we want to be able to print that grid at an arbitrary size? Write a function ``print_grid(n)`` that takes one integer argument -and prints a grid like the picture above, BUT the size of the +and prints a grid just like before, BUT the size of the grid is given by the argument. For example, ``print_grid(11)`` prints the grid in the above picture. -This problem is underspecified. Do something reasonable. +``print_grid(3)`` would print a smaller grid:: + + + - + - + + | | | + + - + - + + | | | + + - + - + + +.. nextslide:: + +``print_grid(15)`` prints a larger grid:: + + + - - - - - - - + - - - - - - - + + | | | + | | | + | | | + | | | + | | | + | | | + | | | + + - - - - - - - + - - - - - - - + + | | | + | | | + | | | + | | | + | | | + | | | + | | | + + - - - - - - - + - - - - - - - + + +.. nextslide:: +This problem is underspecified. Do something reasonable. Part 3: ======= @@ -138,8 +169,54 @@ Even more general... A function with two parameters ------------------------------- -Write a function that draws a similar grid with three 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:: + + + - - - - + - - - - + - - - - + + | | | | + | | | | + | | | | + | | | | + + - - - - + - - - - + - - - - + + | | | | + | | | | + | | | | + | | | | + + - - - - + - - - - + - - - - + + | | | | + | | | | + | | | | + | | | | + + - - - - + - - - - + - - - - + + +.. nextslide:: + +What to do about rounding? -- you decide. + +Another example: ``print_grid2(5,3)``:: + + + - - - + - - - + - - - + - - - + - - - + + | | | | | | + | | | | | | + | | | | | | + + - - - + - - - + - - - + - - - + - - - + + | | | | | | + | | | | | | + | | | | | | + + - - - + - - - + - - - + - - - + - - - + + | | | | | | + | | | | | | + | | | | | | + + - - - + - - - + - - - + - - - + - - - + + | | | | | | + | | | | | | + | | | | | | + + - - - + - - - + - - - + - - - + - - - + + | | | | | | + | | | | | | + | | | | | | + + - - - + - - - + - - - + - - - + - - - + + -(what to do about rounding?) -And while you are at it -- n rows and columns... diff --git a/slides_sources/source/exercises/html_renderer.rst b/slides_sources/source/exercises/html_renderer.rst index 8074e47b..d38dc6e0 100644 --- a/slides_sources/source/exercises/html_renderer.rst +++ b/slides_sources/source/exercises/html_renderer.rst @@ -1,38 +1,66 @@ .. _exercise_html_renderer: -======================= +====================== HTML Renderer Exercise -======================= +====================== HTML Renderer ============= +Ever need to generate some HTML? + +And not want to write all those tags yourself? + Goal: ------ -The goal is to create a set of classes to render html pages -- in a "pretty printed" way. i.e nicely indented and human readable. We'll try to get to all the features required to render: +The goal is to create a set of classes to render html pages -- in a "pretty printed" way. + +i.e. nicely indented and human readable. + +We'll try to get to all the features required to render: :download:`sample_html.html <./sample_html.html>` +Take a look at it with "view source" in your browser -- or open in a text editor -- it's also in the Examples dir. + +If you don't know html -- just look at the example and copy that.... + The exercise is broken down into a number of steps -- each requiring a few more OO concepts in Python. General Instructions: --------------------- -For each step, add the required functionality. There is example code to run your code for each step in: ``code\session06\run_html_render.py`` +For each step, add the required functionality. There is example code to run your code for each step in: ``Examples\session07\run_html_render.py`` -name your file: ``html_render.py`` -- so it can be imported by ``run_html_render.py`` +Name your file: ``html_render.py`` -- so it can be imported by ``run_html_render.py`` You should be able to run that code at each step, uncommenting each new step in ``run_html_render.py`` as you go. -It builds up a html tree, and then calls the ``render()`` method of your element to render the page. +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 is in the files: ``test_html_ouput?.html`` +The html generated at each step will be in the files: ``test_html_ouput?.html`` At each step, your results should look similar that those (maybe not identical...) +Unit tests +------------ + +Use "test driven development": + +In addition to checking if the output is what you expect with the running script -- you should also write unit tests as you go. + +Each new line of code should have a test that will run it -- *before* you write that code. + +That is: + + 1. write a test that exercises the next step in your process + 2. run the tests -- the new test will fail + 3. write your code... + 4. run the tests. If it still fails, go back to step 3... + Step 1: ------- @@ -41,29 +69,39 @@ Create an ``Element`` class for rendering an html element (xml element). It should have class attributes for the tag name ("html" first) and the indentation (spaces to indent for pretty printing) -The constructor signature should look like +The initializer signature should look like .. code-block:: python Element(content=None) -where ``content`` is a string +where ``content`` is expected to be a string It should have an ``append`` method that can add another string to the content. +So your class will need a way to store the content in a way that you can keep adding more to it. + +.. nextslide:: + It should have a ``render(file_out, ind = "")`` method that renders the tag and the strings in the content. ``file_out`` could be any file-like object ( i.e. have a ``write()`` method ). -.. nextslide:: - ``ind`` is a string with the indentation level in it: the amount that the tag should be indented for pretty printing. - This is a little tricky: ``ind`` will be the amount that this element should be indented already. It will be from zero (an empty string) to a lot of spaces, depending on how deep it is in the tree. -The amount of indentation should be set by the class attribute: ``indent`` +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:: + +So this ``render()`` method takes a file-like object, and calls its ``write()`` method, writing the html for a tag. Something like:: + + + Some content. Some more content. + <\html> You should now be able to render an html tag with text in it as contents. @@ -72,25 +110,26 @@ See: step 1. in ``run_html_render.py`` Step 2: -------- -Create a couple subclasses of ``Element``, for a ``html``, ````, and ``

`` tag. All you should have to do is override the ``tag`` class attribute (you may need to add a ``tag`` class attribute to the Element class first...). +Create a couple subclasses of ``Element``, for each of ````, ````, and ``

`` tags. All you should have to do is override the ``tag`` class attribute (you may need to add a ``tag`` class attribute to the ``Element`` class first, if you haven't already). Now you can render a few different types of element. -Extend the ``Element.render()`` method so that it can render other elements inside the tag in addition to strings. Simple recursion should do it. i.e. it can call the ``render()`` method of the elements it contains. You'll need to be smart about setting the ``ind`` optional parameter -- so that the nested elements get indented correctly. +Extend the ``Element.render()`` method so that it can render other elements inside the tag in addition to strings. Simple recursion should do it. i.e. it can call the ``render()`` method of the elements it contains. You'll need to be smart about setting the ``ind`` optional parameter -- so that the nested elements get indented correctly. (again, this is a secondary concern...) -Figure out a way to deal with the fact that the contained elements could be either simple strings or ``Element`` s with render methods (there are a few ways to handle that...). +Figure out a way to deal with the fact that the contained elements could be either simple strings or ``Element`` s with render methods (there are a few ways to handle that...). Think about "Duck Typing" and EAFP. See the section 'Notes on handling "duck typing"' and the end of the Exercise for more. -You should now be able to render a basic web page with an html tag around -the whole thing, a ```` tag inside, and multiple ``

`` tags inside that, with text inside that. And all indented nicely. +.. nextslide:: + +You should now be able to render a basic web page with an ```` tag around the whole thing, a ```` tag inside, and multiple ``

`` tags inside that, with text inside that. And all indented nicely. See ``test_html_output2.html`` -NOTE: when you run step 2 in ``run_html_render.py``, you will want o comment out step 1 -- that way you'll only get one set of output. +NOTE: when you run step 2 in ``run_html_render.py``, you will want to comment out step 1 -- that way you'll only get one set of output. Step 3: -------- -Create a ```` element -- simple subclass. +Create a ```` element -- a simple subclass. Create a ``OneLineTag`` subclass of ``Element``: @@ -109,13 +148,13 @@ Step 4: -------- Extend the ``Element`` class to accept a set of attributes as keywords to the -constructor, ie. (``run_html_render.py``) +constructor, e.g. ``run_html_render.py`` .. code-block:: python Element("some text content", id="TheList", style="line-height:200%") -( remember ``**kwargs``? ) +html elements can take essentially any attributes -- so you can't hard-code these particular ones. ( remember ``**kwargs``? ) The render method will need to be extended to render the attributes properly. @@ -123,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: -------- @@ -135,20 +210,24 @@ attributes, if any. 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? And do all your tests still pass (you do have tests for everything, don't you?) after refactoring? + See ``test_html_output5.html`` Step 6: ------- -Create a ``A`` class for an anchor (link) element. Its constructor should look like:: +Create an ``A`` class for an anchor (link) element. Its constructor should look like:: A(self, link, content) -where link is the link, and content is what you see. It can be called like so:: +where ``link`` is the link, and ``content`` is what you see. It can be called like so:: - A(u"http://google.com/", u"link to google") + 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. @@ -192,21 +271,197 @@ 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" +=============================== + +.. rst-class:: left + + In this exercise, we need to deal with the fact that XML (and thus HTML) allows *either* plain text *or* other tags to be the content of a tag. Our code also needs to handle the fact that there are two possible types that we need to be able to render. + + There are two primary ways to address this (and multiple ways to actually write the code for each of these). + + 1) Make sure that the content only has renderable objects in it. + + 2) Make sure the render() method can handle either type on the fly + + The difference is where you handle the multiple types -- in the render method itself, or ahead of time. + +The ahead of time option: +------------------------- + +You can handle it ahead of time by creating a simple object that wraps a string and gives it a render method. As simple as: + +.. code-block:: python + + class TextWrapper: + """ + A simple wrapper that creates a class with a render method + for simple text + """ + def __init__(self, text): + self.text = text + + def render(self, file_out, current_ind=""): + file_out.write(current_ind) + file_out.write(self.text) + +.. nextslide:: + +You could require your users to use the wrapper, so instead of just appending a string, they would do: + +.. code-block:: python + + an_element.append(TextWRapper("the string they want to add")) + +But this is not very Pythonic style -- it's OO heavy. Strings for text are so common you want to be able to simply use them: + +.. code-block:: python + + an_element.append("the string they want to add") + +So much easier. + +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 +------------------------------- + +How do you decide if the wrapper is required? + +**Checking it it's an instance of Element:** + +You could check and see if the object being appended is an Element: + +.. code-block:: python + + if isinstance(content, Element): + self.content.append(content) + else: + self.content.append(TextWrapper(content)) + +This would work well, but closes the door to using any other type that may not be a strict subclsss of Element, but can render itself. Not too bad in this case, but in general, frowned upon in Python. + +.. nextslide:: + +Alternatively, you could check for the string type: + +.. code-block:: python + + if isinstance(content, str): + self.content.append(TextWrapper(content)) + else: + self.content.append(content) + +I think this is a little better -- strings are a pretty core type in python, it's not likely that anyone is going to need to use a "string-like" object. + +Duck Typing +----------- + +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. You can do that with ``hasattr()`` + +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(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. + + +Duck Typing on the Fly +---------------------- + +The other option is to simply put both elements and text in the content list, and figure out what to do in the ``render()`` method. + +Again, you could type check -- but I prefer the duck typing approach, and EAFP: + +.. code-block:: python + + try: + content.render(out_file) + except AttributeError: + outfile.write(content) + +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 directly instead. + +.. nextslide:: + +You may want to turn it into a string, first:: + + outfile.write(str(content)) + +Then you could write just about anything -- numbers, etc. + + +Where did the Exception come from? +---------------------------------- + +**Caution** + +If the object doesn't have a ``render`` method, then an AttributeError will be raised. But what if it does have a render method, but that method is broken? + +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 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 in the unit test it will be clear where it is coming from. + 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. -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. +.. rst-class:: left -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. + 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 understand a little bit about what you trying to do. HTML ---- @@ -221,23 +476,28 @@ http://www.w3schools.com/html/html_basic.asp And there are countless others online. +As html is XML -- the XML intro is a good source of the XML syntax, too: + +http://www.w3schools.com/xml/default.asp + But here is a tiny intro of just what you need to know for this project. Elements -------- -Modern HTML is a particular dialect of XML (eXrensible Markup Language), +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 ---------- @@ -258,28 +518,31 @@ 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? Special Elements ---------------- -The general structure is everything is between and opening and closing tag. But some elements don't really have content -- just attributes. So the slash goes at the end of the tag, after the attributes. We can call these self-closing tags: +The general structure is everything in between the opening and closing tag. But some elements don't really have content -- just attributes. So the slash goes at the end of the tag, after the attributes. We can call these self-closing tags: .. code-block:: html -To make a link, you use an "anchor" tag: ````. It required attributes to indicate what the link is: +To make a link, you use an "anchor" tag: ````. It requires attributes to indicate what the link is: .. code-block:: html - link + link -the ``href`` attribute is the link (hyper reference). +The ``href`` attribute is the link (hyper reference). -To make a bulleted list, you use a