diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..200982db
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+slides_sources/build
+.idea
+.DS_Store
+#ignore compiled files, sublime workspace and project files
+*.pyc
+*junk*
+
+# testing detritus
+.cache
+
+#ignore sublime workspace files
+*.sublime*
+
+# ignore .gitignore, so we can each have our own.
+.gitignore
+
+# 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 fb9602de..4bdb59db 100644
--- a/Examples/Session01/schedule.py
+++ b/Examples/Session01/schedule.py
@@ -1,5 +1,5 @@
"""
-Schedule students for lightning talks, fall 2014
+Schedule students for lightning talks, fall 2015
"""
import random
@@ -8,33 +8,36 @@
# remove the header line
del students[0]
-# clean it up a bit:
+# 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 = [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)
-weeks = range(2,11)
-
-weeks4 = weeks*4
+# make a list from 1 to 10
+weeks = list(range(2, 11))
-schedule = zip(weeks4, students)
+# make three of them...
+weeks = weeks * 4
-schedule.sort()
+# put the students together with the weeks
+schedule = zip(weeks, students)
-outfile = open('schedule.txt', 'w')
+# sort it for output
+schedule = sorted(schedule)
-for week, student in schedule:
- line = 'week %s: %s\n' % (week, student)
- print line,
- outfile.write(line)
-outfile.close()
+# write it to a file (and print to screen)
+with open('schedule.txt', 'w') as outfile:
+ for week, student in schedule:
+ line = 'week {}: {}\n'.format(week, student)
+ print(line)
+ outfile.write(line)
diff --git a/Examples/Session01/students.txt b/Examples/Session01/students.txt
deleted file mode 100644
index bd345d97..00000000
--- a/Examples/Session01/students.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-name: languages
-Albright, Ryan J :
-Ascoli, Louis John :
-Balcarce, Darcy :
-Brand, Ralph P :
-Buer, Eric :
-Claessens, Michel :
-Conde, Ousmane :
-Davis, Bryan L :
-Davis, Ian M :
-Evans, Carolyn J :
-Fischer, Henry B :
-Fries, Lauren :
-Fugelso, David :
-Fukuhara, Wayne R :
-Galvin, Alexander R :
-Gupta, Vinay :
-Hamed, Salim Hassan :
-Hart, Kyle R :
-Hashemloo, Alireza :
-Huynh, Chantal :
-Kazakova, Alexandra N :
-Klock, Andrew P :
-Kramer, Aleksey :
-Lottsfeldt, Erik Ivan :
-Marcos, Danielle G :
-Mier, Benjamin C :
-Nunn, James B :
-Perkins, Robert W :
-Reece, Lesley D :
-Schwafel, Schuyler Alan :
-Simmons, Arielle R :
-Sylvan, Gideon I :
-Westman, Eric W :
-Zhang, Hui :
-Zhu, Changquing :
diff --git a/Examples/Session01/test.py b/Examples/Session01/test.py
index 361f3408..8a557325 100644
--- a/Examples/Session01/test.py
+++ b/Examples/Session01/test.py
@@ -1,5 +1,12 @@
x = 5
-y = 56
+y = 55
-print x, y
+print(x, y)
+
+def f():
+ x = 5
+ return x
+
+def f2():
+ 5 + "5"
diff --git a/Examples/Session02/codingbat.rst b/Examples/Session02/codingbat.rst
index 9f3c5d74..b1dddb52 100644
--- a/Examples/Session02/codingbat.rst
+++ b/Examples/Session02/codingbat.rst
@@ -1,7 +1,8 @@
+
Coding Bat examples
-######################
+####################
-Warmup-1 > monkey_trouble
+Warmup-1 > monkey_trouble
============================
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::
@@ -11,38 +12,38 @@ We have two monkeys, a and b, and the parameters a_smile and b_smile indicate if
monkey_trouble(True, False) → False
-Warmup-1 > sleep_in
+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.
+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.
sleep_in(False, False) → True
sleep_in(True, False) → False
sleep_in(False, True) → True
-Warmup-1 > diff21
-=======================
+Warmup-1 > diff21
+=================
-Given an int n, return the absolute difference between n and 21, except return double the absolute difference if n is over 21.
+Given an int n, return the absolute difference between n and 21, except return double the absolute difference if n is over 21.
diff21(19) → 2
diff21(10) → 11
diff21(21) → 0
-Warmup-1 > makes10
-======================
+Warmup-1 > makes10
+===================
-Given 2 ints, a and b, return True if one if them is 10 or if their sum is 10.
+Given 2 ints, a and b, return True if one if them is 10 or if their sum is 10.
makes10(9, 10) → True
makes10(9, 9) → False
makes10(1, 9) → True
-Logic-1 > cigar_party
+Logic-1 > 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. Return True if the party with the given values is successful, or False otherwise.
+When squirrels get together for a party, they like to have cigars. A squirrel party is successful when the number of cigars is between 40 and 60, inclusive. Unless it is the weekend, in which case there is no upper bound on the number of cigars. Return True if the party with the given values is successful, or False otherwise.
cigar_party(30, False) → False
cigar_party(50, False) → True
diff --git a/Examples/Session02/factorial.py b/Examples/Session02/factorial.py
new file mode 100644
index 00000000..2a069e0e
--- /dev/null
+++ b/Examples/Session02/factorial.py
@@ -0,0 +1,12 @@
+#!/usr/bin python3
+
+"""
+Simple factorial function -- to demostrate recursion
+"""
+
+
+def fact(n):
+ if n == 0:
+ return 1
+ else:
+ return n * fact(n-1)
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/module_reload.py b/Examples/Session03/module_reload.py
new file mode 100644
index 00000000..446f70e2
--- /dev/null
+++ b/Examples/Session03/module_reload.py
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+
+"""
+a really simple module to use to test reloading
+"""
+
+this = "this2"
+that = "that"
+
+def print_something():
+ print "I'm printing something else"
+
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/Session03/test_script.py b/Examples/Session03/test_script.py
new file mode 100644
index 00000000..5d602d4b
--- /dev/null
+++ b/Examples/Session03/test_script.py
@@ -0,0 +1,4 @@
+#!/usr/bin/env python
+
+print "yes, it ran"
+
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/Session04/format_example.py b/Examples/Session04/format_example.py
new file mode 100644
index 00000000..efc1af73
--- /dev/null
+++ b/Examples/Session04/format_example.py
@@ -0,0 +1,7 @@
+def print_me( nums ):
+ formatter = "the first %d numbers are: " + ", ".join( ["%i"] * len(nums) )
+ print "formatter: ", formatter
+ print formatter%(( len(nums), ) + nums)
+
+print_me( (2,3,4,5) )
+
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
new file mode 100644
index 00000000..3971c4eb
--- /dev/null
+++ b/Examples/Session05/codingbat.py
@@ -0,0 +1,13 @@
+#!/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
+
+
+def sleep_in(weekday, vacation):
+ return not (weekday and vacation)
diff --git a/Examples/Session05/test_codingbat.py b/Examples/Session05/test_codingbat.py
new file mode 100755
index 00000000..6681bdc3
--- /dev/null
+++ b/Examples/Session05/test_codingbat.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+"""
+test file for codingbat module
+
+This version can be run with nose or py.test
+"""
+
+from codingbat import 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)
diff --git a/Examples/Session05/test_pytest_parameter.py b/Examples/Session05/test_pytest_parameter.py
new file mode 100644
index 00000000..4e82a3ab
--- /dev/null
+++ b/Examples/Session05/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/Session05/test_random_pytest.py b/Examples/Session05/test_random_pytest.py
new file mode 100644
index 00000000..c798efa9
--- /dev/null
+++ b/Examples/Session05/test_random_pytest.py
@@ -0,0 +1,38 @@
+#!/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() # 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))
+
+
+def test_choice():
+ element = random.choice(seq)
+ assert (element in seq)
+
+
+def test_sample():
+ for element in random.sample(seq, 5):
+ assert element in seq
+
+
+def test_sample_too_large():
+ with pytest.raises(ValueError):
+ random.sample(seq, 20)
diff --git a/Examples/Session05/test_random_unitest.py b/Examples/Session05/test_random_unitest.py
new file mode 100644
index 00000000..f825be5b
--- /dev/null
+++ b/Examples/Session05/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/Session06/cigar_party.py b/Examples/Session06/cigar_party.py
new file mode 100644
index 00000000..992d99bd
--- /dev/null
+++ b/Examples/Session06/cigar_party.py
@@ -0,0 +1,15 @@
+
+"""
+When squirrels get together for a party, they like to have cigars.
+A squirrel party is successful when the number of cigars is between
+40 and 60, inclusive. Unless it is the weekend, in which case there
+is no upper bound on the number of cigars.
+
+Return True if the party with the given values is successful,
+or False otherwise.
+"""
+
+
+def cigar_party(num, weekend):
+ return num >= 40 and (num <= 60 or weekend)
+
diff --git a/Examples/Session06/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/html_render/html_render.py b/Examples/Session06/html_render/html_render.py
deleted file mode 100755
index 20faa272..00000000
--- a/Examples/Session06/html_render/html_render.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env python
-
-"""
-Python class example.
-
-"""
-
-
-# The start of it all:
-# Fill it all in here.
-class Element(object):
- tag = 'html'
- indent = ' '
-
- def __init__(self, content=None):
- if content is not None:
- self.content = [str(content)]
- else:
- self.content = []
-
- def append(self, new_content):
- """ add some new content to the element"""
- self.content.append(new_content)
-
- def render(self, file_out, ind=""):
- """render the content to the given file like object"""
-
- file_out.write( ind+"<"+self.tag+">\n"+ind+self.indent )
- file_out.write( ("\n"+ind+self.indent).join(self.content) )
- file_out.write( "\n"+ind+""+self.tag+">" )
-
-
diff --git a/Examples/Session06/html_render/html_render.pyc b/Examples/Session06/html_render/html_render.pyc
deleted file mode 100644
index 727b7b1e..00000000
Binary files a/Examples/Session06/html_render/html_render.pyc and /dev/null differ
diff --git a/Examples/Session06/html_render/run_html_render.py b/Examples/Session06/html_render/run_html_render.py
deleted file mode 100644
index 5f6e09fa..00000000
--- a/Examples/Session06/html_render/run_html_render.py
+++ /dev/null
@@ -1,225 +0,0 @@
-#!/usr/bin/env python
-
-"""
-a simple script can run and test your html rendering classes.
-
-Uncomment the steps as you add to your rendering.
-
-"""
-from io import open, StringIO
-
-
-# importing the html_rendering code with a short name for easy typing.
-import html_render as hr
-reload(hr)
-
-
-## writing the file out:
-def render(page, filename):
- """
- render the tree of elements
-
- This uses cSstringIO to render to memory, then dump to console and
- write to file -- very handy!
- """
-
- f = StringIO()
- page.render(f, u" ")
-
- f.seek(0)
-
- print f.read()
-
- f.seek(0)
- open(filename, 'w', encoding="utf-8").write( f.read() )
-
-
-## Step 1
-##########
-
-page = hr.Element()
-
-page.append(u"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(u"And here is another piece of text -- you should be able to add any number")
-
-render(page, u"test_html_output1.html")
-
-# ## Step 2
-# ##########
-
-# page = hr.Html()
-
-# body = hr.Body()
-
-# body.append(hr.P(u"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(u"And here is another piece of text -- you should be able to add any number"))
-
-# page.append(body)
-
-# render(page, u"test_html_output2.html")
-
-# # Step 3
-# ##########
-
-# page = hr.Html()
-
-# head = hr.Head()
-# head.append(hr.Title(u"PythonClass = Revision 1087:"))
-
-# page.append(head)
-
-# body = hr.Body()
-
-# body.append(hr.P(u"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(u"And here is another piece of text -- you should be able to add any number"))
-
-# page.append(body)
-
-# render(page, u"test_html_output3.html")
-
-# # Step 4
-# ##########
-
-# page = hr.Html()
-
-# head = hr.Head()
-# head.append(hr.Title(u"PythonClass = Revision 1087:"))
-
-# page.append(head)
-
-# body = hr.Body()
-
-# body.append(hr.P(u"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=u"text-align: center; font-style: oblique;"))
-
-# page.append(body)
-
-# render(page, u"test_html_output4.html")
-
-# # Step 5
-# #########
-
-# page = hr.Html()
-
-# head = hr.Head()
-# head.append(hr.Title(u"PythonClass = Revision 1087:"))
-
-# page.append(head)
-
-# body = hr.Body()
-
-# body.append(hr.P(u"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=u"text-align: center; font-style: oblique;"))
-
-# body.append(hr.Hr())
-
-# page.append(body)
-
-# render(page, u"test_html_output5.html")
-
-# # Step 6
-# #########
-
-# page = hr.Html()
-
-# head = hr.Head()
-# head.append(hr.Title(u"PythonClass = Revision 1087:"))
-
-# page.append(head)
-
-# body = hr.Body()
-
-# body.append(hr.P(u"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=u"text-align: center; font-style: oblique;"))
-
-# body.append(hr.Hr())
-
-# body.append(u"And this is a ")
-# body.append( hr.A(u"http://google.com/", "link") )
-# body.append(u"to google")
-
-# page.append(body)
-
-# render(page, u"test_html_output6.html")
-
-# # Step 7
-# #########
-
-# page = hr.Html()
-
-# head = hr.Head()
-# head.append(hr.Title(u"PythonClass = Revision 1087:"))
-
-# page.append(head)
-
-# body = hr.Body()
-
-# body.append( hr.H(2, u"PythonClass - Class 6 example") )
-
-# body.append(hr.P(u"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=u"text-align: center; font-style: oblique;"))
-
-# body.append(hr.Hr())
-
-# list = hr.Ul(id=u"TheList", style=u"line-height:200%")
-
-# list.append( hr.Li(u"The first item in a list") )
-# list.append( hr.Li(u"This is the second item", style="color: red") )
-
-# item = hr.Li()
-# item.append(u"And this is a ")
-# item.append( hr.A(u"http://google.com/", u"link") )
-# item.append(u"to google")
-
-# list.append(item)
-
-# body.append(list)
-
-# page.append(body)
-
-# render(page, u"test_html_output7.html")
-
-# # Step 8
-# ########
-
-# page = hr.Html()
-
-
-# head = hr.Head()
-# head.append( hr.Meta(charset=u"UTF-8") )
-# head.append(hr.Title(u"PythonClass = Revision 1087:"))
-
-# page.append(head)
-
-# body = hr.Body()
-
-# body.append( hr.H(2, u"PythonClass - Class 6 example") )
-
-# body.append(hr.P(u"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=u"text-align: center; font-style: oblique;"))
-
-# body.append(hr.Hr())
-
-# list = hr.Ul(id=u"TheList", style=u"line-height:200%")
-
-# list.append( hr.Li(u"The first item in a list") )
-# list.append( hr.Li(u"This is the second item", style="color: red") )
-
-# item = hr.Li()
-# item.append(u"And this is a ")
-# item.append( hr.A(u"http://google.com/", "link") )
-# item.append(u"to google")
-
-# list.append(item)
-
-# body.append(list)
-
-# page.append(body)
-
-# render(page, u"test_html_output8.html")
-
-
-
-
diff --git a/Examples/Session06/html_render/test_html_output2.html b/Examples/Session06/html_render/test_html_output2.html
deleted file mode 100644
index 25d5cdc9..00000000
--- a/Examples/Session06/html_render/test_html_output2.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- 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/Session06/html_render/test_html_output3.html b/Examples/Session06/html_render/test_html_output3.html
deleted file mode 100644
index b5b308cc..00000000
--- a/Examples/Session06/html_render/test_html_output3.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- 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/Session06/html_render/test_html_output4.html b/Examples/Session06/html_render/test_html_output4.html
deleted file mode 100644
index 671fee75..00000000
--- a/Examples/Session06/html_render/test_html_output4.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- 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/Session06/html_render/test_html_output5.html b/Examples/Session06/html_render/test_html_output5.html
deleted file mode 100644
index 92d4748d..00000000
--- a/Examples/Session06/html_render/test_html_output5.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- 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/Session06/html_render/test_html_output6.html b/Examples/Session06/html_render/test_html_output6.html
deleted file mode 100644
index 342e88cf..00000000
--- a/Examples/Session06/html_render/test_html_output6.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- 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/Session06/html_render/test_html_output7.html b/Examples/Session06/html_render/test_html_output7.html
deleted file mode 100644
index cac89eaf..00000000
--- a/Examples/Session06/html_render/test_html_output7.html
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
- 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/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
new file mode 100644
index 00000000..80bc0920
--- /dev/null
+++ b/Examples/Session06/test_cigar_party.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+
+"""
+When squirrels get together for a party, they like to have cigars.
+A squirrel party is successful when the number of cigars is between
+40 and 60, inclusive. Unless it is the weekend, in which case there
+is no upper bound on the number of cigars.
+
+Return True if the party with the given values is successful,
+or False otherwise.
+"""
+
+
+# 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():
+ assert cigar_party(30, False) is False
+
+
+def test_2():
+
+ assert cigar_party(50, False) is True
+
+
+def test_3():
+
+ assert cigar_party(70, True) is True
+
+
+def test_4():
+ assert cigar_party(30, True) is False
+
+
+def test_5():
+ assert cigar_party(50, True) is True
+
+
+def test_6():
+ assert cigar_party(60, False) is True
+
+
+def test_7():
+ assert cigar_party(61, False) is False
+
+
+def test_8():
+ assert cigar_party(40, False) is True
+
+
+def test_9():
+ assert cigar_party(39, False) is False
+
+
+def test_10():
+ assert cigar_party(40, True) is True
+
+
+def test_11():
+ assert cigar_party(39, True) is False
+
diff --git a/Examples/Session06/test_codingbat.py b/Examples/Session06/test_codingbat.py
new file mode 100755
index 00000000..354dcb34
--- /dev/null
+++ b/Examples/Session06/test_codingbat.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+"""
+test file for codingbat module
+
+This version can be run with nose or py.test
+"""
+
+from codingbat import sleep_in, monkey_trouble
+
+
+# tests for sleep_in
+def test_false_false():
+ assert sleep_in(False, False)
+
+
+def test_true_false():
+ assert not (sleep_in(True, False))
+
+
+def test_false_true():
+ assert sleep_in(False, True)
+
+
+def test_true_true():
+ assert sleep_in(True, True)
+
+
+# put tests for monkey_trouble here
+# monkey_trouble(True, True) → True
+# monkey_trouble(False, False) → True
+# monkey_trouble(True, False) → False
+
+def test_monkey_true_true():
+ assert monkey_trouble(True, True)
+
+def test_monkey_false_false():
+ assert monkey_trouble(False, False)
+
+def test_monkey_true_false():
+ assert monkey_trouble(True, False) is False
+
+# more!
diff --git a/Examples/Session06/test_pytest_parameter.py b/Examples/Session06/test_pytest_parameter.py
new file mode 100644
index 00000000..4e82a3ab
--- /dev/null
+++ b/Examples/Session06/test_pytest_parameter.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+"""
+pytest example of a parameterized test
+
+NOTE: there is a failure in here! can you fix it?
+
+"""
+import pytest
+
+
+# a (really simple) function to test
+def add(a, b):
+ """
+ returns the sum of a and b
+ """
+ return a + b
+
+# now some test data:
+
+test_data = [((2, 3), 5),
+ ((-3, 2), -1),
+ ((2, 0.5), 2.5),
+ (("this", "that"), "this that"),
+ (([1, 2, 3], [6, 7, 8]), [1, 2, 3, 6, 7, 8]),
+ ]
+
+
+@pytest.mark.parametrize(("input", "result"), test_data)
+def test_add(input, result):
+ assert add(*input) == result
diff --git a/Examples/Session06/test_random_pytest.py b/Examples/Session06/test_random_pytest.py
new file mode 100644
index 00000000..441f239a
--- /dev/null
+++ b/Examples/Session06/test_random_pytest.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+"""
+port of the random unit tests from the python docs to py.test
+"""
+
+import random
+import pytest
+
+
+seq = list(range(10))
+
+
+def test_shuffle():
+ # make sure the shuffled sequence does not lose any elements
+ random.shuffle(seq)
+ # seq.sort() # commenting this out will make it fail, so we can see output
+ print("seq:", seq) # only see output if it fails
+ assert seq == list(range(10))
+
+
+def test_shuffle_immutable():
+ """should get a TypeError with an imutable type """
+ with pytest.raises(TypeError):
+ random.shuffle((1, 2, 3))
+
+
+def test_choice():
+ """make sure a random item selected is in the original sequence"""
+ element = random.choice(seq)
+ assert (element in seq)
+
+
+def test_sample():
+ """make sure all items returned by sample are there"""
+ for element in random.sample(seq, 5):
+ assert element in seq
+
+
+def test_sample_too_large():
+ """should get a ValueError if you try to sample too many"""
+ with pytest.raises(ValueError):
+ random.sample(seq, 20)
diff --git a/Examples/Session06/test_random_unitest.py b/Examples/Session06/test_random_unitest.py
new file mode 100644
index 00000000..f825be5b
--- /dev/null
+++ b/Examples/Session06/test_random_unitest.py
@@ -0,0 +1,30 @@
+import random
+import unittest
+
+
+class TestSequenceFunctions(unittest.TestCase):
+
+ def setUp(self):
+ self.seq = list(range(10))
+
+ def test_shuffle(self):
+ # make sure the shuffled sequence does not lose any elements
+ random.shuffle(self.seq)
+ self.seq.sort()
+ self.assertEqual(self.seq, list(range(10)))
+
+ # should raise an exception for an immutable sequence
+ self.assertRaises(TypeError, random.shuffle, (1, 2, 3))
+
+ def test_choice(self):
+ element = random.choice(self.seq)
+ self.assertTrue(element in self.seq)
+
+ def test_sample(self):
+ with self.assertRaises(ValueError):
+ random.sample(self.seq, 20)
+ for element in random.sample(self.seq, 5):
+ self.assertTrue(element in self.seq)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Examples/Session07/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/Session07/html_render/html_render.py b/Examples/Session07/html_render/html_render.py
new file mode 100755
index 00000000..f46760fd
--- /dev/null
+++ b/Examples/Session07/html_render/html_render.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+"""
+Python class example.
+"""
+
+
+# The start of it all:
+# Fill it all in here.
+class Element(object):
+
+ def __init__(self, content=None):
+ pass
+ def append(self, new_content):
+ pass
+ def render(self, file_out, ind=""):
+ file_out.write("just something as a place holder...")
diff --git a/Examples/Session07/html_render/run_html_render.py b/Examples/Session07/html_render/run_html_render.py
new file mode 100644
index 00000000..d282fdc9
--- /dev/null
+++ b/Examples/Session07/html_render/run_html_render.py
@@ -0,0 +1,235 @@
+#!/usr/bin/env python
+
+"""
+a simple script can run and test your html rendering classes.
+
+Uncomment the steps as you add to your rendering.
+
+"""
+
+from io import StringIO
+
+# importing the html_rendering code with a short name for easy typing.
+import html_render as hr
+# 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:
+def render_page(page, filename):
+ """
+ render the tree of elements
+
+ This uses StringIO to render to memory, then dump to console and
+ write to file -- very handy!
+ """
+
+ f = StringIO()
+ page.render(f, " ")
+
+ f.seek(0)
+
+ print(f.read())
+
+ f.seek(0)
+ open(filename, 'w').write(f.read())
+
+
+# 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("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
+# ##########
+
+# page = hr.Html()
+
+# 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("And here is another piece of text -- you should be able to add any number"))
+
+# page.append(body)
+
+# render_page(page, "test_html_output2.html")
+
+# # Step 3
+# ##########
+
+# page = hr.Html()
+
+# head = hr.Head()
+# head.append(hr.Title("PythonClass = Revision 1087:"))
+
+# page.append(head)
+
+# 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("And here is another piece of text -- you should be able to add any number"))
+
+# page.append(body)
+
+# render_page(page, "test_html_output3.html")
+
+# # Step 4
+# ##########
+
+# page = hr.Html()
+
+# head = hr.Head()
+# head.append(hr.Title("PythonClass = Revision 1087:"))
+
+# page.append(head)
+
+# 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",
+# style="text-align: center; font-style: oblique;"))
+
+# page.append(body)
+
+# render_page(page, "test_html_output4.html")
+
+# # Step 5
+# #########
+
+# page = hr.Html()
+
+# head = hr.Head()
+# head.append(hr.Title("PythonClass = Revision 1087:"))
+
+# page.append(head)
+
+# 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",
+# style="text-align: center; font-style: oblique;"))
+
+# body.append(hr.Hr())
+
+# page.append(body)
+
+# render_page(page, "test_html_output5.html")
+
+# # Step 6
+# #########
+
+# page = hr.Html()
+
+# head = hr.Head()
+# head.append(hr.Title("PythonClass = Revision 1087:"))
+
+# page.append(head)
+
+# 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",
+# style="text-align: center; font-style: oblique;"))
+
+# body.append(hr.Hr())
+
+# body.append("And this is a ")
+# body.append( hr.A("http://google.com/", "link") )
+# body.append("to google")
+
+# page.append(body)
+
+# render_page(page, "test_html_output6.html")
+
+# # Step 7
+# #########
+
+# page = hr.Html()
+
+# head = hr.Head()
+# head.append(hr.Title("PythonClass = Revision 1087:"))
+
+# page.append(head)
+
+# body = hr.Body()
+
+# 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",
+# style="text-align: center; font-style: oblique;"))
+
+# body.append(hr.Hr())
+
+# list = hr.Ul(id="TheList", style="line-height:200%")
+
+# list.append( hr.Li("The first item in a list") )
+# list.append( hr.Li("This is the second item", style="color: red") )
+
+# item = hr.Li()
+# item.append("And this is a ")
+# item.append( hr.A("http://google.com/", "link") )
+# item.append("to google")
+
+# list.append(item)
+
+# body.append(list)
+
+# page.append(body)
+
+# render_page(page, "test_html_output7.html")
+
+# # Step 8
+# ########
+
+# page = hr.Html()
+
+
+# head = hr.Head()
+# head.append( hr.Meta(charset="UTF-8") )
+# head.append(hr.Title("PythonClass = Revision 1087:"))
+
+# page.append(head)
+
+# body = hr.Body()
+
+# 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",
+# style="text-align: center; font-style: oblique;"))
+
+# body.append(hr.Hr())
+
+# list = hr.Ul(id="TheList", style="line-height:200%")
+
+# list.append( hr.Li("The first item in a list") )
+# list.append( hr.Li("This is the second item", style="color: red") )
+
+# item = hr.Li()
+# item.append("And this is a ")
+# item.append( hr.A("http://google.com/", "link") )
+# item.append("to google")
+
+# list.append(item)
+
+# body.append(list)
+
+# page.append(body)
+
+# render_page(page, "test_html_output8.html")
diff --git a/slides_sources/source/homework/sample_html.html b/Examples/Session07/html_render/sample_html.html
similarity index 100%
rename from slides_sources/source/homework/sample_html.html
rename to Examples/Session07/html_render/sample_html.html
diff --git a/Examples/Session06/html_render/test_html_output1.html b/Examples/Session07/html_render/test_html_output1.html
similarity index 99%
rename from Examples/Session06/html_render/test_html_output1.html
rename to Examples/Session07/html_render/test_html_output1.html
index c1ed9a30..65c2d86c 100644
--- a/Examples/Session06/html_render/test_html_output1.html
+++ b/Examples/Session07/html_render/test_html_output1.html
@@ -1,3 +1,4 @@
+
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
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
+
"
+
+
+# #Extra credit:
+
+def test_tag_wrapper():
+ @tag_wrapper('html')
+ def return_a_string(string):
+ return string
+
+ assert return_a_string("this is a string") == " this is a string "
+
+def test_tag_wrapper2():
+ @tag_wrapper('div')
+ def return_a_string(string):
+ return string
+
+ assert return_a_string("this is a string") == "
this is a string
"
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/Suppliments/ICanEatGlass.utf16.txt b/Examples/Suppliments/ICanEatGlass.utf16.txt
new file mode 100644
index 00000000..24a0858d
Binary files /dev/null and b/Examples/Suppliments/ICanEatGlass.utf16.txt differ
diff --git a/Examples/Suppliments/ICanEatGlass.utf8.txt b/Examples/Suppliments/ICanEatGlass.utf8.txt
new file mode 100644
index 00000000..9ecba2b9
--- /dev/null
+++ b/Examples/Suppliments/ICanEatGlass.utf8.txt
@@ -0,0 +1,23 @@
+I Can Eat Glass:
+
+And from the sublime to the ridiculous, here is a certain phrase in an assortment of languages:
+
+Sanskrit: काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम् ॥
+
+Sanskrit (standard transcription): kācaṃ śaknomyattum; nopahinasti mām.
+
+Classical Greek: ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει.
+
+Greek (monotonic): Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.
+
+Greek (polytonic): Μπορῶ νὰ φάω σπασμένα γυαλιὰ χωρὶς νὰ πάθω τίποτα.
+
+Latin: Vitrum edere possum; mihi non nocet.
+
+Old French: Je puis mangier del voirre. Ne me nuit.
+
+French: Je peux manger du verre, ça ne me fait pas mal.
+
+Provençal / Occitan: Pòdi manjar de veire, me nafrariá pas.
+
+Québécois: J'peux manger d'la vitre, ça m'fa pas mal.
\ No newline at end of file
diff --git a/Examples/Suppliments/add_book_data.py b/Examples/Suppliments/add_book_data.py
new file mode 100644
index 00000000..6fa4b5d1
--- /dev/null
+++ b/Examples/Suppliments/add_book_data.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+"""
+sample data for persistence/serializatiion examples
+
+This version is nested, with more stucture
+ - can be saved with pickle, JSON, xml...
+"""
+
+AddressBook = [ {'first_name': "Chris",
+ 'last_name': "Barker",
+ 'address' : {'line_1':"835 NE 33rd St",
+ 'line_2' : "",
+ 'city' : "Seattle",
+ 'state': "WA",
+ 'zip': "96543"},
+ 'email' : "PythonCHB@gmail.com",
+ 'home_phone' : "206-555-1234",
+ 'office_phone' : "123-456-7890",
+ 'cell_phone' : "234-567-8901",
+ },
+
+ {'first_name': "Fred",
+ 'last_name': "Jones",
+ 'address' : {'line_1':"123 SE 13th St",
+ 'line_2' : "Apt. 43",
+ 'city' : "Tacoma",
+ 'state': "WA",
+ 'zip': "93465"},
+ 'email' : "FredJones@some_company.com",
+ 'home_phone' : "510-555-1234",
+ 'office_phone' : "564-466-7990",
+ 'cell_phone' : "403-561-8911",
+ },
+
+ {'first_name': "Nancy",
+ 'last_name': "Wilson",
+ 'address' : {'line_1':"8654 Walnut St",
+ 'line_2' : "Suite 567",
+ 'city' : "Pasadena",
+ 'state': "CA",
+ 'zip': "12345"},
+ 'email' : "Wilson.Nancy@gmail.com",
+ 'home_phone' : "423-321-9876",
+ 'office_phone' : "123-765-9877",
+ 'cell_phone' : "432-567-8466",
+ },
+ ]
+
diff --git a/Examples/Suppliments/add_book_data_flat.py b/Examples/Suppliments/add_book_data_flat.py
new file mode 100644
index 00000000..97a0869d
--- /dev/null
+++ b/Examples/Suppliments/add_book_data_flat.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+"""
+sample data for persistence/serialization examples
+this version is flat for saving in CSV, ini, etc.
+"""
+
+AddressBook = [ {'first_name': "Chris",
+ 'last_name': "Barker",
+ 'address_line_1':"835 NE 33rd St",
+ 'address_line_2' : "",
+ 'address_city' : "Seattle",
+ 'address_state': "WA",
+ 'address_zip': "96543",
+ 'email' : "PythonCHB@gmail.com",
+ 'home_phone' : "206-555-1234",
+ 'office_phone' : "123-456-7890",
+ 'cell_phone' : "234-567-8901",
+ },
+
+ {'first_name': "Fred",
+ 'last_name': "Jones",
+ 'address_line_1':"123 SE 13th St",
+ 'address_line_2' : "Apt. 43",
+ 'address_city' : "Tacoma",
+ 'address_state': "WA",
+ 'address_zip': "93465",
+ 'email' : "FredJones@some_company.com",
+ 'home_phone' : "510-555-1234",
+ 'office_phone' : "564-466-7990",
+ 'cell_phone' : "403-561-8911",
+ },
+
+ {'first_name': "Nancy",
+ 'last_name': "Wilson",
+ 'address_line_1':"8654 Walnut St",
+ 'address_line_2' : "Suite 567",
+ 'address_city' : "Pasadena",
+ 'address_state': "CA",
+ 'address_zip': "12345",
+ 'email' : "Wilson.Nancy@gmail.com",
+ 'home_phone' : "423-321-9876",
+ 'office_phone' : "123-765-9877",
+ 'cell_phone' : "432-567-8466",
+ },
+ ]
+
diff --git a/Examples/Suppliments/example.cfg b/Examples/Suppliments/example.cfg
new file mode 100644
index 00000000..c27f2939
--- /dev/null
+++ b/Examples/Suppliments/example.cfg
@@ -0,0 +1,9 @@
+[Section1]
+int = 15
+bool = true
+float = 3.1415
+
+[Section2]
+int = 32
+bool = False
+float = 1.4235
\ No newline at end of file
diff --git a/Examples/Suppliments/hello_unicode.py b/Examples/Suppliments/hello_unicode.py
new file mode 100644
index 00000000..6bbad1de
--- /dev/null
+++ b/Examples/Suppliments/hello_unicode.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+hello = 'Hello '
+world = u'世界'
+
+print hello + world
+
+print u"It was nice weather today: it reached 80\u00B0"
+
+print u"Maybe it will reach 90\N{degree sign}"
+
+print u"It is extremely rare for it ever to reach 100° in Seattle"
diff --git a/Examples/Suppliments/latin1_test.py b/Examples/Suppliments/latin1_test.py
new file mode 100644
index 00000000..3990078f
--- /dev/null
+++ b/Examples/Suppliments/latin1_test.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+
+"""
+An example of using latin-1 as a universal encoding
+
+latin-1 is a superset of ASCII that is suitable for western european languages.
+
+Is the most common, and a good default, if you need a one-byte per char encoding
+for European text.
+
+It also has a nice property:
+ : every byte value from 0 to 255 is avalid charactor
+
+Thus you will never get an UnicodeDecodeError if
+you try to decode arbitrary bytes with latin-1.
+
+And it can "round-trip" trhough a unicode object.
+
+This can be useful is you don't know the encoding -- at least it won't break.
+It's also useful if you need to work with cobined text+binary data.
+
+
+
+"""
+
+# all the byte values in a bytes (str) object:
+all_bytes = ''.join( [chr(i) for i in range(255)] )
+
+print type(all_bytes)
+print len(all_bytes)
+
+print "Example value: 20"
+print ord(all_bytes[20]) == 20
+print "Example high value: 245"
+print ord(all_bytes[245]) == 245
+
+# now decode it to a unicode object:
+try:
+ uni = all_bytes.decode()
+except UnicodeDecodeError:
+ print "OOPS: can't decode with default encoding"
+
+# latin-1 works:
+try:
+ all_uni = all_bytes.decode('latin-1')
+ print "Yup -- that worked"
+ print all_uni
+ print "note that the ASCII subset is the same..."
+except UnicodeDecodeError:
+ print "OOPS: This should have worked!!"
+ raise
+
+## now show that it round-trips:
+all_bytes2 = all_uni.encode('latin-1')
+
+if all_bytes2 == all_bytes:
+ print "yup -- that worked...the values are preserved on the round trip."
+else:
+ print "Hey, that should have worked"
+
+
+
+
+
+
+
diff --git a/Examples/Suppliments/text.utf16 b/Examples/Suppliments/text.utf16
new file mode 100644
index 00000000..b80b2efc
Binary files /dev/null and b/Examples/Suppliments/text.utf16 differ
diff --git a/Examples/Suppliments/text.utf32 b/Examples/Suppliments/text.utf32
new file mode 100644
index 00000000..c5295310
Binary files /dev/null and b/Examples/Suppliments/text.utf32 differ
diff --git a/Examples/Suppliments/text.utf8 b/Examples/Suppliments/text.utf8
new file mode 100644
index 00000000..9de18890
--- /dev/null
+++ b/Examples/Suppliments/text.utf8
@@ -0,0 +1,17 @@
+Origin (in native language) Name (in native language)
+Հայաստան Արամ Խաչատրյան
+ Australia Nicole Kidman
+ Österreich Johann Strauß
+ Azərbaycan Vaqif Səmədoğlu
+ Азәрбајҹан Вагиф Сәмәдоғлу
+ Azərbaycan Heydər Əliyev
+ Азәрбајҹан Һејдәр Әлијев
+ België René Magritte
+ Belgique René Magritte
+ Belgien René Magritte
+ বাংলা সুকুমার রায়
+ འབྲུག་ཡུལ། མགོན་པོ་རྡོ་རྗེ།
+ ប្រទេសកម្ពុជា ព្រះពុទ្ឋឃោសាចារ្យជួនណាត
+Canada Céline Dion
+ ᓄᓇᕗᒻᒥᐅᑦ ᓱᓴᓐ ᐊᒡᓗᒃᑲᖅ
+
\ No newline at end of file
diff --git a/Examples/Suppliments/unicode_exception_test.py b/Examples/Suppliments/unicode_exception_test.py
new file mode 100755
index 00000000..24666dc2
--- /dev/null
+++ b/Examples/Suppliments/unicode_exception_test.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+
+"""
+example for what happens when you pass non-ascii unicode to a Exception
+"""
+
+#msg = u'This is an ASCII-compatible unicode message'
+
+msg = u'This is an non ASCII\N{EM DASH}compatible unicode message'
+
+print "\nDo you see this message in the Exception report?\n"
+print msg
+print
+
+raise ValueError(msg)
+
diff --git a/Examples/Suppliments/unicodify.py b/Examples/Suppliments/unicodify.py
new file mode 100644
index 00000000..15683ee6
--- /dev/null
+++ b/Examples/Suppliments/unicodify.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+'''
+Decorators to convert all arguments passed to a function or method to
+unicode or str, including default arguments
+
+From: http://axialcorps.com/2014/03/20/unicode-str/
+
+'''
+
+
+import sys
+import functools
+import inspect
+
+def _convert_arg(arg, from_, conv, enc):
+ '''Safely convert unicode to string or string to unicode'''
+ return getattr(arg, conv)(encoding=enc) if isinstance(arg, from_) else arg
+
+def _wrap_convert(from_type, fn, encoding=None):
+ '''Decorate a function converting all str arguments to unicode or
+ vice-versa'''
+ conv = 'decode' if from_type is str else 'encode'
+ encoding = encoding or sys.getdefaultencoding()
+
+ # override string defaults using partial
+ aspec, dflts = inspect.getargspec(fn), {}
+ if aspec.defaults:
+ for k,v in zip(aspec.args[-len(aspec.defaults):],aspec.defaults):
+ dflts[k] = _convert_arg(v, from_type, conv, encoding)
+ fn = functools.partial(fn, **dflts)
+
+ @functools.wraps(fn.func if isinstance(fn, functools.partial) else fn)
+ def converted(*args, **kwargs):
+ args = [_convert_arg(a, from_type, conv, encoding) for a in args]
+ for k,v in kwargs.iteritems():
+ kwargs[k] = _convert_arg(v, from_type, conv, encoding)
+ return fn(*args, **kwargs)
+
+ return converted
+
+def unicodify(fn=None, encoding=None):
+ '''Convert all str arguments to unicode'''
+ if fn is None:
+ return functools.partial(unicodify, encoding=encoding)
+ return _wrap_convert(str, fn, encoding=encoding)
+
+def stringify(fn=None, encoding=None):
+ '''Convert all unicode arguments to str'''
+ if fn is None:
+ return functools.partial(stringify, encoding=encoding)
+ return _wrap_convert(unicode, fn, encoding=encoding)
+
+__all__ = ['unicodify', 'stringify']
\ No newline at end of file
diff --git a/README.rst b/README.rst
index 835744c3..9274ab3e 100644
--- a/README.rst
+++ b/README.rst
@@ -3,7 +3,7 @@ IntroToPython
Introduction to Python: First in the Python Certification series.
-This repository contains the source materials for the first class in the the University of Washington Professional and Continuing Education Program Python Certification Program:
+This repository contains the source materials for the first class in the University of Washington Professional and Continuing Education Program Python Certification Program:
.. _Certificate in Python Programming : http://www.pce.uw.edu/certificates/python-programming.html
diff --git a/Solutions/README.rst b/Solutions/README.rst
deleted file mode 100644
index 77cf496c..00000000
--- a/Solutions/README.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-This is place for example solutions to the assignments for the CodeFellows Foundations II Python class: sept 2014
-
-Solutions will be added to this directory as the course progresses.
-
diff --git a/Students/Lottsfeldt_Erik/Session01/break_me.py b/Students/Lottsfeldt_Erik/Session01/break_me.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/Students/Lottsfeldt_Erik/Session01/monkey_trouble.py b/Students/Lottsfeldt_Erik/Session01/monkey_trouble.py
deleted file mode 100644
index 5c738c29..00000000
--- a/Students/Lottsfeldt_Erik/Session01/monkey_trouble.py
+++ /dev/null
@@ -1,10 +0,0 @@
-def monkey_trouble(a_smile, b_smile):
- if a_smile and b_smile:
- return True
- if not a_smile and not b_smile:
- return True
- return False
- ## The above can be shortened to:
- ## return ((a_smile and b_smile) or (not a_smile and not b_smile))
- ## Or this very short version (think about how this is the same as the above)
- ## return (a_smile == b_smile)
\ No newline at end of file
diff --git a/Students/Lottsfeldt_Erik/Session01/print_grid.py b/Students/Lottsfeldt_Erik/Session01/print_grid.py
deleted file mode 100644
index a451a9c1..00000000
--- a/Students/Lottsfeldt_Erik/Session01/print_grid.py
+++ /dev/null
@@ -1,65 +0,0 @@
-"""
-Chris' solution to the week 1 homework problem.
-
-Note that we hadn't talked about loops yet, so this is a solution with no
-loops.
-
-Note also that there is more than one way to skin a cat -- or code a function
-"""
-def print_grid(size):
-
- """
- print a 2x2 grid with a total size of size
-
- :param size: total size of grid -- it will be rounded if not one more than
- a multiple of 2
- """
-number = 2
- box_size = int((size-1) // 2) # size of one grid box
-print "box_size:", box_size
- # top row
-+ top = ('+ ' + '- ' * box_size) * number + '+' + '\n'
-+ middle = ('| ' + ' ' * 2 * box_size) * number + '|' + '\n'
-+
-+ row = top + middle*box_size
-+
-+ grid = row*number + top
-+
-+ print grid
-+
-+
-+def print_grid2(number, size):
-+ """
-+ print a number x number grid with each box of size width and height
-+
-+ :param number: number of grid boxes (row and column)
-+
-+ :param size: size of each grid box
-+ """
-+ # top row
-+ top = ('+ ' + '- '*size)*number + '+' + '\n'
-+ middle = ('| ' + ' '*2*size)*number + '|' + '\n'
-+
-+ row = top + middle*size
-+
-+ grid = row*number + top
-+
-+ print grid
-
-
-def print_grid3(size):
- """
-same as print_grid, but calling print_grid2 to do the work
-"""
- number = 2
- box_size = (size-1) / 2 # size of one grid box
- print_grid2(number, box_size)
-
-
-print_grid(11)
-print_grid(7)
-
-print_grid2(3, 3)
-print_grid2(3, 5)
-
-print_grid3(11)
\ No newline at end of file
diff --git a/Students/Lottsfeldt_Erik/Session01/sleep_in.py b/Students/Lottsfeldt_Erik/Session01/sleep_in.py
deleted file mode 100644
index f9d66bd9..00000000
--- a/Students/Lottsfeldt_Erik/Session01/sleep_in.py
+++ /dev/null
@@ -1,5 +0,0 @@
-def sleep_in(weekday, vacation):
- if not weekday or vacation:
- return True
- else:
- return False
\ No newline at end of file
diff --git a/Students/Lottsfeldt_Erik/Session01/sum_double.py b/Students/Lottsfeldt_Erik/Session01/sum_double.py
deleted file mode 100644
index d59e033b..00000000
--- a/Students/Lottsfeldt_Erik/Session01/sum_double.py
+++ /dev/null
@@ -1,8 +0,0 @@
-def sum_double(a, b):
- # Store the sum in a local variable
- sum = a + b
-
- # Double it if a and b are the same
- if a == b:
- sum = sum * 2
- return sum
\ No newline at end of file
diff --git a/Students/Lottsfeldt_Erik/Session02/funky_bools.py b/Students/Lottsfeldt_Erik/Session02/funky_bools.py
deleted file mode 100644
index 39c233a4..00000000
--- a/Students/Lottsfeldt_Erik/Session02/funky_bools.py
+++ /dev/null
@@ -1,9 +0,0 @@
-dist = sqrt( (x1-x2)**2 + (y1-y2)**2 )
-
-
-
-x = 3
-y = 2
-
-print (dist)
-
diff --git a/Students/Readme.rst b/Students/Readme.rst
deleted file mode 100644
index aea97a11..00000000
--- a/Students/Readme.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-This is a dir for student's work.
-
-If you want to put your work here for review:
-
-* "fork" this repository in gitHub (make a copy in your own gitHub account)
-* Create a directoy in this directory with your name
-* put your work in that directory in some organised fashion
-* commit those changes to your gitHub repo
-* submit a "pull request"
-
diff --git a/Syllabus.rst b/Syllabus.rst
index e53c7b0d..86a9b6ef 100644
--- a/Syllabus.rst
+++ b/Syllabus.rst
@@ -5,25 +5,32 @@ Syllabus: Introduction to Python
UW Adult and Continuing Education Program
============================================
-Certification in Python Programming
----------------------------------------------------
+Certification in Python Programming: Program Description
+---------------------------------------------------------
-Tuesdays 6-9 pm: Sept 30 - Dec 9, 2014 (10 Sessions)
-.....................................................
+Program ID #5149
+The Python Certificate program is a 9-month curriculum divided into three courses. By the end of the program students will have gained a fundamental understanding of programming in Python by creating a variety of scripts and applications for the Web and for systems development. Python is a versatile programming language, suitable for projects ranging from small scripts to large systems. The certificate program emphasizes best practices such as version control, unit testing and recommended styles and idioms. Students will explore the large standard library of Python 3.0, which supports many common programming tasks.
-NOTE: in the spirit of the dynamic nature of Python, the Syllabus (and the class) will be a dynamic document -- evolving as the class progresses. The general structure is fixed, but the details will change.
+First Course: Introduction to Python
+=====================================
+Tuesdays 6-9 pm: Sept 27 - Dec 6, 2016 (10 Sessions)
+---------------------------------------------------
-Instructor:
-===============
-Christopher Barker, PhD. (``PythonCHB@gmail.com``) is an oceanographer and software developer currently working for NOAA in Seattle. He first began programming over 30 years ago, and has been using programming to solve problems in science and engineering ever since. He has been using Python as his primary language since 1998. Chris gives numerous presentations on his work at professional conferences, and teaches oceanography and oil spill modeling at regular workshops. He has been involved with the Seattle Python Interest Group (www.seapig.org) for many years, and has given a number of talks and tutorials at SEAPIG meetings, as well as the PyCon and Scipy conferences. He is an active participant in a number Python-related open source communities, and has served as a Google Summer of Code mentor for the wxPython project.
+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.
-Python Version:
+
+Learning Goals
===============
-There are two main supported versions of Python: the 2.* series and the 3.* series (py3k). In this class we will be using "cPython" version 2.7, the version distributed by ``_. Each student is expected to have access to a computer with python 2.7 and a decent programmers text editor installed, both during class and for homework assignments. Any modern Operating sytem is fine: OS-X, Linux, or Windows.
+By the end of this course, students will be able to “do something useful with Python”.
+ * Identify/characterize/define a problem
+ * Design a program to solve the problem
+ * Create executable code
+ * Read most Python code
+ * Write basic unit tests
Approach:
=========
@@ -31,31 +38,81 @@ This class assumes a basic knowledge of programming. Thus I will try to emphasiz
One learns programming by doing -- I'll be demonstrating as I talk about concepts, and I will pause frequently to give you a chance to try things out, so plan on having a laptop up and running with python and your text editor of choice during each class.
-Homework:
+We will be using a combination of traditional lectore format at "reverse classroom" approach -- We will generally have reading (or video) assignements that cover a topic, and then in class, we will work through excercises as a group to cement your understanding. We will also be doing frequent "pair programming" -- teaming the students up in pairs to work through excercises together.
+
+Logistics
=========
-There will generally be weekly homework assignments. They will usually be flexible to allow for students' varying time constraints. However, you learn by doing, so I do encourage you to put some time in to the homework. I will review your work if you ask me to, and do a mini code-review of selected assignments during class.
+Location: Puget Sound Plaza, 4th and Union, Seattle
+Dates, times: Tuesday nights, 6 - 9pm; Oct 6 - Dec 8, 2015
+Instructor: Chris Barker, PhD [PythonCHB@gmail.com]
+Course assistant: Maria McKinley [parody@uw.edu]
+Course website: https://github.com/UWPCE-PythonCert/IntroToPython
+
+Instructor:
+===========
+Christopher Barker, PhD. (``PythonCHB@gmail.com``) is an oceanographer and software developer currently working for NOAA in Seattle. He first began programming over 30 years ago, and has been using programming to solve problems in science and engineering ever since. He has been using Python as his primary language since 1998. Chris gives numerous presentations on his work at professional conferences, and teaches oceanography and oil spill modeling at regular workshops. He has been involved with the Seattle Python Interest Group (www.seapig.org) for many years, and has given a number of talks and tutorials at SEAPIG meetings, as well as the PyCon and SciPy conferences. He is an active participant in a number Python-related open source communities, and has served as a Google Summer of Code mentor for the wxPython project.
+
+
+Python Version:
+===============
+
+There are two main supported versions of Python: the 2.* series and the 3.* series (py3k). In this class we will be using "cPython" version 3.5, the version distributed by ``_. Each student is expected to have access to a computer with python 3.5 and a decent programmers text editor installed, both during class and for homework assignments. Any modern Operating sytem is fine: OS-X, Linux, or Windows.
+
+Note that python3 and Python2 have some slightly different syntax and symantics. Much (or most), of the examples you find on the web are in Python2 syntax. We will cover the differences early in class so you will know how to translate.
+
+Assignments And Assessment
+===========================
+
+Homework:
+---------
+There will generally be weekly homework assignments. They will include both reading and video watching and programming excercises. You are not required to turn in the assignments to pass the course, however, we learn by doing, so I do encourage you to put some time in to the homework. I will review your work if you ask me to, and do mini code-reviews of selected assignments during class.
`Teach Yourself Programming in Ten Years `_
-In addition, I will ask each student to identify a small project, ideally related to your work, that you can develop as a class project -- that project will be the primary homework for the last few classes.
+In addition, each student will identify a small project, ideally related to your work, that can be developed as a class project -- that project will be the primary homework for the last few classes.
Lightning Talks:
-----------------
Each student is expected to give one "lightning talk" during the class -- this is a simple 5-minute talk on something related to Python -- totally up to you. We will randomly assign the talks schedule (using Python, of course) during the first class.
+Grading And Attendance
+----------------------
+
+This course is graded pass/fail, based on attendance and completion of projects. Students are required to attend at least 8 of the 10 classes.
+
+Policies And Values
+-------------------
+
+Active learning requires students to participate in the class, as opposed to sitting and listening quietly. In class students will follow the instructor in creating demonstrative examples. Outside of class, students are expected to read the assignments, perform the homework, and post questions (about recent session topics) that they have on the class mailing list before the next class session. Other students are strongly encouraged to answer these questions if possible. Answers to common and unanswered questions will be reviewed in the next class session.
+
+Your feedback on the course and instruction
+-------------------------------------------
+
+After the 3rd class session, we solicit anonymous feedback from all students regarding the pacing and instruction of the course. Students will also be invited to provide comments at the end of the course.
+
+Accomodations
+-------------
+
+The University of Washington is committed to providing access and reasonable accommodation in its services, programs, activities, education and employment for individuals with disabilities. For information or to request disability accommodation contact: Disability Services Office: 206.543.6450/V, 206.543.6452/TTY, 206.685.7264 (FAX), or e-mail at dso@u.washington.edu.
+
+Student Handbook
+-----------------
+
+The student handbook can be found online http://www.pce.uw.edu/resources/certificates/
+
Class format:
==============
Each class will be broken down something like this:
-- 30 minutes talk
-- 25 minutes lab time
+- 20 minutes talk
+- 35 minutes lab time
- 5 minute lightning talk
- 5 minute lightning talk
- 20 minutes talk
-- 30 minutes lab time
+- 35 minutes lab time
- 5 minute lightning talk
- 5 minute lightning talk
@@ -68,73 +125,105 @@ Each class will be broken down something like this:
gitHub:
=======
-All class materials will be up on gitHub (where you probably found this). This allows me to update things at the last minute, and the students can all have easy access to the latest versions. It also familiarizes you with a very useful tool for software development. We'll spend a bit of time during the first class getting everyone up and running with git....
+All class materials will be up on gitHub (where you probably found this). This allows me to update things at the last minute, and the students can all have easy access to the latest versions. It also familiarizes you with a very useful tool for software development.
+
+We will also be using gitHub to communicate during the class -- turn in assignments, post questions, etc.
+
+We'll spend a bit of time during the first couple classes getting everyone up and running with git and gitHub.
https://github.com/UWPCE-PythonCert/IntroToPython
-for rendered and ready to read version:
+for rendered and ready to read version of the class lecture notes:
http://UWPCE-PythonCert.github.io/IntroToPython
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: 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. A few you may want to consider:
+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 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:
References for getting started
-------------------------------
* **The Python Tutorial**
- (https://docs.python.org/2/tutorial/): This is the
+ (https://docs.python.org/3/tutorial/): This is the
official tutorial from the Python website. No more authoritative source is
available.
* **Code Academy Python Track**
(http://www.codecademy.com/tracks/python): Often
cited as a great resource, this site offers an entertaining and engaging
- approach and in-browser work.
+ approach and in-browser work. Python2, as far as I can tell, but most of the lessons will work fine with python3 syntax.
* **Learn Python the Hard Way**
(http://learnpythonthehardway.org/book/): Solid
and gradual. This course offers a great foundation for folks who have never
- programmed in any language before.
+ programmed in any language before. [Python 2]
+
+* **Core Python Programming**
+ (http://corepython.com/): Only available as a dead
+ trees version, but if you like to have book to hold in your hands anyway, this is the best textbook style introduction out there. It starts from the
+ beginning, but gets into the full language. Published in 2009, but still in
+ print, with updated appendixes available for new language features. IN teh thord edtion, "the contents have been cleaned up and retrofitted w/Python 3 examples paired w/their 2.x friends.""
* **Dive Into Python 3**
(http://www.diveinto.org/python3/): The updated version
- of a classic. This book offers an introduction to Python aimed at the student
- who has experience programming in another language.
+ of a classic. This book offers an introduction to Python aimed at the student who has experience programming in another language. Updated for Python 3.
* **Python for You and Me**
(http://pymbook.readthedocs.org/en/latest/): Simple
- and clear. This is a great book for absolute newcomers, or to keep as a quick
- reference as you get used to the language.
+ and clear. This is a great book for absolute newcomers, or to keep as a quick reference as you get used to the language. The latest version is Python 3
* **Think Python**
- (http://greenteapress.com/thinkpython/): Methodical and
- complete. This book offers a very "computer science"-style introduction to
- Python. It is really an intro to Python *in the service of* Computer Science,
- though, so while helpful for the absolute newcomer, it isn't quite as
- "pythonic" as it might be.
-
-* **Core Python Programming**
- (http://corepython.com/): Only available as a dead
- trees version, but if you like to have book to hold in your hands anyway, this
- is the best textbook style introduction out there. It starts from the
- beginning, but gets into the full language. Published in 2009, but still in
- print, with updated appendixes available for new language features.
+ (http://greenteapress.com/thinkpython/): Methodical and complete.
+ This book offers a very "computer science"-style introduction to
+ Python. It is really an intro to Python *in the service of* Computer
+ Science, though, so while helpful for the absolute newcomer, it isn't
+ quite as "pythonic" as it might be.
* **Python 101**
(http://www.blog.pythonlibrary.org/2014/06/03/python-101-book-published-today/)
- Available as a reasonably priced ebook. This is a new one from a popular Blogger
- about Python. Lots of practical examples. Also avaiable as a Kindle book:
+ Available as a reasonably priced ebook. This is a new one from a popular
+ Blogger about Python. Lots of practical examples. Python3, with some references to differences to Python 2. Also avaiable as a Kindle book:
http://www.amazon.com/Python-101-Michael-Driscoll-ebook/dp/B00KQTFHNK
+* **Problem Solving with Algorithms and Data Stuctures**
+
+http://interactivepython.org/runestone/static/pythonds/index.html
+
+* **Python Course**
+
+http://www.python-course.eu/python3_course.php
+
+
+
+References for getting better, once you know the basics
+--------------------------------------------------------
+
* **Python Essential Reference**
(http://www.dabeaz.com/per.html)
The definitive reference for both Python and much of the standard library.
+* **Hitchhikers Guide to Python**
+ (http://docs.python-guide.org/en/latest)
+ Under active development, and still somewhat incomplete, but what is there is good stuff.
+
+* **Writing Idiomatic Python**
+ (https://www.jeffknupp.com/writing-idiomatic-python-ebook)
+ Focused on not just getting the code to work, but how to write it in a really "Pythonic" way.
+
+* **Fluent Python**
+ (http://shop.oreilly.com/product/0636920032519.do)
+ All python3, and focused on getting the advanced details right. Good place to go once you've got the basics down.
+
+* **Python 3 Object Oriented Programming** *
+ https://www.packtpub.com/application-development/python-3-object-oriented-programming
+ Nice book specifically about Object Oriented programming stucture, and how to do it in Python. From local Author and founder of the Puget Sound Programming Python (PuPPy) meetup group, Dusty Phillips.
... and many others
@@ -144,89 +233,99 @@ Class Schedule:
Topics of each week
--------------------
-Week 1: Sept 30
+Week 1: September 27
................
General Introduction to Python and the class. Using the command interpreter and development environment.
-Finding and using the documentation. Getting help. Class github project. Basic data types, functions.
+Kick-off tutorial
+
+Finding and using the documentation. Getting help.
+
+Python 2/3 differences.
-Week 2: Oct 7
+
+Week 2: October 4
................
-More on functions: definition and use, arguments, block structure, scope, recursion
+Introduction to git and gitHub
+
+Basic data types.
+
+Functions: definition and use, arguments, block structure, scope, recursion
Modules and import
Conditionals and Boolean expressions
-Week 3: Oct 14
+Week 3: October 11
.................
Sequences: Strings, Tuples, Lists
-Iteration, Looping and control flow.
+Iteration, looping and control flow.
String methods and formatting
-Week 4: Oct 21
+Week 4: October 18
................
Dictionaries, Sets and Mutability.
-Exceptions.
-
Files and Text Processing
-Week 5: Oct 28
+Week 5: October 25
........................
-Unicode.
-
-Advanced Argument passing
+Exceptions
List and Dict Comprehensions
+Week 6: November 1
+..................
+
Testing
-Week 6: November 4
-....................
+Advanced Argument passing
+
-Lambda and Functional programming.
-Object oriented programming. Classes, instances, and methods
+**No class Nov 8th for election night**
+Week 7: November 15
+...................
+
+Object Oriented Programming:
-Week 7: November 11
-.......................
+classes, instances, methods, inheritance
-More OO -- Inheritance and duck typing
+Week 8: November 22
+...................
+More OO: Multiple inheritance, Properties, Special methods.
-Week 8: November 18
-....................
+Emulating built-in types
-More OO: Special methods
+
+Week 9: November 29
+...................
+Lambda
+
+Functions as Objects
Iterators and Generators
-Week 9: December 2
+Week 10: December 6
...................
Decorators
Context Managers
-Packages and packaging
-
-
-Week 10: December 9
-....................
-
-Persistence / Serialization
+Wrap Up / Students Code review
diff --git a/slides_sources/ToDo.txt b/slides_sources/ToDo.txt
new file mode 100644
index 00000000..e51851c8
--- /dev/null
+++ b/slides_sources/ToDo.txt
@@ -0,0 +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:
+
+
+add pathlib examples
+
diff --git a/slides_sources/build_gh_pages.sh b/slides_sources/build_gh_pages.sh
index f03a5a03..6eccd8fb 100755
--- a/slides_sources/build_gh_pages.sh
+++ b/slides_sources/build_gh_pages.sh
@@ -3,13 +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
+pushd $GHPAGESDIR
git add * # in case there are new files added
-git commit -a
+git commit -a -m "updating presentation materials"
+git pull -s ours --no-edit
git push
+
diff --git a/slides_sources/old_versions/week-03/code/string_formatting_solution.py b/slides_sources/old_versions/week-03/code/string_formatting_solution.py
index 57e6d91a..3a8951ba 100644
--- a/slides_sources/old_versions/week-03/code/string_formatting_solution.py
+++ b/slides_sources/old_versions/week-03/code/string_formatting_solution.py
@@ -10,14 +10,16 @@
# solution 1
# the goal was to demonstrate dynamic building of format strings:
-n = 6
# create the numbers
-numbers = range(1,n+1)
+numbers = [32, 56, 34, 12, 48, 18]
+
# build the format string for the numbers:
-formatter = " %i," * n
+formatter = " %i," * len(numbers)
+
formatter = formatter[:-1] # take the extra comma off the end
+
# put it together with the rest of the string
-formatter = "the first %i numbers are: %s"%(n, formatter)
+formatter = "the first %i numbers are: %s"%(len(numbers), formatter)
# use it:
# the format operator needs a tuple
@@ -28,11 +30,9 @@
# in class, a couple people realized that str() would make a nice string from
# a list or tuple
-n = 7
-numbers = range(1, n+1)
numbers_str = str(numbers)[1:-1] # make a string, remove the brackets
# put it together with the rest of the string
-print "the first %i numbers are: %s"%(n, numbers_str)
+print "the first %i numbers are: %s"%(len(numbers), numbers_str)
#####
# Write a format string that will take:
diff --git a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.pyc b/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.pyc
index 1922e355..c4e9b2d4 100644
Binary files a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.pyc and b/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.pyc differ
diff --git a/slides_sources/requirements.txt b/slides_sources/requirements.txt
index 69243dbf..6f1e540f 100644
--- a/slides_sources/requirements.txt
+++ b/slides_sources/requirements.txt
@@ -1,6 +1,11 @@
-Jinja2==2.7.2
-MarkupSafe==0.19
-Pygments==1.6
-Sphinx==1.2.2
-docutils==0.11
-sphinx-rtd-theme==0.1.6
+Jinja2
+MarkupSafe
+Pygments
+Sphinx
+docutils
+sphinx-rtd-theme
+hieroglyph
+#-e git+https://github.com/nyergler/hieroglyph.git#egg=hieroglyph
+libsass
+ipython
+
diff --git a/slides_sources/scss_sources/slides_custom.scss b/slides_sources/scss_sources/slides_custom.scss
index 2d01f6d7..7691483c 100644
--- a/slides_sources/scss_sources/slides_custom.scss
+++ b/slides_sources/scss_sources/slides_custom.scss
@@ -112,6 +112,17 @@ article {
font-size: inherit;
}
}
+ .figure {
+ text-align: center;
+ a.center {
+ margin: auto;
+ text-decoration: none;
+ border: none;
+ img.center {
+ margin: auto;
+ }
+ }
+ }
dl {
margin-bottom: 10em;
dt {
diff --git a/slides_sources/source/_static/git_another_commit_on_branch.png b/slides_sources/source/_static/git_another_commit_on_branch.png
new file mode 100644
index 00000000..7ef6a068
Binary files /dev/null and b/slides_sources/source/_static/git_another_commit_on_branch.png differ
diff --git a/slides_sources/source/_static/git_checkout_branch.png b/slides_sources/source/_static/git_checkout_branch.png
new file mode 100644
index 00000000..dab12bdc
Binary files /dev/null and b/slides_sources/source/_static/git_checkout_branch.png differ
diff --git a/slides_sources/source/_static/git_checkout_master.png b/slides_sources/source/_static/git_checkout_master.png
new file mode 100644
index 00000000..dc245a7f
Binary files /dev/null and b/slides_sources/source/_static/git_checkout_master.png differ
diff --git a/slides_sources/source/_static/git_commit_on_branch.png b/slides_sources/source/_static/git_commit_on_branch.png
new file mode 100644
index 00000000..23143d7f
Binary files /dev/null and b/slides_sources/source/_static/git_commit_on_branch.png differ
diff --git a/slides_sources/source/_static/git_head.png b/slides_sources/source/_static/git_head.png
new file mode 100644
index 00000000..c48c40e6
Binary files /dev/null and b/slides_sources/source/_static/git_head.png differ
diff --git a/slides_sources/source/_static/git_master_branch.png b/slides_sources/source/_static/git_master_branch.png
new file mode 100644
index 00000000..9c4aeb8a
Binary files /dev/null and b/slides_sources/source/_static/git_master_branch.png differ
diff --git a/slides_sources/source/_static/git_merge_commit.png b/slides_sources/source/_static/git_merge_commit.png
new file mode 100644
index 00000000..2df3d2d3
Binary files /dev/null and b/slides_sources/source/_static/git_merge_commit.png differ
diff --git a/slides_sources/source/_static/git_new_branch.png b/slides_sources/source/_static/git_new_branch.png
new file mode 100644
index 00000000..a0a4ef4c
Binary files /dev/null and b/slides_sources/source/_static/git_new_branch.png differ
diff --git a/slides_sources/source/_static/git_new_commit.png b/slides_sources/source/_static/git_new_commit.png
new file mode 100644
index 00000000..012eb847
Binary files /dev/null and b/slides_sources/source/_static/git_new_commit.png differ
diff --git a/slides_sources/source/_static/git_new_commit_on_master.png b/slides_sources/source/_static/git_new_commit_on_master.png
new file mode 100644
index 00000000..6c25e51a
Binary files /dev/null and b/slides_sources/source/_static/git_new_commit_on_master.png differ
diff --git a/slides_sources/source/_static/git_simple_timeline.png b/slides_sources/source/_static/git_simple_timeline.png
new file mode 100644
index 00000000..465f546c
Binary files /dev/null and b/slides_sources/source/_static/git_simple_timeline.png differ
diff --git a/slides_sources/source/_static/phd101212s.gif b/slides_sources/source/_static/phd101212s.gif
new file mode 100644
index 00000000..721323e9
Binary files /dev/null and b/slides_sources/source/_static/phd101212s.gif differ
diff --git a/slides_sources/source/_static/remotes_clone.png b/slides_sources/source/_static/remotes_clone.png
new file mode 100644
index 00000000..8003dce2
Binary files /dev/null and b/slides_sources/source/_static/remotes_clone.png differ
diff --git a/slides_sources/source/_static/remotes_fork.png b/slides_sources/source/_static/remotes_fork.png
new file mode 100644
index 00000000..e4946961
Binary files /dev/null and b/slides_sources/source/_static/remotes_fork.png differ
diff --git a/slides_sources/source/_static/remotes_start.png b/slides_sources/source/_static/remotes_start.png
new file mode 100644
index 00000000..aa4839d0
Binary files /dev/null and b/slides_sources/source/_static/remotes_start.png differ
diff --git a/slides_sources/source/_static/remotes_upstream.png b/slides_sources/source/_static/remotes_upstream.png
new file mode 100644
index 00000000..de036593
Binary files /dev/null and b/slides_sources/source/_static/remotes_upstream.png differ
diff --git a/slides_sources/source/conf.py b/slides_sources/source/conf.py
index 0050c14d..ace14544 100644
--- a/slides_sources/source/conf.py
+++ b/slides_sources/source/conf.py
@@ -19,12 +19,12 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
+# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@@ -34,12 +34,17 @@
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx.ext.coverage',
- 'sphinx.ext.pngmath',
+ # 'sphinx.ext.pngmath',
+ 'sphinx.ext.mathjax',
+ #'sphinx.ext.jsmath',
'sphinx.ext.ifconfig',
'IPython.sphinxext.ipython_console_highlighting',
'IPython.sphinxext.ipython_directive',
]
+# this doesn't work.
+jsmath_path = "../../../jsMath-3.6e/easy/load.js" # needed for jsmath
+
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -47,7 +52,7 @@
source_suffix = '.rst'
# The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
@@ -67,13 +72,13 @@
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-#language = None
+# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+# today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@@ -81,27 +86,27 @@
# The reST default role (used for this markup: `text`) to use for all
# documents.
-#default_role = None
+# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'colorful'
# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
-#keep_warnings = False
+# keep_warnings = False
# -- Options for HTML output ----------------------------------------------
@@ -113,27 +118,27 @@
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
-#html_theme_options = {}
+# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
-#html_title = None
+# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-#html_favicon = None
+# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -143,48 +148,48 @@
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
-#html_extra_path = []
+# html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
+# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
# If false, no module index is generated.
-#html_domain_indices = True
+# html_domain_indices = True
# If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'IntroToPythonDoc'
@@ -194,13 +199,13 @@
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
+# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
+# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
-#'preamble': '',
+# 'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
@@ -213,23 +218,23 @@
# The name of an image file (relative to this directory) to place at the top of
# the title page.
-#latex_logo = None
+# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
# If true, show page references after internal links.
-#latex_show_pagerefs = False
+# latex_show_pagerefs = False
# If true, show URL addresses after external links.
-#latex_show_urls = False
+# latex_show_urls = False
# Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
# If false, no module index is generated.
-#latex_domain_indices = True
+# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
@@ -242,7 +247,7 @@
]
# If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
@@ -278,6 +283,8 @@
slide_title = "Intro to Python"
slide_theme = 'slides2'
slide_levels = 3
+slide_numbers = False
+
# Place custom static assets in the _static directory and uncomment
# the following lines to include them
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
new file mode 100644
index 00000000..51a3f8ee
--- /dev/null
+++ b/slides_sources/source/exercises/circle_class.rst
@@ -0,0 +1,240 @@
+.. _exercise_circle_class:
+
+======================
+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
+
+.. nextslide::
+
+You will 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. Run these tests (and they will fail the first time)
+
+3. Add the code required for your tests to pass.
+
+
+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:
+
+.. code-block:: python
+
+ >> 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:
+
+.. code-block:: python
+
+ >> 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:
+
+.. code-block:: python
+
+ >> 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:
+
+.. code-block:: python
+
+ >> 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:
+
+.. code-block:: python
+
+ >> c = Circle(2)
+ >> c.area = 42
+ AttributeError
+
+Step 5:
+-------
+
+Add an "alternate constructor" that lets the user create a Circle directly
+with the diameter:
+
+.. code-block:: python
+
+ >> 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:
+
+.. code-block:: ipython
+
+ 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:
+
+.. code-block:: ipython
+
+ In [7]: c1 = Circle(2)
+
+ In [8]: c2 = Circle(4)
+
+ In [9]: c1 + c2
+ Out[9]: Circle(6)
+
+and multiply one times a number:
+
+.. code-block:: ipython
+
+ In [16]: c2 * 3
+ Out[16]: Circle(12)
+
+(what happens with ``3 * c2`` ? -- can you fix that?)
+
+.. nextslide::
+
+Step 8:
+--------
+add the ability to compare two circles:
+
+.. code-block:: ipython
+
+ 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
+
+.. nextslide::
+
+Once the comparing is done, you should be able to sort a list of circles:
+
+.. code-block:: ipython
+
+ 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:
+
+.. code-block:: python
+
+ a_circle * 3 == 3 * a_circle
+
+* What else makes sense: division? others?
+
+* Add the "augmented assignment" operators, where they make sense:
+
+.. code-block:: python
+
+ a_circle += another_circle
+
+ a_circle *= 2
+
+* look through all the "magic methods" and see what makes sense for circles
+
+
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
new file mode 100644
index 00000000..86343f60
--- /dev/null
+++ b/slides_sources/source/exercises/fib_and_lucas.rst
@@ -0,0 +1,101 @@
+.. _exercise_fibonacci:
+
+*************************
+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.
+
+.. _Fibonacci Series: http://en.wikipedia.org/wiki/Fibbonaci_Series
+
+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, ...
+
+.. _Lucas Numbers: http://en.wikipedia.org/wiki/Lucas_number
+
+
+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.
+
+**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...
+--------
+
+Add a block of code 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.
+
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
new file mode 100644
index 00000000..d6f19fe1
--- /dev/null
+++ b/slides_sources/source/exercises/fizz_buzz.rst
@@ -0,0 +1,69 @@
+.. _exercise_fizz_buzz:
+
+******************
+Fizz Buzz Exercise
+******************
+
+The Classic Fizz Buzz Problem
+==============================
+
+.. rst-class:: left
+
+ Fizz Buzz is a classic simple problem in computer science.
+
+ Often used as an exercise in interviews for programmers.
+
+ Apparently a LOT of people applying for jobs as profesional developers can't do this in an interview:
+
+ (http://c2.com/cgi/wiki?FizzBuzzTest)
+
+ Now that I've psyched you out -- it's really pretty straightforward.
+
+Goal:
+-----
+
+* Write a program that prints the numbers from 1 to 100 inclusive.
+
+* But for multiples of three print "Fizz" instead of the number
+
+* For the multiples of five print "Buzz".
+
+* For numbers which are multiples of both three and five print "FizzBuzz" instead.
+
+Hint:
+-----
+
+* Look up the ``%`` operator. What do these do?
+
+ * ``10 % 7``
+ * ``14 % 7``
+
+(try that in iPython)
+
+* **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
new file mode 100644
index 00000000..41e43f57
--- /dev/null
+++ b/slides_sources/source/exercises/grid_printer.rst
@@ -0,0 +1,222 @@
+.. _exercise_grid_printer:
+
+*********************
+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
+-----
+
+.. rst-class:: center medium
+
+ 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:
+
+.. code-block:: python
+
+ 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:
+
+.. code-block:: python
+
+ print('+', end=' ')
+ print('-')
+
+The output of these statements is ``'+ -'``.
+
+(that end parameter defaults to a newline...)
+
+.. nextslide:: no arguments...
+
+A print function with no arguments ends the current line and goes to the next line:
+
+.. code-block:: python
+
+ print()
+
+
+Simple string manipulation:
+---------------------------
+
+You can put two strings together with the plus operator:
+
+.. code-block:: ipython
+
+ In [20]: "this" + "that"
+ Out[20]: 'thisthat
+
+Particularly useful if they have been assigned names:
+
+.. code-block:: ipython
+
+ 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.
+
+.. nextslide:: multiplication of strings
+
+You can also multiply strings:
+
+.. code-block:: ipython
+
+ In [24]: '+' * 10
+ Out[24]: '++++++++++'
+
+And combine that with plus in a complex expression:
+
+.. code-block:: ipython
+
+ 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
+=======
+
+.. rst-class:: center medium
+
+ 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 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.
+
+``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:
+=======
+
+Even more general...
+
+A function with two parameters
+-------------------------------
+
+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)``::
+
+ + - - - + - - - + - - - + - - - + - - - +
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ + - - - + - - - + - - - + - - - + - - - +
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ + - - - + - - - + - - - + - - - + - - - +
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ + - - - + - - - + - - - + - - - + - - - +
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ + - - - + - - - + - - - + - - - + - - - +
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ + - - - + - - - + - - - + - - - + - - - +
+
+
+
diff --git a/slides_sources/source/exercises/html_renderer.rst b/slides_sources/source/exercises/html_renderer.rst
new file mode 100644
index 00000000..d38dc6e0
--- /dev/null
+++ b/slides_sources/source/exercises/html_renderer.rst
@@ -0,0 +1,566 @@
+.. _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:
+
+: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: ``Examples\session07\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 an html tree, and then calls the ``render()`` method of your element to render the page.
+
+It uses a ``StringIO`` object (like a file, but in memory) to render to memory, then dumps it to the console, and writes a file. Take a look at the code at the end to make sure you understand it.
+
+The html generated at each step will be in the files: ``test_html_ouput?.html``
+
+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:
+-------
+
+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 initializer signature should look like
+
+.. code-block:: python
+
+ Element(content=None)
+
+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 ).
+
+``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 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. 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.
+
+See: step 1. in ``run_html_render.py``
+
+Step 2:
+--------
+
+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. (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...). Think about "Duck Typing" and EAFP. See the section 'Notes on handling "duck typing"' and the end of the Exercise for more.
+
+.. 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 to comment out step 1 -- that way you'll only get one set of output.
+
+Step 3:
+--------
+
+Create a ``
`` element -- a 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::
+
+ PythonClass - Session 6 example
+
+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 ``
`` 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, e.g. ``run_html_render.py``
+
+.. code-block:: python
+
+ Element("some text content", id="TheList", style="line-height:200%")
+
+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.
+
+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:
+--------
+
+Create a ``SelfClosingTag`` subclass of Element, to render tags like::
+
+ and (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 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 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::
+
+ 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 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
,
,
, called like
+
+.. code-block:: python
+
+ H(2, "The text of the header")
+
+for an
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 "" 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 ```` (like for ```` and `` `` 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``
+
+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 assignment.
+
+.. rst-class:: left
+
+ 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
+----
+
+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.
+
+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 (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::
+
+ some content
+
+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
+----------
+
+.. code-block:: html
+
+ is the core tag indicating the entire document
+
+
is a single paragraph of text
+
+ is the tag that indicated the text of the document
+
+ defines the header of the document -- a place for metadata
+
+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:
+
+.. 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 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 requires attributes to indicate what the link is:
+
+.. code-block:: html
+
+ link
+
+The ``href`` attribute is the link (hyper reference).
+
+lists
+-----
+
+To make a bulleted list, you use a
tag (unordered list), and inside that, you put individual list items
:
+
+.. code-block:: html
+
+
+
+ The first item in a list
+
+
+ This is the second item
+
+
+
+Note that the list itself *and* the list items can both take various attributes (all tags can...)
+
+Section Headers are created with "h" tags:
is the biggest (highest level), and there is
,
, etc. for sections, sub sections, subsub sections...
+
+.. code-block:: html
+
+
PythonClass - Class 7 example
+
+I think that's all you need to know!
diff --git a/slides_sources/source/exercises/index.rst b/slides_sources/source/exercises/index.rst
new file mode 100644
index 00000000..78ac470e
--- /dev/null
+++ b/slides_sources/source/exercises/index.rst
@@ -0,0 +1,77 @@
+=========
+Exercises
+=========
+
+Contents:
+=========
+
+.. rst-class:: left
+
+
+Session 2:
+----------
+.. toctree::
+ :maxdepth: 1
+
+ grid_printer
+ fizz_buzz
+ fib_and_lucas
+
+Session 3:
+----------
+.. toctree::
+ :maxdepth: 1
+
+ slicing
+ list_lab
+ string_formatting
+ rot13
+ mailroom
+
+Session 4:
+----------
+.. toctree::
+ :maxdepth: 1
+
+ dict_lab
+ file_lab
+ kata_fourteen
+
+Session 5:
+----------
+.. toctree::
+ :maxdepth: 1
+
+ exceptions_lab
+ comprehensions_lab
+
+Session 6:
+----------
+.. toctree::
+ :maxdepth: 1
+
+ args_kwargs_lab
+
+
+Session 7:
+----------
+.. toctree::
+ :maxdepth: 1
+
+ html_renderer
+
+Session 8:
+-----------
+.. toctree::
+ :maxdepth: 1
+
+ circle_class
+ sparse_array
+
+Session 9:
+----------
+.. toctree::
+ :maxdepth: 1
+
+ lambda_magic
+ trapezoid
\ No newline at end of file
diff --git a/slides_sources/source/homework/kata_fourteen.rst b/slides_sources/source/exercises/kata_fourteen.rst
similarity index 94%
rename from slides_sources/source/homework/kata_fourteen.rst
rename to slides_sources/source/exercises/kata_fourteen.rst
index 8bca7be7..b7552bcf 100644
--- a/slides_sources/source/homework/kata_fourteen.rst
+++ b/slides_sources/source/exercises/kata_fourteen.rst
@@ -1,5 +1,8 @@
+.. _exercise_trigrams:
+
+=========================================
Kata Fourteen: Tom Swift Under Milk Wood
-=========================================
+=========================================
Adapted from Dave Thomas's work:
@@ -7,10 +10,15 @@ 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
@@ -34,8 +42,9 @@ came up with:
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."
+ instrumental in capturing the scoundrels right out of jail."
+.. nextslide::
Stylistically, it’s Victor Appleton meets Dylan Thomas. Technically,
it’s all done with trigrams.
@@ -55,6 +64,8 @@ You might generate::
"may I" => ["wish"]
"I may" => ["I"]
+.. nextslide::
+
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.
@@ -75,6 +86,8 @@ is constrained to another "I".::
I may I wish I
+.. nextslide::
+
Now we look up "wish I", and find we have a choice. Let’s
choose "may"::
@@ -88,6 +101,9 @@ get::
At this point we stop, as no sequence starts "I might."
+
+.. nextslide::
+
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.
@@ -100,6 +116,9 @@ books (Tom Swift and His Airship is `here `.
diff --git a/slides_sources/source/exercises/lambda_magic.rst b/slides_sources/source/exercises/lambda_magic.rst
new file mode 100644
index 00000000..edcde112
--- /dev/null
+++ b/slides_sources/source/exercises/lambda_magic.rst
@@ -0,0 +1,61 @@
+.. _exercise_lambda_magic:
+
+************************
+lambda and keyword Magic
+************************
+
+Goals
+=====
+
+.. rst-class:: left
+
+ * A bit of lambda
+ * functions as objects
+ * keyword evaluation
+
+
+Task
+----
+
+Write a function that returns a list of n functions,
+such that each one, when called, will return the input value,
+incremented by an increasing number.
+
+Use a for loop, ``lambda``, and a keyword argument
+
+**Extra credit:**
+
+Do it with a list comprehension, instead of a for loop
+
+Not clear? here's what you should get...
+
+Example calling code
+---------------------
+
+.. code-block:: ipython
+
+ In [96]: the_list = function_builder(4)
+ ### so the_list should contain n functions (callables)
+ In [97]: the_list[0](2)
+ Out[97]: 2
+ ## the zeroth element of the list is a function that add 0
+ ## to the input, hence called with 2, returns 2
+ In [98]: the_list[1](2)
+ Out[98]: 3
+ ## the 1st element of the list is a function that adds 1
+ ## to the input value, thus called with 2, returns 3
+ In [100]: for f in the_list:
+ print(f(5))
+ .....:
+ 5
+ 6
+ 7
+ 8
+ ### If you loop through them all, and call them, each one adds one more
+ to the input, 5... i.e. the nth function in the list adds n to the input.
+
+.. nextslide::
+
+See the test code in Examples/Session09
+
+
diff --git a/slides_sources/source/exercises/list_lab.rst b/slides_sources/source/exercises/list_lab.rst
new file mode 100644
index 00000000..36943bfb
--- /dev/null
+++ b/slides_sources/source/exercises/list_lab.rst
@@ -0,0 +1,113 @@
+.. _exercise_list_lab:
+
+********
+List Lab
+********
+
+Learning about lists
+====================
+
+After:
+
+http://www.upriss.org.uk/python/session5.html
+
+Goal:
+-----
+
+Learn the basic ins and outs of Python lists.
+
+hint
+----
+
+to query the user for info at the command line, you use:
+
+.. code-block:: python
+
+ response = input("a prompt for the user > ")
+
+``response`` will be a string of whatever the user types (until a ).
+
+
+Procedure
+---------
+
+In your student dir in the IntroPython2015 repo, create a ``session03`` dir and put in a new ``list_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
+
+ $ ./list_lab.py
+
+(At least on OS-X and Linux)
+
+-- you do that with this command:
+
+.. code-block:: bash
+
+ $ chmod +x list_lab.py
+
+(The +x means make this executable)
+
+The file will also need this on the first line::
+
+ #!/usr/bin/env python3
+
+This is known as the "she-bang" line -- it tells the shell how to execute that file -- in this case, with ``python3``
+
+NOTE: on Windows, there is a python launcher which, if everything is configured correctly look at that line to know you want python3 if there is more than one python on your system.
+
+.. 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:: Series 1
+
+- Create a list that contains "Apples", "Pears", "Oranges" and "Peaches".
+- Display the list.
+- Ask the user for another fruit and add it to the end of the list.
+- Display the list.
+- Ask the user for a number and display the number back to the user and the
+ fruit corresponding to that number (on a 1-is-first basis).
+- Add another fruit to the beginning of the list using "+" and display the
+ list.
+- Add another fruit to the beginning of the list using insert() and display the list.
+- Display all the fruits that begin with "P", using a for loop.
+
+
+.. nextslide:: Series 2
+
+Using the list created in series 1 above:
+
+- Display the list.
+- Remove the last fruit from the list.
+- Display the list.
+- Ask the user for a fruit to delete and find it and delete it.
+- (Bonus: Multiply the list times two. Keep asking until a match is found. Once found, delete all occurrences.)
+
+.. nextslide:: Series 3
+
+Again, using the list from series 1:
+
+- Ask the user for input displaying a line like "Do you like apples?"
+- for each fruit in the list (making the fruit all lowercase).
+- For each "no", delete that fruit from the list.
+- For any answer that is not "yes" or "no", prompt the user to answer with one
+ of those two values (a while loop is good here):
+- Display the list.
+
+.. nextslide:: Series 4
+
+Once more, using the list from series 1:
+
+- Make a copy of the list and reverse the letters in each fruit in the copy.
+- Delete the last item of the original list. Display the original list and the
+ copy.
diff --git a/slides_sources/source/exercises/mailroom-oo.rst b/slides_sources/source/exercises/mailroom-oo.rst
new file mode 100644
index 00000000..17f0dacb
--- /dev/null
+++ b/slides_sources/source/exercises/mailroom-oo.rst
@@ -0,0 +1,167 @@
+.. _exercise_mailroom_oo:
+
+********
+Mailroom
+********
+
+Making Mailroom Object Oriented
+
+A complete program
+==================
+
+It was quite resonable to build the simple MailRoom program using a
+single module, a simple data structure, and functions that manipulate
+that data structure.
+
+But if one were to expand the program with additional functionality, it
+would start to get a bit unwieldy and hard to maintain.
+
+So it's a pretty good candidate for an object-oriented approach.
+
+Goal:
+-----
+
+Refactor the mailroom program usined a couple classes to help organise the code.
+
+
+
+
+The program
+-----------
+
+Write a small command-line script called ``mailroom.py``. This script should be executable. The script should accomplish the following goals:
+
+* It should have a data structure that holds a list of your donors and a
+ history of the amounts they have donated. This structure should be populated
+ at first with at least five donors, with between 1 and 3 donations each
+
+* The script should prompt the user (you) to choose from a menu of 3 actions:
+ 'Send a Thank You' or 'Create a Report' or 'quit')
+
+Sending a Thank You
+-------------------
+
+* If the user (you) selects 'Send a Thank You', prompt for a Full Name.
+
+ * If the user types 'list', show them a list of the donor names and re-prompt
+ * If the user types a name not in the list, add that name to the data structure and use it.
+ * If the user types a name in the list, use it.
+ * Once a name has been selected, prompt for a donation amount.
+ * Turn the amount into a number -- it is OK at this point for the program to crash if someone types a bogus amount.
+ * Once an amount has been given, add that amount to the donation history of
+ the selected user.
+ * Finally, use string formatting to compose an email thanking the donor for
+ their generous donation. Print the email to the terminal and return to the
+ original prompt.
+
+**It is fine to forget new donors once the script quits running.**
+
+Creating a Report
+------------------
+
+* If the user (you) selected 'Create a Report' print a list of your donors,
+ sorted by total historical donation amount.
+
+ - Include Donor Name, total donated, number of donations and average donation amount as values in each row. You do not need to print out all their donations, just the summary info.
+ - Using string formatting, format the output rows as nicely as possible. The end result should be tabular (values in each column should align with those above and below)
+ - After printing this report, return to the original prompt.
+
+* At any point, the user should be able to quit their current task and return
+ to the original prompt.
+
+* From the original prompt, the user should be able to quit the script cleanly
+
+
+Your report should look something like this::
+
+ Donor Name | Total Given | Num Gifts | Average Gift
+ ------------------------------------------------------------------
+ William Gates, III $ 653784.49 2 $ 326892.24
+ Mark Zuckerberg $ 16396.10 3 $ 5465.37
+ Jeff Bezos $ 877.33 1 $ 877.33
+ Paul Allen $ 708.42 3 $ 236.14
+
+Guidelines
+----------
+
+First, factor your script into separate functions. Each of the above
+tasks can be accomplished by a series of steps. Write discreet functions
+that accomplish individual steps and call them.
+
+Second, use loops to control the logical flow of your program. Interactive
+programs are a classic use-case for the ``while`` loop.
+
+Of course, ``input()`` will be useful here.
+
+Put the functions you write into the script at the top.
+
+Put your main interaction into an ``if __name__ == '__main__'`` block.
+
+Finally, use only functions and the basic Python data types you've learned
+about so far. There is no need to go any farther than that for this assignment.
+
+Submission
+----------
+
+As always, put the new file in your student directory in a ``session03``
+directory, and add it to your clone early. Make frequent commits with
+good, clear messages about what you are doing and why.
+
+When you are done, push your changes and make a pull request.
+
+.. _exercise_mailroom_plus:
+
+Adding dicts...
+---------------
+
+
+For the next week (after Session04)
+
+You should have been able to do all that with the basic data types:
+
+numbers, strings, lists and tuples.
+
+But once you've learned about dictionaries (Session04) you may be able to re-write it a bit more simply and efficiently.
+
+ * Update mailroom from last week to:
+
+ - Use dicts where appropriate
+ - Write a full set of letters to everyone to individual files on disk
+ - See if you can use a dict to switch between the users selections
+ - Try to use a dict and the .format() method to do the letter as one
+ big template -- rather than building up a big string in parts.
+
+Example:
+
+.. code-block:: ipython
+
+ In [3]: d
+ Out[3]: {'first_name': 'Chris', 'last_name': 'Barker'}
+
+
+ In [5]: "My name is {first_name} {last_name}".format(**d)
+ Out[5]: 'My name is Chris Barker'
+
+Don't worry too much about the "**" -- we'll get into the details later, but for now, it means, more or less -- pass this whole dict in as a bunch of keyword arguments.
+
+
+.. _exercise_mailroom_exeptions:
+
+Adding Exceptions
+-----------------
+
+**After Session05:**
+
+* Exceptions:
+
+Now that you've learned about Exception handling, you can update your code to handle errors better -- like when a user inputs bad data.
+
+* Comprehensions:
+
+Can you use comprehensions to clean up your code a bit?
+
+* Tests
+
+Add some tests..
+
+
diff --git a/slides_sources/source/exercises/mailroom.rst b/slides_sources/source/exercises/mailroom.rst
new file mode 100644
index 00000000..656e5c19
--- /dev/null
+++ b/slides_sources/source/exercises/mailroom.rst
@@ -0,0 +1,158 @@
+.. _exercise_mailroom:
+
+********
+Mailroom
+********
+
+A complete program
+==================
+
+Using basic data types and logic for a full program
+
+Goal:
+-----
+
+You work in the mail room at a local charity. Part of your job is to write
+incredibly boring, repetitive emails thanking your donors for their generous
+gifts. You are tired of doing this over an over again, so you've decided to
+let Python help you out of a jam.
+
+The program
+-----------
+
+Write a small command-line script called ``mailroom.py``. This script should be executable. The script should accomplish the following goals:
+
+* It should have a data structure that holds a list of your donors and a
+ history of the amounts they have donated. This structure should be populated
+ at first with at least five donors, with between 1 and 3 donations each
+
+* The script should prompt the user (you) to choose from a menu of 3 actions:
+ 'Send a Thank You' or 'Create a Report' or 'quit')
+
+Sending a Thank You
+-------------------
+
+* If the user (you) selects 'Send a Thank You', prompt for a Full Name.
+
+ * If the user types 'list', show them a list of the donor names and re-prompt
+ * If the user types a name not in the list, add that name to the data structure and use it.
+ * If the user types a name in the list, use it.
+ * Once a name has been selected, prompt for a donation amount.
+ * Turn the amount into a number -- it is OK at this point for the program to crash if someone types a bogus amount.
+ * Once an amount has been given, add that amount to the donation history of
+ the selected user.
+ * Finally, use string formatting to compose an email thanking the donor for
+ their generous donation. Print the email to the terminal and return to the
+ original prompt.
+
+**It is fine to forget new donors once the script quits running.**
+
+Creating a Report
+------------------
+
+* If the user (you) selected 'Create a Report' print a list of your donors,
+ sorted by total historical donation amount.
+
+ - Include Donor Name, total donated, number of donations and average donation amount as values in each row. You do not need to print out all their donations, just the summary info.
+ - Using string formatting, format the output rows as nicely as possible. The end result should be tabular (values in each column should align with those above and below)
+ - After printing this report, return to the original prompt.
+
+* At any point, the user should be able to quit their current task and return
+ to the original prompt.
+
+* From the original prompt, the user should be able to quit the script cleanly
+
+
+Your report should look something like this::
+
+ Donor Name | Total Given | Num Gifts | Average Gift
+ ------------------------------------------------------------------
+ William Gates, III $ 653784.49 2 $ 326892.24
+ Mark Zuckerberg $ 16396.10 3 $ 5465.37
+ Jeff Bezos $ 877.33 1 $ 877.33
+ Paul Allen $ 708.42 3 $ 236.14
+
+Guidelines
+----------
+
+First, factor your script into separate functions. Each of the above
+tasks can be accomplished by a series of steps. Write discreet functions
+that accomplish individual steps and call them.
+
+Second, use loops to control the logical flow of your program. Interactive
+programs are a classic use-case for the ``while`` loop.
+
+Of course, ``input()`` will be useful here.
+
+Put the functions you write into the script at the top.
+
+Put your main interaction into an ``if __name__ == '__main__'`` block.
+
+Finally, use only functions and the basic Python data types you've learned
+about so far. There is no need to go any farther than that for this assignment.
+
+Submission
+----------
+
+As always, put the new file in your student directory in a ``session03``
+directory, and add it to your clone early. Make frequent commits with
+good, clear messages about what you are doing and why.
+
+When you are done, push your changes and make a pull request.
+
+.. _exercise_mailroom_plus:
+
+Adding dicts...
+---------------
+
+
+For the next week (after Session04)
+
+You should have been able to do all that with the basic data types:
+
+numbers, strings, lists and tuples.
+
+But once you've learned about dictionaries (Session04) you may be able to re-write it a bit more simply and efficiently.
+
+ * Update mailroom from last week to:
+
+ - Use dicts where appropriate
+ - Write a full set of letters to everyone to individual files on disk
+ - See if you can use a dict to switch between the users selections
+ - Try to use a dict and the .format() method to do the letter as one
+ big template -- rather than building up a big string in parts.
+
+Example:
+
+.. code-block:: ipython
+
+ In [3]: d
+ Out[3]: {'first_name': 'Chris', 'last_name': 'Barker'}
+
+
+ In [5]: "My name is {first_name} {last_name}".format(**d)
+ Out[5]: 'My name is Chris Barker'
+
+Don't worry too much about the "**" -- we'll get into the details later, but for now, it means, more or less -- pass this whole dict in as a bunch of keyword arguments.
+
+
+.. _exercise_mailroom_exeptions:
+
+Adding Exceptions
+-----------------
+
+**After Session05:**
+
+* Exceptions:
+
+Now that you've learned about Exception handling, you can update your code to handle errors better -- like when a user inputs bad data.
+
+* Comprehensions:
+
+Can you use comprehensions to clean up your code a bit?
+
+* Tests
+
+Add some tests..
+
+
diff --git a/slides_sources/source/exercises/rot13.rst b/slides_sources/source/exercises/rot13.rst
new file mode 100644
index 00000000..0763adf4
--- /dev/null
+++ b/slides_sources/source/exercises/rot13.rst
@@ -0,0 +1,48 @@
+.. _exercise_rot13:
+
+*****
+ROT13
+*****
+
+Goal
+----
+
+Get used to working with the number values for characters
+
+Get a bit of practice with string methods and string processing
+
+
+ROT13 encryption
+-----------------
+
+The ROT13 encryption scheme is a simple substitution cypher where each letter
+in a text is replace by the letter 13 away from it (imagine the alphabet as a
+circle, so it wraps around).
+
+The task
+--------
+
+Add a python module named ``rot13.py`` to the session03 dir in your student dir. This module should provide at least one function called ``rot13`` that takes any amount of text and returns that same text encrypted by ROT13.
+
+This function should preserve whitespace, punctuation and capitalization.
+
+Your module should include an ``if __name__ == '__main__':`` block with tests (asserts) that demonstrate that your ``rot13`` function and any helper functions you add work properly.
+
+
+.. nextslide:: A bit more
+
+There is a "short-cut" available that will help you accomplish this task. Some
+spelunking in `the documentation for strings`_ should help you to find it. If
+you do find it, using it is completely fair game.
+
+As usual, add your new file to your local clone right away. Make commits
+early and often and include commit messages that are descriptive and concise.
+
+When you are done, if you want me to review it, push your changes to github
+and issue a pull request.
+
+try decrypting this:
+
+"Zntargvp sebz bhgfvqr arne pbeare"
+
+.. _the documentation for strings: https://docs.python.org/3/library/stdtypes.html#string-methods
diff --git a/Examples/Session06/html_render/sample_html.py b/slides_sources/source/exercises/sample_html.html
similarity index 100%
rename from Examples/Session06/html_render/sample_html.py
rename to slides_sources/source/exercises/sample_html.html
diff --git a/slides_sources/source/homework/sherlock.txt b/slides_sources/source/exercises/sherlock.txt
similarity index 100%
rename from slides_sources/source/homework/sherlock.txt
rename to slides_sources/source/exercises/sherlock.txt
diff --git a/slides_sources/source/homework/sherlock_small.txt b/slides_sources/source/exercises/sherlock_small.txt
similarity index 98%
rename from slides_sources/source/homework/sherlock_small.txt
rename to slides_sources/source/exercises/sherlock_small.txt
index 992a29b1..dcccaabd 100644
--- a/slides_sources/source/homework/sherlock_small.txt
+++ b/slides_sources/source/exercises/sherlock_small.txt
@@ -14,3 +14,4 @@ own story. He was at work again. He had risen out of his
drug-created dreams and was hot upon the scent of some new
problem. I rang the bell and was shown up to the chamber which
had formerly been in part my own.
+
diff --git a/slides_sources/source/exercises/slicing.rst b/slides_sources/source/exercises/slicing.rst
new file mode 100644
index 00000000..61747eb8
--- /dev/null
+++ b/slides_sources/source/exercises/slicing.rst
@@ -0,0 +1,25 @@
+.. _exercise_slicing:
+
+***********
+Slicing Lab
+***********
+
+Goal
+====
+
+Get the basics of sequence slicing down
+
+Tasks
+-----
+
+Write some functions that:
+
+* return a sequence with the first and last items exchanged.
+* return a sequence with every other item removed
+* return a sequence with the first and last 4 items removed, and every other item in between
+* return a sequence reversed (just with slicing)
+* return a sequence with the middle third, then last third, then the first third in the new order
+
+NOTE:
+these should work with ANY sequence -- but you can use strings to test, if you like.
+
diff --git a/slides_sources/source/exercises/sparse_array.rst b/slides_sources/source/exercises/sparse_array.rst
new file mode 100644
index 00000000..f627c82a
--- /dev/null
+++ b/slides_sources/source/exercises/sparse_array.rst
@@ -0,0 +1,86 @@
+.. _exercise_sparse_array:
+
+======================
+Sparse Array Exercise
+======================
+
+Sparse Array
+============
+
+.. rst-class:: medium
+
+ Goal:
+
+Learn how to emulate a built-in class.
+
+Sparse Array:
+-------------
+
+Oftentimes, at least in computation programming, we have large arrays of data that hold mostly zeros.
+
+These are referred to as "sparse" as the information in them is widely scattered, or sparse.
+
+Since they are mostly zeros, it can be memory and computationally efficient to store only the value that are non-zero.
+
+But you want it to look like a regular array in user code.
+
+In the real world, these are usually 2 dimensional arrays. But to keep it a bit simpler, we'll make a 1 dimensional sparse array in this class.
+
+(feel free to make it 2d for an extra challenge!)
+
+A Sparse array class
+--------------------
+
+A spare array class should present to the user the same interface as a regular list.
+
+Some ideas of how to do that:
+
+* Internally, it can store the values in a dict, with the index as the keys. So that only the indexes with non-zero values will be stored.
+
+* It should take a sequence of values as an initializer:
+
+.. code-block:: python
+
+ sa = SparseArray([1,2,0,0,0,0,3,0,0,4])
+
+* you should be able to tell how long it is:
+
+.. code-block:: python
+
+ len(my_array)
+
+ This will give its "virtual" length -- with the zeros
+
+.. nextslide::
+
+* It should support getting and setting particular elements via indexing:
+
+.. code-block:: python
+
+ sa[5] = 12
+ sa[3] = 0 # the zero won't get stored!
+ val = sa[13] # it should get a zero if not set
+
+* It should support deleting an element by index:
+
+.. code-block:: python
+
+ del sa[4]
+
+* It should raise an ``IndexError`` if you try to access an index beyond the end.
+
+* it should have an append() method
+
+.. nextslide::
+
+* Can you make it support slicing?
+
+* How else can you make it like a list?
+
+.. code-block:: ipython
+
+ In [10]: my_array = SparseArray( (1,0,0,0,2,0,0,0,5) )
+ In [11]: my_array[4]
+ Out[11]: 2
+ In [12]: my_array[2]
+ Out[12]: 0
diff --git a/slides_sources/source/exercises/string_formatting.rst b/slides_sources/source/exercises/string_formatting.rst
new file mode 100644
index 00000000..f01556d9
--- /dev/null
+++ b/slides_sources/source/exercises/string_formatting.rst
@@ -0,0 +1,111 @@
+.. _exercise_string_formatting:
+
+*********************
+String Formatting Lab
+*********************
+
+Building up strings
+===================
+
+.. rst-class:: left
+
+For reference:
+
+The official reference docs:
+
+https://docs.python.org/3/library/string.html#string-formatting
+
+And a more human-readable intro:
+
+https://pyformat.info/
+
+And a nice "Cookbook":
+
+https://mkaz.tech/python-string-format.html
+
+
+A Couple Exercises
+------------------
+
+* Write a format string that will take:
+
+ ``( 2, 123.4567, 10000)``
+
+ and produce:
+
+ ``'file_002 : 123.46, 1.00e+04'``
+
+**Note:** the idea behind the "file_002" is that if you have a bunch of files that you want to name with numbers that can be sorted, you need to "pad" the numbers with zeros to get the right sort order.
+
+.. nextslide::
+
+For example:
+
+.. code-block:: ipython
+
+ In [10]: fnames = ['file1', 'file2', 'file10', 'file11']
+ In [11]: fnames.sort()
+ In [12]: fnames
+ Out[12]: ['file1', 'file10', 'file11', 'file2']
+
+That is probably not what you want. However:
+
+.. code-block:: ipython
+
+ In [1]: fnames = ['file001', 'file002', 'file010', 'file011']
+ In [3]: sorted(fnames)
+ Out[3]: ['file001', 'file002', 'file010', 'file011']
+
+That works!
+
+So you want to find a string formatting operator that will "pad" the number with zeros for you.
+
+Dynamically Building up format strings
+--------------------------------------
+
+* Rewrite:
+
+``"the 3 numbers are: {:d}, {:d}, {:d}".format(1,2,3)``
+
+to take an arbitrary number of values.
+
+Trick: You can pass in a tuple of values to a function with a ``*``:
+
+.. code-block:: ipython
+
+ In [52]: t = (1,2,3)
+
+ In [53]: "the 3 numbers are: {:d}, {:d}, {:d}".format(*t)
+ Out[53]: 'the 3 numbers are: 1, 2, 3'
+
+.. nextslide::
+
+The idea here is that you may have a tuple of three numbers, but might also have 4 or 5 or....
+
+So you can dynamically build up the format string to accommodate the length of the tuple.
+
+The string object has the ``format()`` method, so you can call it with a string that is bound to a name, not just a string literal. For example:
+
+.. code-block:: ipython
+
+ In [16]: fstring = "{:d}, {:d}"
+
+ In [17]: nums = (34, 56)
+
+ In [18]: fstring.format(*nums)
+ Out[18]: '34, 56'
+
+So how would you make an fstring that was the right length for an arbitrary tuple?
+
+.. nextslide::
+
+Put your code in a function that will return the formatted string like so:
+
+.. code-block:: ipython
+
+ In [20]: formatter((2,3,5))
+ Out[20]: 'the 3 numbers are: 2, 3, 5'
+
+ In [21]: formatter((2,3,5,7,9))
+ Out[21]: 'the 5 numbers are: 2, 3, 5, 7, 9'
+
diff --git a/slides_sources/source/exercises/trapezoid.rst b/slides_sources/source/exercises/trapezoid.rst
new file mode 100644
index 00000000..bf6c97ef
--- /dev/null
+++ b/slides_sources/source/exercises/trapezoid.rst
@@ -0,0 +1,295 @@
+.. _exercise_trapezoidal_rule:
+
+*****************
+Trapezoidal Rule
+*****************
+
+Passing functions around
+=========================
+
+
+.. rst-class:: medium left
+
+ Goal:
+
+.. rst-class:: left
+
+ Making use of functions as objects -- functions that act on functions.
+
+
+Trapezoidal rule
+----------------
+
+The "trapezoidal rule":
+
+https://en.wikipedia.org/wiki/Trapezoidal_rule
+
+Is one of the easiest "quadrature" methods.
+
+Otherwise known as computing a definite integral, or, simply,
+
+Computing the area under a curve.
+
+The task
+--------
+
+Your task is to write a ``trapz()`` function that will compute the area under an arbitrary function, using the trapezoidal rule.
+
+The function will take another function as an argument, as well as the start and end points to compute, and return the area under the curve.
+
+Example:
+--------
+
+.. code-block:: python
+
+ def line(x):
+ '''a very simple straight horizontal line at y = 5'''
+ return 5
+
+ area = trapz(line, 0, 10)
+
+ area
+ 50
+
+About the simplest "curve" you can have is a horizontal straight line, in this case, at y = 5. The area under that line from 0 to 10 is a rectangle that is 10 wide and 5 high, so with an area of 50.
+
+Of course in this case, it's easiest to simply multiply the height times the width, but we want a function that will work for **Any** curve.
+
+HINT: this simple example could be a good test case!
+
+The Solution:
+-------------
+
+Your function definition should look like:
+
+.. code-block:: python
+
+ def trapz(fun, a, b):
+ """
+ Compute the area under the curve defined by
+ y = fun(x), for x between a and b
+
+ :param fun: the function to evaluate
+ :type fun: a function that takes a single parameter
+
+ :param a: the start point for teh integration
+ :type a: a numeric value
+
+ :param b: the end point for the integration
+ :type b: a numeric value
+ """
+ pass
+
+.. nextslide::
+
+In the function, you want to compute the following equation:
+
+.. math::
+
+ area = \frac{b-a}{2N}(f(x_0) + 2f(x_1) + 2f(x_2) + \dotsb + 2f(x_{N-1}) + f(x_N))
+
+So you will need to:
+
+ - create a list of x values from a to b (maybe 100 or so values to start)
+
+ - compute the function for each of those values and double them
+
+ - add them all up
+
+ - multiply by the half of the difference between a and b divided by the number of steps.
+
+.. nextslide::
+
+Note that the first and last values are not doubled, so it may be more efficient to rearrange it like this:
+
+.. math::
+
+ area = \frac{b-a}{N} \left( \frac{f(x_0) + f(x_{N})}{2} + \sum_{i=1}^{N-1} f(x_i) \right)
+
+Can you use comprehensions for this?
+
+NOTE: ``range()`` only works for integers -- how can you deal with that?
+
+.. nextslide::
+
+Once you have that, it should work for any function that can be evaluated between a and b.
+
+Try it for some built-in math functions, like ``math.sin``
+
+tests
+-----
+
+Do this using test-drive development.
+
+A few examples of analytical solutions you can use for tests:
+
+A simple horizontal line -- see above.
+
+.. nextslide::
+
+A sloped straight line:
+
+.. math::
+
+ \int_a^b y = mx + B = \frac{1}{2} m (b^2-a^2) + B (b-a)
+
+The quadratic:
+
+.. math::
+
+ \int_a^b y = Ax^2 + Bx + C = \frac{A}{3} (b^3-a^3) + \frac{B}{2} (b^2-a^2) + C (b-a)
+
+
+The sine function:
+
+.. math::
+
+ \int_a^b \sin(x) = \cos(a) - \cos(b)
+
+Computational Accuracy
+----------------------
+
+In the case of the linear functions, the result should theoretically be exact. But with the vagaries of floating point math may not be.
+
+And for non-linear functions, the result will certainly not be exact.
+
+So you want to check if the answer is *close* to what you expect.
+
+In py3.5 -- there is an ``isclose()`` function (PEP485)
+
+https://www.python.org/dev/peps/pep-0485/
+
+In earlier pythons -- you'll need your own. There is one in:
+
+``Examples/Session09/test_trapz.py``
+
+
+
+Stage two:
+----------
+
+Some functions need extra parameters to do their thing. But the above will only handle a single parameter. For example, a quadratic function:
+
+.. math::
+
+ y = A x^2 + Bx + C
+
+Requires values for A, B, and C in order to compute y from an given x.
+
+You could write a specialized version of this function for each A, B, and C:
+
+.. code-block:: python
+
+ def quad1(x):
+ return 3 * x**2 + 2*x + 4
+
+But then you need to write a new function for any value of these parameters you might need.
+
+.. nextslide::
+
+Instead, you can pass in A, B and C each time:
+
+.. code-block:: python
+
+ def quadratic(x, A=0, B=0, C=0):
+ return A * x**2 + B * x + C
+
+Nice and general purpose.
+
+But how would we compute the area under this function?
+
+The function we wrote above only passes x in to the function it is integrating.
+
+Passing arguments through:
+--------------------------
+
+Update your trapz() function so that you can give it a function that takes arbitrary extra arguments, either positional or keyword, after the x.
+
+So you can do:
+
+.. code-block:: python
+
+ trapz(quadratic, 2, 20, A=1, B=3, C=2)
+
+or
+
+.. code-block:: python
+
+ trapz(quadratic, 2, 20, 1, 3, C=2)
+
+or
+
+.. code-block:: python
+
+ coef = {'A':1, 'B':3, 'C': 2}
+ trapz(quadratic, 2, 20, **coef)
+
+.. nextslide::
+
+**NOTE:** Make sure this will work with ANY function, with **ANY** additional positional or keyword arguments -- not just this particular function.
+
+This is pretty conceptually challenging -- but it's very little code!
+
+If you are totally lost -- look at the lecture notes from previous classes -- how can you both accept and pass arbitrary arguments to/from a function?
+
+.. nextslide::
+
+You want your trapz function to take ANY function that can take ANY arbitrary extra arguments -- not just the quadratic function, and not just ``A,B, and C``. So good to test with another example.
+
+The generalized sine function is:
+
+.. math::
+
+ A \sin(\omega t)
+
+where :math:`A` is the amplitude, and :math:`\omega` is the frequency of the function. In this case, the area under the curve from a to b is:
+
+.. math::
+
+ \frac{A}{\omega} \left( \cos(\omega a) - \cos(\omega b) \right)
+
+The test code has a test for this one, too.
+
+Currying
+--------
+
+Another way to solve the above problem is to use the original ``trapz``, and create a custom version of the quadratic() function instead.
+
+Write a function that takes ``A, B, and C`` as arguments, and returns a function that evaluates the quadratic for those particular coefficients.
+
+Try passing the results of this into your ``trapz()`` and see if you get the same answer.
+
+partial
+-------
+
+Do the above with ``functools.partial`` as well.
+
+Extra credit
+------------
+
+This isn't really the point of the exercise, but see if you can make it dynamically accurate.
+
+How accurate it is depends on how small the chunks are that you break the function up into.
+
+See if you can think of a way to dynamically determine how small a step you should use.
+
+This is one for the math and computational programming geeks!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/slides_sources/source/extra_topics.rst b/slides_sources/source/extra_topics.rst
new file mode 100644
index 00000000..39062e0a
--- /dev/null
+++ b/slides_sources/source/extra_topics.rst
@@ -0,0 +1,131 @@
+.. _extra_topics:
+
+************
+Extra Topics
+************
+
+Here are some extra topics that we didn't have time for in the regular class sessions:
+
+==============================
+Closures and function Currying
+==============================
+
+Defining specialized functions on the fly
+
+Closures
+--------
+
+"Closures" and "Currying" are cool CS terms for what is really just defining functions on the fly.
+
+you can find a "proper" definition here:
+
+https://en.wikipedia.org/wiki/Closure_(computer_programming)
+
+but I even have trouble following that.
+
+So let's go straight to an example:
+
+.. nextslide::
+
+.. code-block:: python
+
+ def counter(start_at=0):
+ count = [start_at]
+ def incr():
+ count[0] += 1
+ return count[0]
+ return incr
+
+What's going on here?
+
+We have stored the ``start_at`` value in a list.
+
+Then defined a function, ``incr`` that adds one to the value in the list, and returns that value.
+
+[ Quiz: why is it: ``count = [start_at]``, rather than just ``count=start_at`` ]
+
+.. nextslide::
+
+So what type of object do you get when you call ``counter()``?
+
+.. code-block:: ipython
+
+ In [37]: c = counter(start_at=5)
+
+ In [38]: type(c)
+ Out[38]: function
+
+So we get a function back -- makes sense. The ``def`` defines a function, and that function is what's getting returned.
+
+Being a function, we can, of course, call it:
+
+.. code-block:: ipython
+
+ In [39]: c()
+ Out[39]: 6
+
+ In [40]: c()
+ Out[40]: 7
+
+Each time is it called, it increments the value by one.
+
+.. nextslide::
+
+But what happens if we call ``counter()`` multiple times?
+
+.. code-block:: ipython
+
+ In [41]: c1 = counter(5)
+
+ In [42]: c2 = counter(10)
+
+ In [43]: c1()
+ Out[43]: 6
+
+ In [44]: c2()
+ Out[44]: 11
+
+So each time ``counter()`` is called, a new function is created. And that function has its own copy of the ``count`` object. This is what makes in a "closure" -- it carries with it the scope in which is was created.
+
+the returned ``incr`` function is a "curried" function -- a function with some parameters pre-specified.
+
+``functools.partial``
+---------------------
+
+The ``functools`` module in the standard library provides utilities for working with functions:
+
+https://docs.python.org/3.5/library/functools.html
+
+Creating a curried function turns out to be common enough that the ``functools.partial`` function provides an optimized way to do it:
+
+What functools.partial does is:
+
+ * Makes a new version of a function with one or more arguments already filled in.
+ * The new version of a function documents itself.
+
+Example:
+
+.. code-block:: python
+
+ def power(base, exponent):
+ """returns based raised to the give exponent"""
+ return base ** exponent
+
+Simple enough. but what if we wanted a specialized ``square`` and ``cube`` function?
+
+We can use ``functools.partial`` to *partially* evaluate the function, giving us a specialized version:
+
+square = partial(power, exponent=2)
+cube = partial(power, exponent=3)
+
+Reading:
+--------
+
+http://www.pydanny.com/python-partials-are-fun.html
+
+https://pymotw.com/3/functools/
+
+http://www.programiz.com/python-programming/closure
+
+https://www.clear.rice.edu/comp130/12spring/curry/
+
diff --git a/slides_sources/source/homework/html_builder.rst b/slides_sources/source/homework/html_builder.rst
deleted file mode 100644
index 2f5ffad0..00000000
--- a/slides_sources/source/homework/html_builder.rst
+++ /dev/null
@@ -1,193 +0,0 @@
-.. _homework_html_renderer:
-
-==================================
-HTML Renderer Homework Assignment
-==================================
-
-HTML Render
-============
-
-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:
-
-:download:`sample_html.html <./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
-
-.. code-block:: python
-
- 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 ).
-
-.. 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``
-
-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 ```` tag 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...).
-
-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 ``
`` tag inside, and multiple ``
`` tags inside that,
-with text inside that. And all indended nicely.
-
-See ``test_html_output2.html``
-
-Step 3:
---------
-
-Create a ``
`` 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::
-
- PythonClass - Session 6 example
-
-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 ``
`` 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``)
-
-.. code-block:: python
-
- 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 ``
`` tags (and others) with attributes
-
-See ``test_html_output4.html``
-
-Step 5:
---------
-
-Create a ``SelfClosingTag`` subclass of Element, to render tags like::
-
-
and (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 and
-
-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
,
,
, called like
-
-.. code-block:: python
-
- H(2, "The text of the header")
-
-for an
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 "" 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 ```` (like for ```` and `` `` 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``
-
-
-
\ No newline at end of file
diff --git a/slides_sources/source/homework/index.rst b/slides_sources/source/homework/index.rst
deleted file mode 100644
index 805484dc..00000000
--- a/slides_sources/source/homework/index.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Homework Materials
-======================
-
-.. toctree::
- :maxdepth: 1
-
- kata_fourteen
- html_builder
-
diff --git a/slides_sources/source/include.rst b/slides_sources/source/include.rst
new file mode 100644
index 00000000..607ee281
--- /dev/null
+++ b/slides_sources/source/include.rst
@@ -0,0 +1,6 @@
+
+.. |instructor_1_name| replace:: Christopher Barker
+.. |instructor_1_email| replace:: PythonCHB@gmail.com
+
+.. |instructor_2_name| replace:: Maria McKinley
+.. |instructor_2_email| replace:: maria@mariakathryn.net
diff --git a/slides_sources/source/index.rst b/slides_sources/source/index.rst
index 07ebd15a..040d3dfe 100644
--- a/slides_sources/source/index.rst
+++ b/slides_sources/source/index.rst
@@ -1,3 +1,8 @@
+***************
+Intro To Python
+***************
+
+
In This Course
==============
@@ -9,7 +14,7 @@ In This Course
| .. toctree:: | .. toctree:: |
| :maxdepth: 1 | :maxdepth: 1 |
| | |
- | session01 | homework/index |
+ | session01 | exercises/index |
| session02 | supplements/index |
| session03 | |
| session04 | |
@@ -17,6 +22,8 @@ In This Course
| session06 | |
| session07 | |
| session08 | |
+ | session09 | |
+ | session10 | |
+----------------------+-----------------------+
.. ifnotslides::
@@ -35,6 +42,8 @@ In This Course
session06
session07
session08
+ session09
+ session10
Materials:
----------
@@ -42,14 +51,16 @@ In This Course
.. toctree::
:maxdepth: 2
- homework/index
+ extra_topics
+ exercises/index
supplements/index
.. rst-class:: credit
These materials copyright Christopher Barker and Cris Ewing, with thanks to
Jon Jacky and Brian Dorsey for the materials from which these were derived.
-Licenced under the Creative Commons Attribution-ShareAlike 4.0 International Public License.
+Licenced under the
+Creative Commons Attribution-ShareAlike 4.0 International Public License.
https://creativecommons.org/licenses/by-sa/4.0/legalcode
diff --git a/slides_sources/source/session01.rst b/slides_sources/source/session01.rst
index 73853c1c..a282e32a 100644
--- a/slides_sources/source/session01.rst
+++ b/slides_sources/source/session01.rst
@@ -1,9 +1,16 @@
+.. include:: include.rst
+
**************************
Session One: Introductions
**************************
-| In which you are introduced to this class, your instructors, your environment
-| and your new best friend, Python.
+Introductions
+=============
+
+In which you are introduced to this class, your instructors, your environment,
+and your new best friend, Python.
+
+|
.. image:: /_static/python.png
:align: center
@@ -15,6 +22,17 @@ Session One: Introductions
.. _xkcd.com/353: http://xkcd.com/353
+Goals for Session One:
+======================
+
+* Meet each other, set expectations for the class.
+
+* Schedule lightning talks.
+
+* Get you all up and running with Python
+
+* Start having fun with Python with a quick tutorial
+
Introductions
=============
@@ -26,37 +44,39 @@ In which we meet each-other
Your instructors
----------------
-.. rst-class:: center large
+.. rst-class:: center medium
-| Christopher Barker
-| (PythonCHB at gmail dot com)
+| |instructor_1_name|
+| |instructor_1_email|
|
.. nextslide::
-.. rst-class:: center large
+.. rst-class:: center medium
-| Nathan Savage
-| (nathansavagemail at gmail dot com)
+| |instructor_2_name|
+| |instructor_2_email|
|
Who are you?
-------------
-.. rst-class:: center large
+.. rst-class:: center medium
Tell us a tiny bit about yourself:
* name
-* programming background
-* what do you hope to get from this class
+* programming background: what languages have you used?
+* neighbor's name
+* neighbor's favorite coffee shop or bar
+
Introduction to This Class
==========================
.. rst-class:: center large
-Intro to Python
+ Introduction to Python
Course Materials Online
@@ -66,27 +86,29 @@ A rendered HTML copy of the slides for this course may be found online at:
http://uwpce-pythoncert.github.io/IntroToPython
-Also there are same homework descriptions and supplemental materials.
+Also there are some exercise descriptions and supplemental materials.
The source of these materials are in the class gitHub repo:
https://github.com/UWPCE-PythonCert/IntroToPython
-Class email list: We will be using this list to communicate for this class:
+We also have a bunch of supplemental resources for the program here:
-programming-in-python@googlegroups.com
+http://uwpce-pythoncert.github.io/PythonResources/index.html
-You should have (or will soon) received and email invitation to join
-the mailing list.
+The source for those is here:
+https://github.com/UWPCE-PythonCert/PythonResources
Class Structure
---------------
Class Time:
- * Some lecture, lots of demos
+ * Some lecture -- as little as possible
+ * Lots of demos
* Lab time: lots of hand-on practice
+ - Take a break if you need one then...
* Lather, Rinse, Repeat.....
Interrupt me with questions -- please!
@@ -94,89 +116,65 @@ Interrupt me with questions -- please!
(Some of the best learning prompted by questions)
Homework:
-----------
-
-* Assigned at each class
-
-* You are adults -- it's up to you to do it
-
-* You can do a gitHub "pull request" if you want us to review it.
-
-* I'll review at the next class
-
-
-Mailing list and Office Hours
-------------------------------
-
-We've set up a google group -- you will all be invited to join::
-
-programming-in-python@googlegroups.com
+---------
-Office Hours:
+* Homework will be reading, exercises, and the occasional Video
-I generally will hold "office hours" at a coffee shop for a couple hours each
-weekend.
+* Exercises will be started in class -- but you can finish them at home.
-Nathan can do some as well.
+* You are adults -- it's up to you to do it
-What are good times for you?
+* You can do a gitHub "pull request" if you want us to review your work.
+ - We'll show you how to do that in the second session
-Lightning Talks
-----------------
+Communication
+-------------
-Lightning Talks:
+**Mailing list:**
- * 5 minutes (including setup) - no kidding!
- * Every student will give one
- * Purposes: introduce yourself, share interests, also show Python applications
- * Any topic you like, that is related to Python -- according to you!
+We've set up a Google Group for this class:
-We need to schedule them -- let's use Python for that!
+programming-in-python@googlegroups.com
+We will be using this list to communicate with you. You should have (or will soon) received an email invitation to join the mailing list.
-Python Ecosystem
------------------
+Slack: We have set up a slack channel for discussions. Anything python related is fair game.
-Python is Used for:
+https://python2016fall.slack.com/
- * CS education (this course!)
- * Application scripting (GIS, GNU Radio, Blender...)
- * Systems administration and "glue"
- * Web applications (Django etc. etc. etc.)
- * Scientific/technical computing (a la MATLAB, R, .... )
- * Software tools (automated software testing, distributed version control, ...)
- * Research (natural language, graph theory, distributed computing, ...)
+We highly encourage you to work together. You will learn at a much deeper level if you work together,
+and it gets you ready to collaborate with colleagues.
-An unusually large number of niches -- versatile
-.. nextslide::
+Office Hours
+------------
-Used by:
+We will generally will hold "office hours" at a coffee shop for a couple hours
+each weekend.
-* Beginners
-* Professional software developers, computer system administrators, ...
-* Professionals OTHER THAN computer specialists: biologists, urban planners, ....
+Please feel free to attend even if you do not have a specific question.
+It is an opportunity to work with the instructors and fellow students,
+and learn from each other.
-An unusually large number of types of users -- versatile
+What are good times for you?
-You can be productive in Python WITHOUT full-time immersion!
+And what locations?
+Lightning Talks
+----------------
-Python Features
----------------
+**Lightning Talks:**
-Gets many things right:
+ * 5 minutes each (including setup) - no kidding!
+ * Every student will give one
+ * Purposes: introduce yourself, share interests, show Python applications
+ * Any topic you like that is related to Python -- according to you!
-* Readable -- looks nice, makes sense
-* No ideology about best way to program -- object-oriented programming, functional, etc.
-* No platform preference -- Windows, Mac, Linux, ...
-* Easy to connect to other languages -- C, Fortran - essential for science/math
-* Large standard library
-* Even larger network of external packages
-* Countless conveniences, large and small, make it pleasant to work with
+Python Ecosystem
+================
What is Python?
---------------
@@ -188,7 +186,6 @@ What is Python?
* Byte-compiled
* Interpreted
-
.. nextslide::
.. rst-class:: center large
@@ -199,8 +196,6 @@ But what does that mean?
Python Features
---------------
-Features:
-
.. rst-class:: build
* Unlike C, C++, C\#, Java ... More like Ruby, Lisp, Perl, Javascript
@@ -291,19 +286,18 @@ Python 3.x ("py3k")
.. nextslide::
-This class uses Python 2.7 not Python 3.x
-
-.. rst-class:: build
+This class uses Python 3 -- not Python 2
* Adoption of Python 3 is growing fast
- * A few key packages still not supported (https://python3wos.appspot.com/)
- * Most code in the wild is still 2.x
+ * Almost all key packages now supported (https://python3wos.appspot.com/)
+ * But much code in the wild is still 2.x
-* You *can* learn to write Python that is forward compatible from 2.x to 3.x
-* We will be teaching from that perspective.
+* If you find yourself needing to work with Python 2 and 3, there are ways to write compatible code:
-* If you find yourself needing to work with Python 2 and 3, there are ways to write compatible code: https://wiki.python.org/moin/PortingPythonToPy3k
+https://wiki.python.org/moin/PortingPythonToPy3k
+
+* We will cover that more later in the program. Also: a short intro to the differences you really need to know about up front later this session.
Introduction to Your Environment
@@ -311,6 +305,8 @@ Introduction to Your Environment
There are three basic elements to your environment when working with Python:
+.. rst-class:: left
+
.. rst-class:: build
* Your Command Line
@@ -323,70 +319,142 @@ Your Command Line (cli)
Having some facility on the command line is important
-We won't cover this in class, so if you are not comfortable, please bone up at
-home.
+We won't cover this much in class, so if you are not comfortable,
+please bone up at home.
-I suggest running through the **cli** tutorial at "learn code the hard way":
+We have some resources here: `PythonResources--command line `_
-`http://cli.learncodethehardway.org/book`_
+**Windows:**
-.. _http://cli.learncodethehardway.org/book: http://cli.learncodethehardway.org/book
+Most of the demos in class, etc, will be done using the "bash" command line shell on OS-X. This is identical to the bash shell on Linux.
+Windows provides the "DOS" command line, which is OK, but pretty old and limited, or "Power Shell" -- a more modern, powerful, flexible command shell.
-.. nextslide:: Command Line Enhancements
+If you are comfortable with either of these -- go for it.
-There are a few things you can do to help make your command line a better place
-to work.
+If not, you can use the "git Bash" shell -- which is much like the bash shell on OS-X and Linux. Or, on Windows 10, look into the "bash shell for Windows" otherwise known as the "Linux system" - - more info here: `PythonResources--Windows Bash `_
-Part of your homework this week will be to do these things.
-More on this later.
+LAB: Getting set up
+-------------------
+Before we move on -- we need to get all of us on the same page, with the tools we need for class.
-Your Interpreter
-----------------
+You will find instructions for how to get python, etc, up and running on your machine here:
-Python comes with a built-in interpreter.
+**Windows:**
-You see it when you type ``python`` at the command line:
+http://uwpce-pythoncert.github.io/PythonResources/Installing/python_for_windows.html
-.. code-block:: pycon
+**OS-X:**
- $ python
- Python 2.7.5 (default, Aug 25 2013, 00:04:04)
- [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
- Type "help", "copyright", "credits" or "license" for more information.
- >>>
+http://uwpce-pythoncert.github.io/PythonResources/Installing/python_for_mac.html
+
+**Linux:**
+
+http://uwpce-pythoncert.github.io/PythonResources/Installing/python_for_linux.html
+
+We'll run through some of that together.
+
+If you already have a working environment, please feel free to help your neighbor or look at the Python Resources pages, particularly reviewing/learning the shell and git.
+
+http://uwpce-pythoncert.github.io/PythonResources
+
+Our Class Environment
+---------------------
+
+We are going to work from a common environment in this class.
+
+We will take the time here in class to get this going.
+
+This helps to ensure that you will be able to work.
+
+
+Step 1: Python 3
+------------------
+
+.. rst-class:: medium
+
+ Do you already have this??
+
+.. code-block:: bash
+
+ $ python
+ Python 3.6.1 (v3.5.2:4def2a2901a5, Jun 26 2016, 10:47:25)
+ [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
+ Type "help", "copyright", "credits" or "license" for more information.
+ >>>
+
+If not, or you have an older version -- let's install it!
+
+If you're all ready to go -- take this time to get started on a tutorial:
-That last thing you see, ``>>>`` is the "Python prompt".
+http://uwpce-pythoncert.github.io/PythonResources/GeneralPython/learning.html#getting-started-tutorials
-This is where you type code.
+Step 2: Pip
+-----------
+
+Python comes with quite a bit ("batteries included").
+
+Sometimes you need a bit more.
+
+Pip allows you to install Python packages to expand your system.
+
+The previous instructions include pip as well - make sure it's working.
+
+Once you've installed pip, you use it to install Python packages by name:
+
+.. code-block:: bash
+
+ $ python -m pip install foobar
+ ...
+
+To find packages (and their proper names), you can search the python
+package index (PyPI):
+
+https://pypi.python.org/pypi
+
+
+Step 3: Install iPython
+------------------------
+
+As this is an intro class, we are going to use almost entirely features
+of the standard library. But there are a couple things you may want:
+
+**iPython** is an "enhanced python shell" -- it make s it easier to work with python interactively.
+
+.. code-block:: bash
+
+ $ python -m pip install ipython[all]
-.. nextslide:: Python in the Interpreter
+
+Python in the Interpreter
+-------------------------
Try it out:
-.. code-block:: pycon
+.. code-block:: python
- >>> print u"hello world!"
+ >>> print("hello world!")
hello world!
>>> 4 + 5
9
>>> 2 ** 8 - 1
255
- >>> print u"one string" + u" plus another"
+ >>> print ("one string" + " plus another")
one string plus another
>>>
.. nextslide:: Tools in the Interpreter
-When you are in an interpreter, there are a number of tools available to you.
+When you are in an interpreter, there are a number of tools available to
+you.
There is a help system:
-.. code-block:: pycon
+.. code-block:: python
>>> help(str)
Help on class str in module __builtin__:
@@ -405,9 +473,9 @@ You can type ``q`` to exit the help viewer.
You can also use the ``dir`` builtin to find out about the attributes of a
given object:
-.. code-block:: pycon
+.. code-block:: python
- >>> bob = u"this is a string"
+ >>> bob = "this is a string"
>>> dir(bob)
['__add__', '__class__', '__contains__', '__delattr__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
@@ -436,8 +504,7 @@ Your Editor
Typing code in an interpreter is great for exploring.
-But for anything "real", you'll want to save the work you are doing in a more permanent
-fashion.
+But for anything "real", you'll want to save the work you are doing in a more permanent fashion.
This is where an Editor fits in.
@@ -449,7 +516,7 @@ MS Word is **not** a text editor.
Nor is *TextEdit* on a Mac.
-``Notepad`` is a text editor -- but a crappy one.
+``Notepad`` on Windows is a text editor -- but a crappy one.
You need a real "programmers text editor"
@@ -458,7 +525,6 @@ characters hidden behind the scenes.
.. nextslide:: Minimum Requirements
-
At a minimum, your editor should have:
.. rst-class:: build
@@ -472,28 +538,29 @@ In addition, great features to add include:
* Tab completion
* Code linting
-* Jump-to-definition
-* Interactive follow-along for debugging
Have an editor that does all this? Feel free to use it.
-If not, I suggest ``Sublime Text``:
+If not, I suggest ``SublimeText``: http://www.sublimetext.com/
+
+(Use version 3, even though it's "beta")
-http://www.sublimetext.com/
+http://uwpce-pythoncert.github.io/PythonResources/DevEnvironment/sublime_as_ide.html
+"Atom" is another good open source option.
+
+And, of course, vi or Emacs on Linux, if you are familiar with those.
Why No IDE?
-----------
I am often asked this question.
-An IDE does not give you much that you can't get with a good editor plus a good
-interpreter.
+An IDE does not give you much that you can't get with a good editor plus a good interpreter.
An IDE often weighs a great deal
-Setting up IDEs to work with different projects can be challenging and
-time-consuming.
+Setting up IDEs to work with different projects can be challenging and time-consuming.
Particularly when you are first learning, you don't want too much done for you.
@@ -504,127 +571,6 @@ Particularly when you are first learning, you don't want too much done for you.
YAGNI
-Setting Up Your Environment
-===========================
-
-.. rst-class:: centered large
-
-Shared setup means reduced complications.
-
-
-Our Class Environment
----------------------
-
-We are going to work from a common environment in this class.
-
-We will take the time here in class to get this going.
-
-This helps to ensure that you will be able to work.
-
-
-Step 1: Python 2.7
-------------------
-
-.. rst-class:: large
-
-You have this already, RIGHT?
-
-.. code-block:: bash
-
- $ python
- Python 2.7.5 (default, Aug 25 2013, 00:04:04)
- [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
- Type "help", "copyright", "credits" or "license" for more information.
- >>> ^D
- $
-
-If not:
-
- * `For the mac <./supplements/python_for_mac.html>`_
-
- * `For linux <./supplements/python_for_linux.html>`_
-
- * `For windows <./supplements/python_for_windows.html>`_
-
-Step 2: Pip
------------
-
-Python comes with quite a bit ("batteries included").
-
-Sometimes you need a bit more.
-
-Pip allows you to install Python packages to expand your system.
-
-You install it by downloading and then executing an installer script:
-
-.. code-block:: bash
-
- $ curl -O https://bootstrap.pypa.io/get-pip.py
- % Total % Received % Xferd Average Speed Time Time Time Current
- Dload Upload Total Spent Left Speed
- 100 1309k 100 1309k 0 0 449k 0 0:00:02 0:00:02 --:--:-- 449k
-
- $ python get-pip.py
-
-(or go to: http://pip.readthedocs.org/en/latest/installing.html)
-
-.. nextslide:: Using Pip
-
-Once you've installed pip, you use it to install Python packages by name:
-
-.. code-block:: bash
-
- $ pip install foobar
- ...
-
-To find packages (and their proper names), you can search the python package index (PyPI):
-
-https://pypi.python.org/pypi
-
-
-Step 4: Clone Class Repository
-------------------------------
-
-`gitHub `_ is an industry-standard system for collaboration
-on software projects -- particularly open source ones.
-
-Next, you'll make a copy of the class repository using ``git``.
-
-The canonical copy is in the UWPCE organization on GitHub:
-
-https://github.com/UWPCE-PythonCert/IntroToPython
-
-Open that URL, and look for: "HTTPS clone URL"
-
-You can click in there an copy and paste to get the clone url.
-
-At your command line, run the following commands:
-
-.. code-block:: bash
-
- $ cd your_working_directory_for_the_class
- $ git clone https://github.com/UWPCE-PythonCert/IntroToPython.git
-
-(you can copy and paste that link from the gitHub page)
-
-
-Step 5: Install Requirements
-----------------------------
-
-As this is an intro class, we are going to use almost entirely features
-of standand library. But there are a couple things you may want:
-
-**iPython**
-
-.. code-block:: bash
-
- $pip install ipython
-
-If you are using SublimeText, you may want:
-
-.. code-block:: bash
-
- $ pip install PdbSublimeTextSupport
Introduction to iPython
=======================
@@ -632,7 +578,7 @@ Introduction to iPython
iPython Overview
------------------
-You have now installed `iPython`_.
+You have installed `iPython`_.
iPython is an advanced Python interpreter that offers enhancements.
@@ -643,8 +589,8 @@ Specifically, you'll want to pay attention to the information about
`Using iPython for Interactive Work`_.
.. _iPython: http://ipython.org
-.. _official documentation: http://ipython.org/ipython-doc/stable/index.html
-.. _Using iPython for Interactive Work: http://ipython.org/ipython-doc/stable/interactive/index.html
+.. _official documentation: http://ipython.readthedocs.io/en/stable/
+.. _Using iPython for Interactive Work: http://ipython.readthedocs.io/en/stable/interactive/index.html
.. ifslides::
@@ -654,25 +600,22 @@ Specifically, you'll want to pay attention to the information about
The very basics of iPython
--------------------------
-iPython can do a lot for you, but for starters, here are the key pieces you'll
-want to know:
+iPython can do a lot for you, but for starters, here are the key pieces
+you'll want to know:
Start it up
.. code-block:: bash
- $ipython
-
- $ ipython
- Python 2.7.6 (v2.7.6:3a1db0d2747e, Nov 10 2013, 00:42:54)
- Type "copyright", "credits" or "license" for more information.
-
- IPython 2.0.0 -- An enhanced Interactive Python.
- ? -> Introduction and overview of IPython's features.
- %quickref -> Quick reference.
- help -> Python's own help system.
- object? -> Details about 'object', use 'object??' for extra details.
+ $ ipython
+ Python 3.5.0 (v3.5.0:374f501f4567, Sep 12 2015, 11:00:19)
+ Type "copyright", "credits" or "license" for more information.
+ IPython 4.0.0 -- An enhanced Interactive Python.
+ ? -> Introduction and overview of IPython's features.
+ %quickref -> Quick reference.
+ help -> Python's own help system.
+ object? -> Details about 'object', use 'object??' for extra details.
.. ifslides::
@@ -718,12 +661,13 @@ This is the stuff I use every day:
That's it -- you can get a lot done with those.
+
How to run a python file
--------------------------
A file with python code in it is a 'module' or 'script'
-(more on the distiction later on...)
+(more on the distinction later on...)
It should be named with the ``.py`` extension: ``some_name.py``
@@ -735,7 +679,19 @@ To run it, you have a couple options:
$ python the_name_of_the_script.py
-2) run ``iPython``, and run it from within iPython with the ``run`` command
+2) On *nix (linux, OS-X, Windows bash), you can make the file "executable"::
+
+ chmod +x the_file.py
+
+ And make sur it has a "shebang" line at the top::
+
+ #!/usr/bin/env python
+
+ Then you can run it directly::
+
+ ./the_file.py
+
+3) run ``iPython``, and run it from within iPython with the ``run`` command
.. code-block:: ipython
@@ -747,16 +703,61 @@ To run it, you have a couple options:
[demo]
-
-
Basic Python Syntax
===================
+(Follow along in the iPython interpreter...)
+
.. rst-class:: center mlarge
-| Expressions, Statements,
-| Values, Types, and Symbols
+| Values, Types, and Names
+|
+| Expressions and Statements
+
+
+Values
+------
+
+All of programming is really about manipulating values.
+
+* Values are pieces of unnamed data: ``42``, ``'Hello, world'``
+
+* In Python, all values are objects
+
+ - Try ``dir(42)`` - lots going on behind the curtain!
+
+* Every value has a type
+
+ - Try ``type(42)`` - the type of a value determines what it can do
+
+.. ifslides::
+
+ .. rst-class:: centered
+
+ [demo]
+
+
+Literals for the Basic Value types:
+------------------------------------
+
+Numbers:
+ - floating point: ``3.4``
+ - integers: ``456``
+
+Text:
+ - ``"a bit of text"``
+ - ``'a bit of text'``
+ - (either single or double quotes work -- why?)
+
+Boolean values:
+ - ``True``
+ - ``False``
+
+The nothing object:
+ - ``None``
+
+(There are intricacies to all of these that we'll get into later)
Code structure
--------------
@@ -786,49 +787,28 @@ Statements:
In [6]: # statements do not return a value, may contain an expression
- In [7]: print u"this"
- this
+ In [7]: line_count = 42
- In [8]: line_count = 42
+ In [8]: return something
- In [9]:
-
-.. nextslide:: The Print Statement
+.. nextslide:: The Print Function
It's kind of obvious, but handy when playing with code:
.. code-block:: ipython
- In [1]: print u"something"
+ In [1]: print("something")
something
-You can print multiple things:
+You can print multiple things:
.. code-block:: ipython
- In [2]: print u"the value is", 5
+ In [2]: print("the value is", 5)
the value is 5
-.. nextslide::
-
-Python automatically adds a newline, which you can suppress with a comma:
-
-
-.. code-block:: ipython
-
- In [12]: for i in range(5):
- ....: print u"the value is",
- ....: print i
- ....:
- the value is 0
- the value is 1
- the value is 2
- the value is 3
- the value is 4
-
-
.. nextslide::
Any python object can be printed (though it might not be pretty...)
@@ -839,7 +819,7 @@ Any python object can be printed (though it might not be pretty...)
...: pass
...:
- In [2]: print bar
+ In [2]: print(bar)
@@ -856,7 +836,7 @@ Blocks of code are delimited by a colon and indentation:
.. code-block:: python
for i in range(100):
- print i**2
+ print(i**2)
.. code-block:: python
@@ -867,7 +847,7 @@ Blocks of code are delimited by a colon and indentation:
.. nextslide::
-Python uses whitespace to delineate structure.
+Python uses indentation to delineate structure.
This means that in Python, whitespace is **significant**.
@@ -887,12 +867,12 @@ These two blocks look the same:
.. code-block:: python
for i in range(100):
- print i**2
+ print(i**2)
.. code-block:: python
for i in range(100):
- print i**2
+ print(i**2)
.. nextslide::
@@ -918,52 +898,16 @@ But they are not:
NEVER INDENT WITH TABS
-make sure your editor is set to use spaces only --
-
-ideally even when you hit the key
-
-Values
-------
-
-.. rst-class:: build
+Make sure your editor is set to use spaces only --
-* Values are pieces of unnamed data: ``42, u'Hello, world',``
-* In Python, all values are objects
+Even when you hit the key
- * Try ``dir(42)`` - lots going on behind the curtain!
+[Python itself allows any number of spaces (and tabs), but you are just going to confuse yourself and others if you do anything else]
-* Every value belongs to a type
-
- * Try ``type(42)`` - the type of a value determines what it can do
-
-.. ifslides::
-
- .. rst-class:: centered
-
- [demo]
-
-Literals for the Basic Value types:
-------------------------------------
-
-Numbers:
- - floating point: ``3.4``
- - integers: ``456``
-
-Text:
- - ``u"a bit of text"``
- - ``u'a bit of text'``
- - (either single or double quotes work -- why?)
-
-Boolean values:
- - ``True``
- - ``False``
-
-(There are intricacies to all of these that we'll get into later)
-
-Values in Action
-----------------
+Expressions
+------------
-An expression is made up of values and operators
+An *expression* is made up of values and operators.
.. rst-class:: build
@@ -974,12 +918,11 @@ An expression is made up of values and operators
* Integer vs. float arithmetic
* (Python 3 smooths this out)
- * Always use ``/`` when you want float results, ``//`` when you want floored (integer) results
+ * Always use ``/`` when you want division with float results, ``//`` when you want floored (integer) results (no remainder).
* Type conversions
* This is the source of many errors, especially in handling text
- * Python 3 will not implicitly convert bytes to unicode
* Type errors - checked at run time only
@@ -990,31 +933,31 @@ An expression is made up of values and operators
[demo]
-Symbols
+Names
-------
-Symbols are how we give names to values (objects).
+Names are how we give names to values (objects) -- hence "names"
.. rst-class:: build
-* Symbols must begin with an underscore or letter
-* Symbols can contain any number of underscores, letters and numbers
+* Names must begin with an underscore or letter
+* Names can contain any number of underscores, letters and numbers
- * this_is_a_symbol
+ * this_is_a_name
* this_is_2
* _AsIsThis
* 1butThisIsNot
* nor-is-this
-* Symbols don't have a type; values do
+* Names don't have a type; values do
- * This is why python is 'Dynamic'
+ * This is why python is "Dynamic"
-Symbols and Type
+Names and Type
----------------
-Evaluating the type of a *symbol* will return the type of the *value* to which
+Evaluating the type of a *name* will return the type of the *value* to which
it is bound.
.. code-block:: ipython
@@ -1037,11 +980,12 @@ it is bound.
In [26]: type(a)
Out[26]: float
+*wait!* a has a different type?!? -- yes, because it's the type of teh value: "3.14", names don't actually have a type, they can refer to any type.
Assignment
----------
-A *symbol* is **bound** to a *value* with the assignment operator: ``=``
+A *name* is **bound** to a *value* with the assignment operator: ``=``
.. rst-class:: build
@@ -1049,17 +993,16 @@ A *symbol* is **bound** to a *value* with the assignment operator: ``=``
* A value can have many names (or none!)
* Assignment is a statement, it returns no value
-
.. nextslide::
Evaluating the name will return the value to which it is bound
.. code-block:: ipython
- In [26]: name = u"value"
+ In [26]: name = "value"
In [27]: name
- Out[27]: u'value'
+ Out[27]: 'value'
In [28]: an_integer = 42
@@ -1071,6 +1014,24 @@ Evaluating the name will return the value to which it is bound
In [31]: a_float
Out[31]: 3.14
+Variables?
+----------
+
+.. rst-class:: build
+
+* In most languages, what I'm calling names are called "variables".
+
+* In fact, I'll probably call them variables in this class.
+
+* That's because they are used, for the most part, for the same purposes.
+
+* But often a "variable" is defined as something like:
+ "a place in memory that can store values"
+
+* That is **NOT** what a name in python is!
+
+* A name can be bound to a value -- but that has nothing to do with a
+ location in memory.
In-Place Assignment
-------------------
@@ -1102,7 +1063,8 @@ also: ``-=, *=, /=, **=, \%=``
Multiple Assignment
-------------------
-You can assign multiple variables from multiple expressions in one statement
+You can assign multiple names from multiple expressions in one
+statement
.. code-block:: ipython
@@ -1125,7 +1087,7 @@ Python evaluates all the expressions on the right before doing any assignments
Nifty Python Trick
------------------
-Using this feature, we can swap values between two symbols in one statement:
+Using this feature, we can swap values between two names in one statement:
.. code-block:: ipython
@@ -1143,15 +1105,14 @@ Using this feature, we can swap values between two symbols in one statement:
In [55]: j
Out[55]: 4
-Multiple assignment and symbol swapping can be very useful in certain contexts
-
+Multiple assignment and name swapping can be very useful in certain contexts
Deleting
--------
-You can't actually delete anything in python...
+You can't actually directly delete values in python...
-``del`` only unbinds a name.
+``del`` only deletes a name (or "unbinds" the name...)
.. code-block:: ipython
@@ -1200,7 +1161,7 @@ Identity
Every value in Python is an object.
Every object is unique and has a unique *identity*, which you can inspect with
-the ``id`` *builtin*:
+the ``id`` *builtin* function:
.. code-block:: ipython
@@ -1219,7 +1180,7 @@ the ``id`` *builtin*:
Testing Identity
----------------
-You can find out if the values bound to two different symbols are the **same
+You can find out if the values bound to two different names are the **same
object** using the ``is`` operator:
.. code-block:: ipython
@@ -1242,6 +1203,7 @@ object** using the ``is`` operator:
[demo]
+**NOTE:** checking the id of an object, or using "is" to check if two objects are the same is rarely used except for debugging and understanding what's going on under the hood. They are not used regularly in production code.
Equality
--------
@@ -1257,17 +1219,39 @@ You can test for the equality of certain values with the ``==`` operator
In [79]: val1 == val2
Out[79]: True
- In [80]: val3 = u'50'
+ In [80]: val3 = '50'
In [81]: val1 == val3
Out[84]: False
+A string is never equal to a number!
+
.. ifslides::
.. rst-class:: centered
[demo]
+For the numerical values, there is also::
+
+ >, <, >=, <=, !=
+
+Singletons
+----------
+
+Python has three "singletons" -- value fro which there is only one instance:
+
+ ``True``, ``False``, and ``None``
+
+To check if a name is bound to one of these, you use ``is``::
+
+ a is True
+
+ b is False
+
+ x is None
+
+Note that in contrast to english -- "is" is asking a question, not making an assertion -- ``a is True`` means "is a the True value?"
Operator Precedence
-------------------
@@ -1278,8 +1262,11 @@ Operator Precedence determines what evaluates first:
4 + 3 * 5 != (4 + 3) * 5
-To force statements to be evaluated out of order, use parentheses.
+To force statements to be evaluated out of order, use parentheses -- expressions in parentheses are always evaluated first:
+ (4 + 3) * 5 != 4 + (3 * 5)
+
+Python follows the "usual" rules of algebra.
Python Operator Precedence
--------------------------
@@ -1287,7 +1274,7 @@ Python Operator Precedence
Parentheses and Literals:
``(), [], {}``
- ``"", b'', u''``
+ ``"", b'', ''``
Function Calls:
``f(args)``
@@ -1339,40 +1326,45 @@ Anonymous Functions:
String Literals
---------------
-You define a ``string`` value by writing a *literal*:
+A "string" is a chunk of text.
+
+You define a "string" value by writing a string *literal*:
.. code-block:: ipython
- In [1]: u'a string'
- Out[1]: u'a string'
+ In [1]: 'a string'
+ Out[1]: 'a string'
- In [2]: u"also a string"
- Out[2]: u'also a string'
+ In [2]: "also a string"
+ Out[2]: 'also a string'
- In [3]: u"a string with an apostrophe: isn't it cool?"
- Out[3]: u"a string with an apostrophe: isn't it cool?"
+ In [3]: "a string with an apostrophe: isn't it cool?"
+ Out[3]: "a string with an apostrophe: isn't it cool?"
- In [4]: u'a string with an embedded "quote"'
- Out[4]: u'a string with an embedded "quote"'
+ In [4]: 'a string with an embedded "quote"'
+ Out[4]: 'a string with an embedded "quote"'
-(what's the '``u``' about?)
.. nextslide::
.. code-block:: ipython
- In [5]: u"""a multi-line
+ In [5]: """a multi-line
...: string
...: all in one
...: """
- Out[5]: u'a multi-line\nstring\nall in one\n'
+ Out[5]: 'a multi-line\nstring\nall in one\n'
- In [6]: u"a string with an \n escaped character"
- Out[6]: u'a string with an \n escaped character'
+ In [6]: "a string with an \n escaped character"
+ Out[6]: 'a string with an \n escaped character'
In [7]: r'a "raw" string, the \n comes through as a \n'
Out[7]: 'a "raw" string, the \\n comes through as a \\n'
+Python3 strings are fully support Unicode, which means that it can suport literally all the languages in the world (and then some -- Klingon, anyone?)
+
+Because Unicode is native, you can get very far without even thinking about it. Anything you can type in your editor will work fine.
+
Keywords
--------
@@ -1381,7 +1373,7 @@ Python defines a number of **keywords**
These are language constructs.
-You *cannot* use these words as symbols.
+You *cannot* use these words as names.
::
@@ -1395,24 +1387,25 @@ You *cannot* use these words as symbols.
.. nextslide::
-If you try to use any of the keywords as symbols, you will cause a
+
+If you try to use any of the keywords as names, you will cause a
``SyntaxError``:
.. code-block:: ipython
- In [13]: del = u"this will raise an error"
+ In [13]: del = "this will raise an error"
File "", line 1
- del = u"this will raise an error"
+ del = "this will raise an error"
^
SyntaxError: invalid syntax
.. code-block:: ipython
- In [14]: def a_function(else=u'something'):
- ....: print else
+ In [14]: def a_function(else='something'):
+ ....: print(else)
....:
File "", line 1
- def a_function(else=u'something'):
+ def a_function(else='something'):
^
SyntaxError: invalid syntax
@@ -1420,7 +1413,7 @@ If you try to use any of the keywords as symbols, you will cause a
__builtins__
------------
-Python also has a number of pre-bound symbols, called **builtins**
+Python also has a number of pre-bound names, called **builtins**
Try this:
@@ -1434,31 +1427,30 @@ Try this:
'BaseException',
'BufferError',
...
- 'unicode',
'vars',
'xrange',
'zip']
.. nextslide::
-You are free to rebind these symbols:
+You are free to rebind these names:
.. code-block:: ipython
- In [15]: type(u'a new and exciting string')
- Out[15]: unicode
+ In [15]: type('a new and exciting string')
+ Out[15]: str
- In [16]: type = u'a slightly different string'
+ In [16]: type = 'a slightly different string'
- In [17]: type(u'type is no longer what it was')
+ In [17]: type('type is no longer what it was')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in ()
- ----> 1 type(u'type is no longer what it was')
+ ----> 1 type('type is no longer what it was')
- TypeError: 'unicode' object is not callable
+ TypeError: 'str' object is not callable
-In general, this is a **BAD IDEA**.
+In general, this is a **BAD IDEA** -- hopefully your editor will warn you.
Exceptions
@@ -1472,11 +1464,12 @@ There are several exceptions that you are likely to see a lot of:
.. rst-class:: build
-* ``NameError``: indicates that you have tried to use a symbol that is not bound to
- a value.
-* ``TypeError``: indicates that you have tried to use the wrong kind of object for
- an operation.
+* ``NameError``: indicates that you have tried to use a name that is not bound to a value.
+
+* ``TypeError``: indicates that you have tried to use the wrong kind of object for an operation.
+
* ``SyntaxError``: indicates that you have mis-typed something.
+
* ``AttributeError``: indicates that you have tried to access an attribute or
method that an object does not have (this often means you have a different
type of object than you expect)
@@ -1491,36 +1484,34 @@ What is a function?
A function is a self-contained chunk of code
-
You use them when you need the same code to run multiple times,
or in multiple parts of the program.
-(DRY)
-
+(DRY) -- "Don't Repeat Yourself"
Or just to keep the code clean
-
Functions can take and return information
.. nextslide::
-Minimal Function does nothing
+The minimal Function has at least one statement
.. code-block:: python
- def ():
-
+ def a_name():
+ a_statement
.. nextslide::
-Pass Statement (Note the indentation!)
+Pass Statement does nothing (Note the indentation!)
.. code-block:: python
def minimal():
pass
+This, or course, is not useful -- you will generally have multiple statements in a function.
Functions: ``def``
------------------
@@ -1530,8 +1521,8 @@ Functions: ``def``
.. rst-class:: build
* it is executed
- * it creates a local variable
-
+ * it creates a local name
+ * it does *not* return a value
.. nextslide::
@@ -1550,7 +1541,7 @@ function defs must be executed before the functions can be called:
.. code-block:: ipython
In [18]: def simple():
- ....: print u"I am a simple function"
+ ....: print("I am a simple function")
....:
In [19]: simple()
@@ -1566,22 +1557,25 @@ You **call** a function using the function call operator (parens):
In [2]: type(simple)
Out[2]: function
+
In [3]: simple
Out[3]:
+
In [4]: simple()
I am a simple function
+Calling a function is how you run the code in that function.
+
Functions: Call Stack
---------------------
-functions call functions -- this makes an execution stack -- that's all a trace
-back is
+functions can call other functions -- this makes an execution stack -- that's what a "trace back" is:
.. code-block:: ipython
In [5]: def exceptional():
- ...: print u"I am exceptional!"
+ ...: print("I am exceptional!")
...: print 1/0
...:
In [6]: def passive():
@@ -1615,13 +1609,13 @@ Functions: Tracebacks
in exceptional()
1 def exceptional():
- 2 print u"I am exceptional!"
- ----> 3 print 1/0
+ 2 print("I am exceptional!")
+ ----> 3 print(1/0)
4
ZeroDivisionError: integer division or modulo by zero
-
+The error occurred in the ``doer`` function -- but the traceback shows you where that was called from. In a more complex system, this can be VERY useful -- learn to read tracebacks!
Functions: ``return``
---------------------
@@ -1637,7 +1631,7 @@ This is actually the simplest possible function:
.. nextslide::
-if you don't explicilty put ``return`` there, Python will:
+if you don't explicitly put ``return`` there, Python will return None for you:
.. code-block:: ipython
@@ -1646,15 +1640,15 @@ if you don't explicilty put ``return`` there, Python will:
...:
In [10]: fun()
In [11]: result = fun()
- In [12]: print result
+ In [12]: print(result)
None
-note that the interpreter eats ``None``
+note that the interpreter eats ``None`` -- you need to call ``print()`` to see it.
.. nextslide::
-Only one return statement will ever be executed.
+Only one return statement in a function will ever be executed.
Ever.
@@ -1665,12 +1659,12 @@ This is useful when debugging!
.. code-block:: ipython
In [14]: def no_error():
- ....: return u'done'
+ ....: return 'done'
....: # no more will happen
- ....: print 1/0
+ ....: print(1/0)
....:
In [15]: no_error()
- Out[15]: u'done'
+ Out[15]: 'done'
.. nextslide::
@@ -1680,7 +1674,7 @@ However, functions *can* return multiple results:
.. code-block:: ipython
In [16]: def fun():
- ....: return (1, 2, 3)
+ ....: return 1, 2, 3
....:
In [17]: fun()
Out[17]: (1, 2, 3)
@@ -1692,7 +1686,7 @@ Remember multiple assignment?
.. code-block:: ipython
- In [18]: x,y,z = fun()
+ In [18]: x, y, z = fun()
In [19]: x
Out[19]: 1
In [20]: y
@@ -1711,10 +1705,10 @@ In a ``def`` statement, the values written *inside* the parens are
In [22]: def fun(x, y, z):
....: q = x + y + z
- ....: print x, y, z, q
+ ....: print(x, y, z, q)
....:
-x, y, z are *local* symbols -- so is q
+x, y, z are *local* names -- so is q
Functions: arguments
@@ -1728,24 +1722,37 @@ When you call a function, you pass values to the function parameters as
In [23]: fun(3, 4, 5)
3 4 5 12
-The values you pass in are *bound* to the symbols inside the function and used.
+The values you pass in are *bound* to the names inside the function and used.
+
+The name used outside the object is separete from the name used inside teh function:
+
+.. code-block:: python
+
+ x = 5
+
+ def fun(a):
+ print(a)
+
+ fun(x)
+
+The "a" printed inside the function is the *same* object as the "x" outside the function.
The ``if`` Statement
---------------------
-In order to do anything interesting at all (including this week's homework), you need to be able to make a decision.
+In order to do anything interesting at all, you need to be able to make a decision.
.. nextslide::
-.. code-block:: python
+.. code-block:: ipython
In [12]: def test(a):
....: if a == 5:
- ....: print u"that's the value I'm looking for!"
+ ....: print("that's the value I'm looking for!")
....: elif a == 7:
- ....: print u"that's an OK number"
+ ....: print("that's an OK number")
....: else:
- ....: print u"that number won't do!"
+ ....: print("that number won't do!")
In [13]: test(5)
that's the value I'm looking for!
@@ -1767,11 +1774,90 @@ That's it for our basic intro to Python
Before next session, you'll use what you've learned here today to do some
exercises in Python programming
+Schedule the lightning talks:
+-----------------------------
+
+.. rst-class:: build
+
+* We need to schedule your lightning talks.
+
+* **Let's use Python for that !**
+
+[demo]
+
+Python 2-3 Differences
+======================
+
+Much of the example code you'll find online is Python2, rather than Python3
+
+For the most part, they are the same -- so you can use those examples to learn from.
+
+There are a lot of subtle differences that you don't need to concern yourself with just yet.
+
+But a couple that you'll need to know right off the bat:
+
+print()
+-------
+
+In python2, ``print`` is a "statement", rather than a function. That means it didn't require parentheses around what you want printed::
+
+ print something, something_else
+
+This made it a bit less flexible and powerful.
+
+But -- if you try to use it that way in Python3, you'll get an error::
+
+ In [15]: print "this"
+ File "", line 1
+ print "this"
+ ^
+ SyntaxError: Missing parentheses in call to 'print'
+
+So -- if you get this error, simply add the parentheses::
+
+ In [16]: print ("this")
+ this
+
+.. nextslide:: division
+
+In python 3, the division operator is "smart" when you divide integers::
+
+ In [17]: 1 / 2
+ Out[17]: 0.5
+
+However in python2, integer division, will give you an integer result::
+
+ In [1]: 1/2
+ Out[1]: 0
+
+In both versions, you can get "integer division" if you want it with a double slash::
+
+ In [1]: 1//2
+ Out[1]: 0
+
+And in python2, you can get the behavior of py3 with "true division"::
+
+ In [2]: from __future__ import division
+
+ In [3]: 1/2
+ Out[3]: 0.5
+
+For the most part, you just need to be a bit careful with the rare cases where py2 code counts on integer division.
+
+Other py2/py3 differences
+-------------------------
+
+Most of the other differences are essentially of implementation details, like getting iterators instead of sequences -- we'll talk about that more when it comes up in class.
+
+There are also a few syntax differences with more advances topics: Exceptions, super(), etc.
+
+We'll talk about all that when we cover those topics.
+
Homework
========
-??? Tasks by Next Week
+Tasks and reading by next week
Task 1
@@ -1782,79 +1868,128 @@ Task 1
Make sure you have the basics of command line usage down:
Work through the supplemental tutorials on setting up your
-`Command Line`_ for good development support.
+Command Line (http://uwpce-pythoncert.github.io/PythonResources/DevEnvironment/shell.html) for good development support.
Make sure you've got your editor set up productively -- at the very very
least, make sure it does Python indentation and syntax coloring well.
+.. nextslide::
+
**Advanced Editor Setup:**
If you are using SublimeText, here are some notes to make it super-nifty:
-Setting up `SublimeText`_ .
+http://uwpce-pythoncert.github.io/PythonResources/DevEnvironment/sublime_as_ide.html
At the end, your editor should support tab completion and pep8 and pyflakes
-linting. Your command line should be able to show you what virtualenv is active
-and give you information about your git repository when you are inside one.
+linting.
If you are not using SublimeText, look for plugins that accomplish the same
goals for your own editor. If none are available, please consider a change of
editor.
-.. _SublimeText: supplements/sublime_as_ide.html
-.. _Command Line: supplements/shell.html
-
Also make sure you've got iPython working, if you didn't get to that in class.
+
+Task 3
+------
+
+**Explore Errors**
+
+* Create a new directory in your working dir for the class::
+
+ $ mkdir session01
+ $ cd session01
+
+* Add a new file to it called ``break_me.py``
+
+* In the ``break_me.py`` file write four simple Python functions:
+
+ * Each function, when called, should cause an exception to happen
+
+ * Each function should result in one of the four common exceptions from our
+ lecture.
+
+ * for review: ``NameError``, ``TypeError``, ``SyntaxError``, ``AttributeError``
+
+(hint -- the interpreter will quit when it hits a Exception -- so you can comment out all but the one you are testing at the moment)
+
+ * Use the Python standard library reference on `Built In Exceptions`_ as a
+ reference
+
+.. _Built In Exceptions: https://docs.python.org/3/library/exceptions.html
+
Task 2
------
**Python Pushups**
To get a bit of exercise solving some puzzles with Python, work on the Python
-exercises at `CodingBat`_.
+exercises at "Coding Bat": http://codingbat.com/python
-Begin by making an account on the site. Once you have done so, go to the
-'prefs' link at the top right and enter your name so we know who you are.
+There are 8 sets of puzzles. Do as many as you can, but try to at least
+get all the "Warmups" done.
-In addition, add the following email address to the 'Share To' box. This will
-allow me instructors to see the work you have done.
-::
+Reading, etc.
+-------------
- PythonCHB@gmail.com
+Every one of you has a different backgrond and learning style.
-There are 8 sets of puzzles. Do as many as you can, starting with the Warmups.
+So take a bit of time to figure out which resource works for you.
-.. _CodingBat: http://codingbat.com
+http://uwpce-pythoncert.github.io/PythonResources/GeneralPython/learning.html
+provides some options. Do look it over.
-Task 3
-------
+But here are few to get you started this week:
-**Explore Errors**
+*Think Python:* Chapters 1–7 (http://greenteapress.com/wp/think-python-2e/)
-* Create a new directory in your working dir for the class.
+*Dive Into Python:* Chapters 1–2 (http://www.diveintopython3.net/)
- $ mkdir session01
- $ cd session01
+*LPTHW:* ex. 1–10, 18-21 (http://learnpythonthehardway.org/book/)
+*NOTE:* LPTHW is python 2 -- you will need to add parentheses to all your print calls!
-* Add a new file to it called ``break_me.py``
+Or follow this excellent introductory tutorial:
+https://www.youtube.com/watch?v=MirG-vJOg04
-* In the ``break_me.py`` file write four simple Python functions:
+You should be comfortable with working with variables, numbers, strings, and basic functions.
- * Each function, when called, should cause an exception to happen
- * Each function should result in one of the four common exceptions from our
- lecture.
+git
+---
- * for review: ``NameError``, ``TypeError``, ``SyntaxError``, ``AttributeError``
+We'll be covering the basics of git next week - enough to use for this class. Please read one of these so you'll have a head start:
-(hint -- the interpreter will quit when it hits a Exception -- so you can comment out all but the one you are testing at the moment)
+http://rogerdudler.github.io/git-guide/
+
+or
+
+https://try.github.io/levels/1/challenges/1
+
+
+Next Class
+===========
+
+Next week, we'll:
+
+ * get set up with git and gitHub
+ * Some more basic Python
+ * More on Functions
+ * Boolean Expressions
+ * Code Structure, Modules, and Namespaces
+
+
+Office Hours
+------------
+
+We will have office hours on either Saturday or Sunday from 10:00 to noon.
+
+Preferences?
+
+Locations?
- * Use the Python standard library reference on `Built In Exceptions`_ as a
- reference
-.. _Built In Exceptions: https://docs.python.org/2/library/exceptions.html
diff --git a/slides_sources/source/session02.rst b/slides_sources/source/session02.rst
index b51b55c5..a5199d68 100644
--- a/slides_sources/source/session02.rst
+++ b/slides_sources/source/session02.rst
@@ -1,22 +1,13 @@
-********************************************
-Session Two: Functions, Booleans and Modules
-********************************************
-
-.. ifslides::
-
- .. rst-class:: center large
-
- Oh My!
-
+.. include:: include.rst
+****************************************************
+Session Two: gitHub, Functions, Booleans and Modules
+****************************************************
Review/Questions
================
-Review of Previous Session
---------------------------
-
-.. rst-class:: build
+.. rst-class:: left medium
* Values and Types
* Expressions
@@ -27,69 +18,321 @@ Homework Review
.. rst-class:: center large
-Any questions that are nagging?
+ Any questions that are nagging?
+Lightning Talks Today:
+----------------------
-Git Work
-========
+.. rst-class: medium
-.. rst-class:: center large
-Let's get to know your fellow students!
+|
+| David E Tobey
+|
+| Sharmila Muralidharan
+|
+| Shu A Latif
+|
+| Spencer G McGhin
+
+Class Outline
+-------------
+
+ * git / gitHub primer
+ * Exercise: :ref:`exercise_grid_printer`
+ * Decisions, Decisions.
+ * Exercise: :ref:`exercise_fizz_buzz`
+ * More on functions
+ * Exercise: :ref:`exercise_fibonacci`
+ * Boolean Expressions
+ * Code Structure, Modules, and Namespaces
+First a little git Primer...
+==============================
+
+Let's get to know git a bit
+
+
+Why Version Control?
+--------------------
+
+.. figure:: /_static/phd101212s.gif
+ :class: fill
+ :width: 45 %
+
+.. ifnotslides::
+
+ "Piled Higher and Deeper" by Jorge Cham
+
+ www.phdcomics.com
+
+What is git?
+------------
+.. rst-class:: build
-Working with an Upstream
-------------------------
+.. container::
-You've created a fork of the class repository from the ``codefellows`` account
-on GitHub.
+ A "version control system"
-You've pushed your own changes to that fork, and then issued pull requests to
-have that worked merged back to the ``codefellows`` original.
+ A history of everything everyone does to 'your' code
-You want to keep your fork up-to-date with that original copy as the class goes
-forward.
+ A graph of "states" in which the code has existed
-To do this, you use the git concept of an **upstream** repository.
+ That last one is a bit tricky, and is not necessary to understand right out of the gate. When you are ready, you can look at this supplement to gain a better understanding:
+
+ :ref: http://uwpce-pythoncert.github.io/PythonResources/DevEnvironment/git_overview.html
+
+Setting up git
+--------------
+
+You should have git installed on your machine and accessible from the command line. There will be a little bit of setup for git that you should only have to do once.
+
+.. code-block:: bash
+
+ $ git config --global user.name "Marie Curie"
+ $ git config --global user.email "marie@radioactive.com"
+
+Editor
+------
+
+* git needs an editor occasionally
+* default is VI, which is not very intuitive to non-Unix Geeks
+* Nano is simple, easy solution for Macs and Linux
+* Nano no longer available for windows, use Sublime or Notepad++
+
+
+For Windows users:
+ http://uwpce-pythoncert.github.io/PythonResources/Installing/git_editor_windows.html
.. nextslide::
+Once you have chosen/installed an editor, configure git to use it:
+
+nano
+``$ git config --global core.editor "nano -w"``
+
+sublime (mac)
+``$ git config --global core.editor "subl -n -w"``
+
+sublime (win)
+``$ git config --global core.editor "'c:/program files/sublime text 2/sublime_text.exe' -w"``
+
+Notepad++ (Win)
+``$ git config --global core.editor "'c:/program files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"``
+
+Repositories
+------------
+
+A repository is just a collection of files that 'belong together'.
+
Since ``git`` is a *distributed* versioning system, there is no **central**
-repository that serves as the one to rule them all.
+repository that serves as the one to rule them all. This simply means that all repositories should look the same.
-Instead, you work with *local* repositories, and *remotes* that they are
-connected to.
+However, to keep things sane, there is generally one "central" repository chosen that users check with for changes, for us this is GitHub.
-Cloned repositories get an *origin* remote for free:
-.. code-block:: bash
+Working with Remotes
+--------------------
+
+With git, you work with *local* repositories and *remotes* that they are connected to.
+
+.. rst-class:: build
+.. container::
+
+ Git uses shortcuts to address *remotes*. Cloned repositories get an *origin* shortcut for free:
+
+ .. code-block:: bash
+
+ $ git remote -v
+ origin https://github.com/UWPCE-PythonCert/IntroPython2016.git (fetch)
+ origin https://github.com/UWPCE-PythonCert/IntroPython2016.git (push)
+
+ This shows that the local repo on my machine *originated* from the one in
+ the UWPCE-PythonCert gitHub account (it shows up twice, because I there is
+ a shortcut for both fetch from and push to this remote)
+
+.. nextslide::
+
+.. rst-class:: build
+.. container::
+
+ You can work on any project you wish to that has a public repository on Github. However, since you won't have permission to edit most projects directly, there is such a thing as *forking* a project.
+
+ When you *fork* a repository, you make a copy of that repository in your own (Github) account.
+
+ When you have made changes that you believe the rest of the community will want to adopt, you make a *pull request* to the original project. The maintainer(s) of that project than have the option of accepting your changes, in which case your changes will become part of that project.
+
+ This is how we will be working in this class. When you want feedback on your work, you will make a *pull request* to the instructors.
+
+.. nextslide::
+
+Our class materials reside in a repository on *Github* in the *UWPCE-PythonCert* organization:
+
+.. figure:: /_static/remotes_start.png
+ :width: 50%
+ :class: center
+
+.. nextslide::
+
+Note that this is not the same repository as the class materials.
+
+It will be a repository that is created just for this class, and will be called IntroPython*quarter*.
+
+In examples below it is called IntroToPython, so replace that in your head with the name of this year's repository. :)
+
+We will create this repository now.
+
+.. nextslide::
+
+This new repository will include examples and we will add relevant materials (and exercise solutions) to it throughout the quarter.
+
+There will be a folder called students at the top level, and everyone will create their own directory within it.
+
+So, everyone will commit to this repository, and everyone will have access to everyone's code.
+
+This will make it easier to collaborate.
+
+We will do a live demo of setting up a machine now.
+
+.. nextslide::
+
+We will now create a fork of the class repository from the ``UWPCE-PythonCert``
+account on GitHub into your personal account. This is done on the GitHub website.
+
+Let's pause now to let you all create a gitHub account if you don't have one already.
+
+.. figure:: /_static/remotes_fork.png
+ :width: 50%
+ :class: center
+
+.. nextslide::
+
+The next step is to make a *clone* of your fork on your own computer, which means that **your fork** in github is the *origin* (Demo):
- $ git remote -v
- origin https://github.com/PythonCHB/sea-f2-python-sept14.git (fetch)
- origin https://github.com/PythonCHB/sea-f2-python-sept14.git (push)
+.. figure:: /_static/remotes_clone.png
+ :width: 50%
+ :class: center
-This shows that the local repo on my machine *originated* from the one in my gitHub account (the one it was cloned from)
+.. nextslide::
+
+We will now set up our individual folders and include a README in this folder.
+
+
+.. rst-class:: build
+.. container::
+
+ .. code-block:: bash
+
+ $ cd IntroPythonXXXX
+ $ git status
+
+ .. code-block:: bash
+
+ $ git pull origin master
+
+ .. code-block:: bash
+
+ $ cd students
+
+ .. code-block:: bash
+
+ $ mkdir maria_mckinley
+
+ .. code-block:: bash
+
+ $ cd maria_mckinley
+
+ .. code-block:: bash
+
+ $ echo "# Python code for UWPCE-PythonCert class" >> README.rst
+
+.. nextslide::
+
+.. rst-class:: build
+.. container::
+
+ Check the status
+
+ .. code-block:: bash
+
+ $ git status
+
+ Add anything you want to commit to your commit:
+
+ .. code-block:: bash
+
+ $ git add README.rst
+
+ Make your commit:
+
+ .. code-block:: bash
+
+ $ git commit -m 'added a readme file'
+
+
+.. nextslide::
+
+Push your changes:
+
+ .. code-block:: bash
+
+ $ git push origin master
+
+ origin is the default name given by git refering to the server you cloned
+ (in this case your github repository)
+
+ master is the branch that you are currently pushing to that server
+
+ Go onto GitHub, and make a pull request!
+
+ (This will be a pull request from a fork rather than from a branch)
+
+ https://help.github.com/articles/creating-a-pull-request-from-a-fork/
+
+
+.. nextslide::
+
+You've pushed your own changes to that fork, and then issued pull requests to have that work merged back to the ``UWPCE-PythonCert`` original.
+
+.. rst-class:: build
+.. container::
+
+ You want to keep your fork up-to-date with that original copy as the class
+ goes forward.
+
+ To do this, you add a new *remote* repository to your local clone.
.. nextslide:: Adding a Remote
You can add *remotes* at will, to connect your *local* repository to other
copies of it in different remote locations.
-This allows you to grab changes made to the repository in these other
-locations.
+.. rst-class:: build
+.. container::
-For our class, we will add an *upstream* remote to our local copy that points
-to the original copy of the material in the ``codefellows`` account.
+ This allows you to grab changes made to the repository in these other
+ locations.
-.. code-block:: bash
+ For our class, we will add an *upstream* remote to our local copy that points to the original copy of the material in the ``UWPCE-PythonCert`` account, and we will call it, appropriately, "upstream"
+
+ .. code-block:: bash
- $ git remote add upstream https://github.com/codefellows/sea-f2-python-sept14.git
+ $ git remote add upstream https://github.com/UWPCE-PythonCert/IntroPython2015.git
+
+ $ git remote -v
+ origin https://github.com/PythonCHB/IntroPython2015.git (fetch)
+ origin https://github.com/PythonCHB/IntroPython2015.git (push)
+ upstream https://github.com/UWPCE-PythonCert/IntroPython2015.git (fetch)
+ upstream https://github.com/UWPCE-PythonCert/IntroPython2015.git (push)
+
+.. nextslide::
+
+This should leave you in a situation that looks like this:
+
+.. figure:: /_static/remotes_upstream.png
+ :width: 50%
+ :class: center
- $ git remote -v
- origin https://github.com/PythonCHB/sea-f2-python-sept14.git (fetch)
- origin https://github.com/PythonCHB/sea-f2-python-sept14.git (push)
- upstream https://github.com/codefellows/sea-f2-python-sept14.git (fetch)
- upstream https://github.com/codefellows/sea-f2-python-sept14.git (push)
.. nextslide:: Fetching Everything.
@@ -109,13 +352,9 @@ Then you can see the branches you have locally available:
$ git branch -a
* master
remotes/origin/HEAD -> origin/master
- remotes/origin/gh-pages
remotes/origin/master
- remotes/upstream/gh-pages
remotes/upstream/master
-(the gh-pages branch is used to publish these notes)
-
.. nextslide:: Fetching Upstream Changes
Finally, you can fetch and then merge changes from the upstream master.
@@ -126,20 +365,16 @@ Start by making sure you are on your own master branch:
$ git checkout master
-This is **really really** important. Take the time to ensure you are where you
-think you are.
+This is **really really** important. Take the time to ensure you are where you think you are, iow, not on a remote. Use git status to find out where you are, if necesary.
.. nextslide:: Merging Upstream Changes
-Then, fetch the upstream master branch and merge it into your master:
+Then, fetch the upstream master branch and merge it into your master.
+You can do this in one step with:
.. code-block:: bash
- $ git fetch upstream master
- From https://github.com/codefellows/sea-f2-python-sept14
- * branch master -> FETCH_HEAD
-
- $ git merge upstream/master
+ $ git pull upstream master
Updating 3239de7..9ddbdbb
Fast-forward
Examples/README.rst | 4 ++++
@@ -147,15 +382,11 @@ Then, fetch the upstream master branch and merge it into your master:
create mode 100644 Examples/README.rst
...
-NOTE: you can do that in one step with:
-
-.. code-block:: bash
-
- $ git pull upstream master
.. nextslide:: Pushing to Origin
Now all the changes from *upstream* are present in your local clone.
+You should do this pull everytime you start to work on code.
In order to preserve them in your fork on GitHub, you'll have to push:
@@ -176,93 +407,152 @@ In order to preserve them in your fork on GitHub, you'll have to push:
You can incorporate this into your daily workflow: ::
+ [make sure you are on correct branch]
$ git checkout master
+ [get any changes from class repository]
$ git pull upstream master
- $ git push
- [do some work]
- $ git commit -a
+ [make sure you are in your student directory, do work]
+ [verify you are happy with changes]
+ $ git status
+ [add your changes to what will be committed]
+ $ git add .
[add a good commit message]
+ $ git commit -m 'I wrote some Python.'
+ [push your changes to your remote github account]
$ git push
- [make a pull request]
+ [make a pull request on the GitHub website]
-Quick Intro to Basics
-=====================
-.. rst-class:: center large
+.. nextslide:: Note
+
+Because of the way we have set up the class, you will be able
+to see all work submitted to us from everyone in the class in
+the students directory on your machine. This is not a bad thing.
+And the files tend to be small.
+
+We encourage sharing of knowledge in this class. Helping your
+fellow students will also help you to better understand. Share
+your code, and get use to giving/receiving feedback on how to
+improve your code, if you are not already.
+
+
+LAB: Grid Printer
+=================
+
+.. rst-class:: left
+
+ With only the ability to do a bit with numbers and text, you should be
+ able to do this little project:
+
+ :ref:`exercise_grid_printer`
+
+Getting Started:
+----------------
+
+Lets use git and gitHub to manage this project:
+
+Start by putting a python file in your clone of the class gitHub project:
+
+.. code-block:: bash
+
+ $ cd my_personal_directory
+ $ mkdir session_02
+ $ cd session_02
+ $ touch grid_printer.py
+ $ git add grid_printer.py
+
+Then put your code in grid_printer.py
+
+Committing your code
+--------------------
+
+When your code does something useful, you can commit it.
+
+First check the status:
+
+.. code-block:: bash
+
+ $ git status
+
+If it's what you expect, you can commit and push:
+
+.. code-block:: bash
+
+ $ git commit -a -m "first version"
+ $ git push
+
+And when you want us to take a look, you can go to gitHub and do a "Pull Request"
+(make sure you commit and push first)
+
+
+Committing your code
+--------------------
+
+Commit early and often.
+
+
+Lightning Talk:
+---------------
+
+.. rst-class:: center medium
+
+David E Tobey
+
+
+Beyond Printing
+================
+
+.. rst-class:: center medium
Because there's a few things you just gotta have
Basics
------
-It turns out you can't really do much at all without at least a container type,
-conditionals and looping...
+You really can't really do much at all without at least
+conditionals, looping, and a container type...
-.. nextslide:: if
+Making a Decision
+------------------
-``if`` and ``elif`` allow you to make decisions:
+**"Conditionals"**
+
+``if`` and ``elif`` (else if) allow you to make decisions:
.. code-block:: python
if a:
- print 'a'
+ print('a')
elif b:
- print 'b'
+ print('b')
elif c:
- print 'c'
+ print('c')
else:
- print 'that was unexpected'
+ print('that was unexpected')
.. nextslide:: if
-What's the difference between these two:
+What's the difference between these two?
.. code-block:: python
if a:
- print 'a'
+ print('a')
elif b:
- print 'b'
+ print('b')
+
## versus...
if a:
- print 'a'
+ print('a')
if b:
- print 'b'
-
-
-.. nextslide:: switch?
-
-Many languages have a ``switch`` construct:
+ print('b')
-.. code-block:: js
- switch (expr) {
- case "Oranges":
- document.write("Oranges are $0.59 a pound. ");
- break;
- case "Apples":
- document.write("Apples are $0.32 a pound. ");
- break;
- case "Mangoes":
- case "Papayas":
- document.write("Mangoes and papayas are $2.79 a pound. ");
- break;
- default:
- document.write("Sorry, we are out of " + expr + ". ");
- }
-.. nextslide:: switch?
-
-**Not Python**
-
-use ``if..elif..elif..else``
-
-(or a dictionary, or subclassing....)
-
-
-.. nextslide:: lists
+Lists
+-----
A way to store a bunch of stuff in order
@@ -273,8 +563,10 @@ Pretty much like an "array" or "vector" in other languages
a_list = [2,3,5,9]
a_list_of_strings = ['this', 'that', 'the', 'other']
+You can put any type of object in a list...
-.. nextslide:: tuples
+Tuples
+-------
Another way to store an ordered list of things
@@ -283,24 +575,27 @@ Another way to store an ordered list of things
a_tuple = (2,3,4,5)
a_tuple_of_strings = ('this', 'that', 'the', 'other')
+You can also put any type of object in a tuple...
+(sense a theme here?)
Tuples are **not** the same as lists.
The exact difference is a topic for next session.
-.. nextslide:: for
+``for`` loops
+--------------
Sometimes called a 'determinate' loop
-When you need to do something to everything in a sequence
+When you need to do something to all the objects in a sequence
.. code-block:: ipython
In [10]: a_list = [2,3,4,5]
In [11]: for item in a_list:
- ....: print item
+ ....: print(item)
....:
2
3
@@ -308,24 +603,26 @@ When you need to do something to everything in a sequence
5
-.. nextslide:: range() and for
+``range()`` and for
+-------------------
-Range builds lists of numbers automatically
+``range`` builds sequences of numbers automatically
Use it when you need to do something a set number of times
.. code-block:: ipython
- In [12]: range(6)
- Out[12]: [0, 1, 2, 3, 4, 5]
-
- In [13]: for i in range(6):
- ....: print "*",
+ In [31]: for i in range(4):
+ print('*', end=' ')
....:
- * * * * * *
+ * * * *
+
+NOTE: ``range(n)`` creates an "iterable" -- something you can loop over
+-- more on that later.
-.. nextslide:: Intricacies
+Intricacies
+------------
This is enough to get you started.
@@ -334,28 +631,47 @@ Each of these have intricacies special to python
We'll get to those over the next couple of classes
-Functions
-=========
+LAB: Fizz Buzz
+===============
-Review
-------
+.. rst-class:: left
+
+ We now have the tools to do a implementation of the classic "Fizz Buzz" problem:
+
+ :ref:`exercise_fizz_buzz`
+
+ Do the same git / gitHub dance with this, too!
+
+
+Lightning Talk:
+---------------
+
+.. rst-class:: center medium
+
+Sharmila Muralidharan
+
+
+More on Functions
+=================
+
+Variable scope
+--------------
Defining a function:
.. code-block:: python
def fun(x, y):
- z = x+y
+ z = x + y
return z
-
x, y, z are *local* names
Local vs. Global
----------------
-Symbols bound in Python have a *scope*
+Names bound in Python have a *scope*
That *scope* determines where a symbol is visible, or what value it has in a
given block.
@@ -366,7 +682,7 @@ given block.
In [15]: y = 33
In [16]: z = 34
In [17]: def fun(y, z):
- ....: print x, y, z
+ ....: print(x, y, z)
....:
In [18]: fun(3, 4)
32 3 4
@@ -390,8 +706,8 @@ But, did the value of y and z change in the *global* scope?
In general, you should use global bindings mostly for constants.
-In python we designate global constants by typing the symbols we bind to them
-in ALL_CAPS
+The python convention is to designate global constants by typing the
+symbols we bind to them in ALL_CAPS
.. code-block:: python
@@ -402,7 +718,8 @@ in ALL_CAPS
This is just a convention, but it's a good one to follow.
-.. nextslide:: Global Gotcha
+Global Gotcha
+--------------
Take a look at this function definition:
@@ -413,8 +730,8 @@ Take a look at this function definition:
In [22]: def f():
....: y = x
....: x = 5
- ....: print x
- ....: print y
+ ....: print(x)
+ ....: print(y)
....:
What is going to happen when we call ``f``
@@ -425,18 +742,18 @@ Try it and see:
.. code-block:: ipython
- In [23]: f()
+ In [34]: f()
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
- in ()
+ in ()
----> 1 f()
- in f()
+ in f()
1 def f():
----> 2 y = x
3 x = 5
- 4 print x
- 5 print y
+ 4 print(x)
+ 5 print(y)
UnboundLocalError: local variable 'x' referenced before assignment
@@ -452,7 +769,7 @@ So far we've seen simple parameter lists:
.. code-block:: python
def fun(x, y, z):
- print x, y, z
+ print(x, y, z)
These types of parameters are called *positional*
@@ -467,7 +784,7 @@ You can provide *default values* for parameters in a function definition:
.. code-block:: ipython
In [24]: def fun(x=1, y=2, z=3):
- ....: print x, y, z
+ ....: print(x, y, z)
....:
When parameters are given with default values, they become *optional*
@@ -511,29 +828,6 @@ provide any *positional* arguments:
fun(x=5, 6)
SyntaxError: non-keyword arg after keyword arg
-.. nextslide:: Parameters and Unpacking
-
-This brings us to a fun feature of Python function definitions.
-
-You can define a parameter list that requires an **unspecified** number of
-*positional* or *keyword* arguments.
-
-The key is the ``*`` (splat) or ``**`` (double-splat) operator:
-
-.. code-block:: ipython
-
- In [31]: def fun(*args, **kwargs):
- ....: print args, kwargs
- ....:
- In [32]: fun(1)
- (1,) {}
- In [33]: fun(1, 2, zombies="brains")
- (1, 2) {'zombies': 'brains'}
- In [34]: fun(1, 2, 3, zombies="brains", vampires="blood")
- (1, 2, 3) {'vampires': 'blood', 'zombies': 'brains'}
-
-**args** and **kwargs** are *conventional* names for these.
-
Documentation
-------------
@@ -547,8 +841,6 @@ This can help reduce the number of `WTFs per minute`_ in reading it later.
There are two approaches to this:
-.. rst-class:: build
-
* Comments
* Docstrings
@@ -568,11 +860,11 @@ You can use them to mark places you want to revisit later:
.. code-block:: python
for partygoer in partygoers:
- for baloon in baloons:
+ for balloon in balloons:
for cupcake in cupcakes:
# TODO: Reduce time complexity here. It's killing us
# for large parties.
- resolve_party_favor(partygoer, baloon, cupcake)
+ resolve_party_favor(partygoer, balloon, cupcake)
.. nextslide:: Comments
@@ -590,10 +882,12 @@ This is not useful:
# apply soap to each sponge
worker.apply_soap(sponge)
-.. nextslide:: Docstrings
+Note: Nothing special about Python here -- basic good programing practice.
+
+Docstrings
+----------
-In Python, ``docstrings`` are used to provide in-line documentation in a number
-of places.
+In Python, ``docstrings`` are used to provide in-line documentation in a number of places.
The first place we will see is in the definition of ``functions``.
@@ -611,24 +905,23 @@ header, it is a ``docstring``:
You can then read this in an interpreter as the ``__doc__`` attribute of the
function object.
-.. nextslide:: Docstrings
+.. nextslide::
A ``docstring`` should:
-.. rst-class:: build
-* be a complete sentence in the form of a command describing what the function
+* Be a complete sentence in the form of a command describing what the function
does.
* """Return a list of values based on blah blah""" is a good docstring
* """Returns a list of values based on blah blah""" is *not*
-* fit onto a single line.
+* Have a useful single line.
* If more description is needed, make the first line a complete sentence and
add more lines below for enhancement.
-* be enclosed with triple-quotes.
+* Be enclosed with triple-quotes.
* This allows for easy expansion if required at a later date
* Always close on the same line if the docstring is only one line.
@@ -658,8 +951,7 @@ Recursion is especially useful for a particular set of problems.
For example, take the case of the *factorial* function.
-In mathematics, the *factorial* of an integer is the result of multiplying that
-integer by every integer smaller than it down to 1.
+In mathematics, the *factorial* of an integer is the result of multiplying that integer by every integer smaller than it down to 1.
::
@@ -673,26 +965,46 @@ We can use a recursive function nicely to model this mathematical function
[demo]
+``assert``
+----------
-In-Class Lab:
-=============
+Writing ``tests`` that demonstrate that your program works is an important part of learning to program.
-.. rst-class:: center large
+The python ``assert`` statement is useful in writing simple tests
+for your code.
-Fun With Functions
+.. code-block:: ipython
-Exercises
----------
+ In [1]: def add(n1, n2):
+ ...: return n1 + n2
+ ...:
-Try your hand at writing a function that computes the distance between two
-points::
+ In [2]: assert add(3, 4) == 7
- dist = sqrt( (x1-x2)**2 + (y1-y2)**2 )
+ In [3]: assert add(3, 4) == 10
-Experiment with ``locals`` by adding this statement to the function you just
-wrote:::
+ ---------------------------------------------------------------------
+ AssertionError Traceback (most recent call last)
+ in ()
+ ----> 1 assert add(3, 4) == 10
- print locals()
+ AssertionError:
+
+
+LAB: Fibonacci
+==============
+
+Let's write a few functions in class:
+
+:ref:`exercise_fibonacci`
+
+
+Lightning Talk:
+---------------
+
+.. rst-class:: center medium
+
+Shu A Latif
Boolean Expressions
@@ -703,11 +1015,11 @@ Truthiness
What is true or false in Python?
-.. rst-class:: build
+* The Booleans: ``True`` and ``False``
-* The Booleans: ``True`` and ``False``
* "Something or Nothing"
-* http://mail.python.org/pipermail/python-dev/2002-April/022107.html
+
+* http://mail.python.org/pipermail/python-dev/2002-April/022107.html
.. nextslide::
@@ -719,36 +1031,37 @@ Determining Truthiness:
bool(something)
-.. nextslide:: What is False?
+What is False?
+--------------
-.. rst-class:: build
+* ``None``
+
+* ``False``
-* ``None``
-* ``False``
* **Nothing:**
-* zero of any numeric type: ``0, 0L, 0.0, 0j``.
-* any empty sequence, for example, ``"", (), []``.
-* any empty mapping, for example, ``{}`` .
-* instances of user-defined classes, if the class defines a ``__nonzero__()``
- or ``__len__()`` method, when that method returns the integer zero or bool
- value ``False``.
+ - Zero of any numeric type: ``0, 0L, 0.0, 0j``.
+ - Any empty sequence, for example, ``"", (), []``.
+ - Any empty mapping, for example, ``{}`` .
+ - Instances of user-defined classes, if the class defines a ``__nonzero__()`` or ``__len__()`` method, when that method returns the integer zero or bool value ``False``.
* http://docs.python.org/library/stdtypes.html
-.. nextslide:: What is True?
+What is True?
+-------------
.. rst-class:: center large
Everything Else
-.. nextslide:: Pythonic Booleans
+Pythonic Booleans
+-----------------
Any object in Python, when passed to the ``bool()`` type object, will
evaluate to ``True`` or ``False``.
-When you use the ``if`` keyword, it automatically does this to the statement provided.
+When you use the ``if`` keyword, it automatically does this to the expression provided.
Which means that this is redundant, and not Pythonic:
@@ -768,8 +1081,8 @@ Instead, use what Python gives you:
do_something()
-and, or and not
-----------------
+``and``, ``or`` and ``not``
+---------------------------
Python has three boolean keywords, ``and``, ``or`` and ``not``.
@@ -816,12 +1129,12 @@ statements:
else return x
if x is false,
- x and y return x
- else return y
+ x and y return x
+ else return y
if x is false,
- not x return True,
- else return False
+ not x return True,
+ else return False
.. nextslide:: Chaining
@@ -836,12 +1149,13 @@ The first value that defines the result is returned
.. ifslides::
- .. rst-class:: centered
+ .. rst-class:: centered large
(demo)
-.. nextslide:: Ternary Expressions
+Ternary Expressions
+-------------------
This is a fairly common idiom:
@@ -869,7 +1183,7 @@ PEP 308:
Boolean Return Values
---------------------
-Remember this puzzle from your CodingBat exercises?
+Remember this puzzle from the CodingBat exercises?
.. code-block:: python
@@ -925,29 +1239,26 @@ And you can even do math with them (though it's a bit odd to do so):
(demo)
-In-Class Lab:
-=============
+Lightning Talk:
+---------------
-.. rst-class:: center large
+.. rst-class:: center medium
-Better With Booleans
+Spencer G McGhin
-Exercises
----------
- * Look up the ``%`` operator. What do these do?
+LAB: Booleans
+=============
+
+.. rst-class:: left
+
+ Working with Booleans, Ternary Expressions, etc:
+
+ Re-write a couple CodingBat exercises, returning the direct boolean results, and/or using ternary expressions.
- * ``10 % 7 == 3``
- * ``14 % 7 == 0``
- * Write a program that prints the numbers from 1 to 100 inclusive. But for
- multiples of three print "Fizz" instead of the number and for the
- multiples of five print "Buzz". For numbers which are multiples of both
- three and five print "FizzBuzz" instead.
- * Re-write a couple of CodingBat exercises, using a conditional expression
- * Re-write a couple of CodingBat exercises, returning the direct boolean results
+ Experiment with ``locals`` by adding this statement one of the functions you wrote today::
-use whichever you like, or the ones in:
-:download:`codingbat.rst <../code/session02/codingbat.rst>`
+ print(locals())
Code Structure, Modules, and Namespaces
@@ -983,7 +1294,7 @@ You can put a one-liner after the colon:
.. code-block:: ipython
In [167]: x = 12
- In [168]: if x > 4: print x
+ In [168]: if x > 4: print(x)
12
But this should only be done if it makes your code **more** readable.
@@ -1077,7 +1388,8 @@ inside it.
(demo)
-.. nextslide:: importing from packages
+importing from packages
+-----------------------
.. code-block:: python
@@ -1093,7 +1405,7 @@ inside it.
http://effbot.org/zone/import-confusion.htm
-.. nextslide:: importing from packages
+.. nextslide::
.. code-block:: python
@@ -1104,21 +1416,22 @@ http://effbot.org/zone/import-confusion.htm
**Don't do this!**
-Import
-------
+``import``
+----------
When you import a module, or a symbol from a module, the Python code is
*compiled* to **bytecode**.
The result is a ``module.pyc`` file.
-This process **executes all code at the module scope**.
+Then after compiling, all the code in the module is run **at the module scope**.
For this reason, it is good to avoid module-scope statements that have global
side-effects.
-.. nextslide:: Re-import
+Re-import
+----------
The code in a module is NOT re-run when imported again
@@ -1126,8 +1439,8 @@ It must be explicitly reloaded to be re-run
.. code-block:: python
- import modulename
- reload(modulename)
+ import importlib
+ importlib.reload(modulename)
.. ifslides::
@@ -1150,7 +1463,7 @@ There are a few ways to do this:
* ``In [149]: run hello.py`` -- at the IPython prompt -- running a module brings its names into the interactive namespace
-.. nextslide:: Running a Module
+.. nextslide
Like importing, running a module executes all statements at the module level.
@@ -1161,8 +1474,7 @@ is the same as the filename.
When you *run* a module, the value of the symbol ``__name__`` is ``__main__``.
-This allows you to create blocks of code that are executed *only when you run a
-module*
+This allows you to create blocks of code that are executed *only when you run a module*
.. code-block:: python
@@ -1174,7 +1486,7 @@ module*
This is useful in a number of cases.
-You can put code here that lets your module be a utility script
+You can put code here that lets your module be a utility *script*
You can put code here that demonstrates the functions contained in your module
@@ -1185,39 +1497,11 @@ You can put code here that proves that your module works.
[demo]
-.. nextslide:: ``Assert``
-
-Writing ``tests`` that demonstrate that your program works is an important part
-of learning to program.
-
-The python ``assert`` statement is useful in writing ``main`` blocks that test
-your code.
-
-.. code-block:: ipython
-
- In [1]: def add(n1, n2):
- ...: return n1 + n2
- ...:
-
- In [2]: assert add(3, 4) == 7
-
- In [3]: assert add(3, 4) == 10
- ---------------------------------------------------------------------------
- AssertionError Traceback (most recent call last)
- in ()
- ----> 1 assert add(3, 4) == 10
-
- AssertionError:
-
-In-Class Lab
-============
Import Interactions
+-------------------
-Exercises
----------
-
-Experiment with importing different ways:
+Let's experiment with importing different ways:
.. code-block:: ipython
@@ -1257,10 +1541,9 @@ Experiment with importing different ways:
.. code-block:: python
import sys
- print sys.path
+ print(sys.path)
import os
- print os.path
-
+ print(os.path)
You wouldn't want to import * those!
@@ -1271,109 +1554,48 @@ You wouldn't want to import * those!
os.path.split('/foo/bar/baz.txt')
os.path.join('/foo/bar', 'baz.txt')
-Homework
-========
-
-You have two tasks to complete by next class:
-
-Task 1
-------
-
-The Ackermann function, A(m, n), is defined::
-
- A(m, n) =
- n+1 if m = 0
- A(m−1, 1) if m > 0 and n = 0
- A(m−1, A(m, n−1)) if m > 0 and n > 0.
-
-See http://en.wikipedia.org/wiki/Ackermann_function.
-Create a new module called ``ack.py`` in a ``session02`` folder in your student folder. In that module, write a function named ``ack`` that performs Ackermann's function.
+Next Class
+==========
-* Write a good ``docstring`` for your function according to PEP 257.
-* Ackermann's function is not defined for input values less than 0. Validate
- inputs to your function and return None if they are negative.
+.. rst-class left
-.. nextslide::
-
-The wikipedia page provides a table of output values for inputs between 0 and
-4. Using this table, add a ``if __name__ == "__main__":`` block to test your
-function.
-
-Test each pair of inputs between 0 and 4 and assert that the result produced by
-your function is the result expected by the wikipedia table.
-
-When your module is run from the command line, these tests should be executed.
-If they all pass, print "All Tests Pass" as the result.
-
-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. Then make a pull request and submit your assignment in Canvas.
-
-::
-
- - Adapted from "Think Python": Chapter 6, exercise 5.
-
-Task 2
-------
-
-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, ...
-
-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``
+* Sequences
+* Iteration
+* Strings and String Formatting
-.. _Fibonacci Series: http://en.wikipedia.org/wiki/Fibbonaci_Series
+* Lightning talks by:
-.. nextslide::
+ - Beatrice He
+ - Bradley I Baumel
+ - Jerry Bearer
+ - Sheree Pena
-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, ...
+Office hours: Sunday 10:00 -- 12:00
-.. _Lucas Numbers: http://en.wikipedia.org/wiki/Lucas_number
-In your ``series.py`` module, add a new function ``lucas`` that returns the
-``nth`` value in the *lucas numbers*
+Homework
+---------
-Ensure that your function has a well-formed ``docstring``
+Review and/or finish reading these class notes.
-.. nextslide::
+Finish any labs from class....
-Both the *fibonacci series* and the *lucas numbers* are based on an identical
-formula.
+**Reading:**
-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.
+Think Python, chapters 8, 9, 10, 12
-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.
+(http://greenteapress.com/thinkpython/html/thinkpython009.html)
-Ensure that your function has a well-formed ``docstring``
+Learn Python the Hard way: exercises 11 -- 14, 18, 19, 21, 28-33
+(the ones in between are about files -- we'll get to that later.)
-.. nextslide::
+http://learnpythonthehardway.org/book/ex11.html
-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.
+NOTE: In python3, you use ``input``, rather than ``raw_input``
-Use comments in this block to inform the observer what your tests do.
+Dive Into Python: chapter 4
-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*.
+(http://www.diveintopython3.net/strings.html)
-When you are finished, push your changes to your fork of the class repository
-in GitHub. Then make a pull request and submit your assignment in Canvas.
diff --git a/slides_sources/source/session03.rst b/slides_sources/source/session03.rst
index 3bed59d1..bd58f2ff 100644
--- a/slides_sources/source/session03.rst
+++ b/slides_sources/source/session03.rst
@@ -1,3 +1,5 @@
+.. include:: include.rst
+
*********************************************************
Session Three: Sequences, Iteration and String Formatting
*********************************************************
@@ -8,20 +10,47 @@ Review/Questions
Review of Previous Session
--------------------------
-.. rst-class:: build
-
* Functions
+
+ - recursion
+ - optional arguments
+
* Booleans
+
+ - if and conditional expressions
+
* Modules
Homework Review
---------------
+* FizzBuzz
+
+* Series
+
.. rst-class:: center large
Any questions that are nagging?
+git
+---
+
+.. rst-class:: center large
+
+ OK -- we'll answer git questions...
+
+Lightning Talks Today:
+----------------------
+
+.. rst-class:: mlarge
+
+|
+| Beatrice He
+| Bradley I Baumel
+| Jerry Bearer
+| Sheree Pena
+
Sequences
=========
@@ -34,7 +63,9 @@ Ordered collections of objects
What is a Sequence?
-------------------
-Remember Duck Typing? A *sequence* can be considered as anything that supports
+Remember Duck Typing?
+
+A *sequence* can be considered as anything that supports
*at least* these operations:
.. rst-class:: build
@@ -50,37 +81,38 @@ Remember Duck Typing? A *sequence* can be considered as anything that supports
Sequence Types
--------------
-There are seven builtin types in Python that are *sequences*:
+There are eight builtin types in Python that are *sequences*:
-* strings
-* Unicode strings
-* lists
-* tuples
-* bytearrays
-* buffers
-* array.arrays
-* xrange objects (almost)
+* string
+* list
+* tuple
+* bytes
+* bytearray
+* buffer
+* array.array
+* range object (almost)
-For this class, you won't see much beyond the string types, lists, tuples -- the rest are pretty special purpose.
+For this class, you won't see much beyond string, lists, and tuples --
+the rest are pretty special purpose.
-But what we say today applies to all sequences (with minor caveats)
+But what we learn today applies to all sequences (with minor caveats)
Indexing
--------
-Items in a sequence may be looked up by *index* using the subscription
+Items in a sequence may be looked up by *index* using the indexing
operator: ``[]``
Indexing in Python always starts at zero.
.. code-block:: ipython
- In [98]: s = u"this is a string"
+ In [98]: s = "this is a string"
In [99]: s[0]
- Out[99]: u't'
+ Out[99]: 't'
In [100]: s[5]
- Out[100]: u'i'
+ Out[100]: 'i'
.. nextslide::
@@ -89,11 +121,16 @@ You can use negative indexes to count from the end:
.. code-block:: ipython
- In [105]: s = u"this is a string"
- In [106]: s[-1]
- Out[106]: u'g'
- In [107]: s[-6]
- Out[107]: u's'
+ In [2]: a_list = [34, 56, 19, 23, 55]
+
+ In [3]: a_list[-1]
+ Out[3]: 55
+
+ In [4]: a_list[-2]
+ Out[4]: 23
+
+ In [5]: a_list[-4]
+ Out[5]: 56
.. nextslide::
@@ -101,45 +138,46 @@ Indexing beyond the end of a sequence causes an IndexError:
.. code-block:: ipython
- In [4]: s = [0, 1, 2, 3]
- In [5]: s[4]
+ In [6]: a_list
+ Out[6]: [34, 56, 19, 23, 55]
+
+ In [7]: a_list[5]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
- in ()
- ----> 1 s[4]
+ in ()
+ ----> 1 a_list[5]
IndexError: list index out of range
-
Slicing
-------
Slicing a sequence creates a new sequence with a range of objects from the
original sequence.
-It also uses the subscription operator (``[]``), but with a twist.
+It also uses the indexing operator (``[]``), but with a twist.
``sequence[start:finish]`` returns all sequence[i] for which start <= i < finish:
.. code-block:: ipython
- In [121]: s = u"a bunch of words"
+ In [121]: s = "a bunch of words"
In [122]: s[2]
- Out[122]: u'b'
+ Out[122]: 'b'
In [123]: s[6]
- Out[123]: u'h'
+ Out[123]: 'h'
In [124]: s[2:6]
- Out[124]: u'bunc'
+ Out[124]: 'bunc'
In [125]: s[2:7]
- Out[125]: u'bunch'
+ Out[125]: 'bunch'
.. nextslide:: Helpful Hint
Think of the indexes as pointing to the spaces between the items::
- a b u n c h o f
- | | | | | | | | | |
- 0 1 2 3 4 5 6 7 8 9
+ a b u n c h o f w o r d s
+ | | | | | | | | | | | | | | | |
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@@ -149,11 +187,11 @@ You do not have to provide both ``start`` and ``finish``:
.. code-block:: ipython
- In [6]: s = u"a bunch of words"
+ In [6]: s = "a bunch of words"
In [7]: s[:5]
- Out[7]: u'a bun'
+ Out[7]: 'a bun'
In [8]: s[5:]
- Out[8]: u'ch of words'
+ Out[8]: 'ch of words'
Either ``0`` or ``len(s)`` will be assumed, respectively.
@@ -161,11 +199,11 @@ You can combine this with the negative index to get the end of a sequence:
.. code-block:: ipython
- In [4]: s = u'this_could_be_a_filename.txt'
+ In [4]: s = 'this_could_be_a_filename.txt'
In [5]: s[:-4]
- Out[5]: u'this_could_be_a_filename'
+ Out[5]: 'this_could_be_a_filename'
In [6]: s[-4:]
- Out[6]: u'.txt'
+ Out[6]: '.txt'
Why start from zero?
@@ -173,11 +211,11 @@ Why start from zero?
Python indexing feels 'weird' to some folks -- particularly those that don't come with a background in the C family of languages.
-Why is the "first" item indexed with zero?
+Why is the "first" item indexed with **zero**?
Why is the last item in the slice **not** included?
-Because these lead to some nifty properties::
+*Because* these lead to some nifty properties::
len(seq[a:b]) == b-a
@@ -197,16 +235,20 @@ returned:
.. code-block:: ipython
- In [289]: string = u"a fairly long string"
- In [290]: string[0:15]
- Out[290]: u'a fairly long s'
- In [291]: string[0:15:2]
- Out[291]: u'afil ogs'
- In [292]: string[0:15:3]
- Out[292]: u'aallg'
- In [293]: string[::-1]
- Out[293]: u'gnirts gnol ylriaf a'
+ In [18]: a_tuple
+ Out[18]: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
+
+ In [19]: a_tuple[0:15]
+ Out[19]: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
+
+ In [20]: a_tuple[0:15:2]
+ Out[20]: (0, 2, 4, 6, 8, 10, 12, 14)
+ In [21]: a_tuple[0:15:3]
+ Out[21]: (0, 3, 6, 9, 12)
+
+ In [22]: a_tuple[::-1]
+ Out[22]: (19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
.. nextslide:: Slicing vs. Indexing
@@ -228,7 +270,7 @@ Indexing past the end of a sequence will raise an error, slicing will not:
In [131]: s[10:20]
Out[131]: ' words'
In [132]: s[20:30]
- Out[132]: "
+ Out[132]: ''
(demo)
@@ -255,8 +297,8 @@ other languages:
.. code-block:: ipython
- In [20]: s = u"This is a long string"
- In [21]: u"long" in s
+ In [20]: s = "This is a long string"
+ In [21]: "long" in s
Out[21]: True
This does not work for sub-sequences of other types (can you think of why?):
@@ -275,13 +317,12 @@ Using ``+`` or ``*`` on sequences will *concatenate* them:
.. code-block:: ipython
- In [25]: s1 = u"left"
- In [26]: s2 = u"right"
- In [27]: s1 + s2
- Out[27]: u'leftright'
- In [28]: (s1 + s2) * 3
- Out[28]: u'leftrightleftrightleftright'
-
+ In [18]: l1 = [1,2,3,4]
+ In [19]: l2 = [5,6,7,8]
+ In [20]: l1 + l2
+ Out[20]: [1, 2, 3, 4, 5, 6, 7, 8]
+ In [21]: (l1+l2) * 2
+ Out[21]: [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8]
.. nextslide:: Multiplying and Slicing
@@ -312,12 +353,11 @@ All sequences have a length. You can get it with the ``len`` builtin:
.. code-block:: ipython
- In [36]: s = u"how long is this, anyway?"
+ In [36]: s = "how long is this, anyway?"
In [37]: len(s)
Out[37]: 25
-Remember, Python sequences are zero-indexed, so the last index in a sequence is
-``len(s) - 1``:
+Remember: Sequences are 0-indexed, so the last index is ``len(s)-1``:
.. code-block:: ipython
@@ -343,34 +383,34 @@ All sequences also support the ``min`` and ``max`` builtins:
.. code-block:: ipython
- In [42]: all_letters = u"thequickbrownfoxjumpedoverthelazydog"
+ In [42]: all_letters = "thequickbrownfoxjumpedoverthelazydog"
In [43]: min(all_letters)
- Out[43]: u'a'
+ Out[43]: 'a'
In [44]: max(all_letters)
- Out[44]: u'z'
+ Out[44]: 'z'
-Why are those the answers you get? (hint: ``ord(u'a')``)
+Why are those the answers you get? (hint: ``ord('a')``)
+Of course this works with numbers, too!
.. nextslide:: Index
-All sequences also support the ``index`` method, which returns the index of the
-first occurence of an item in the sequence:
+All sequences also support the ``index`` method, which returns the index of the first occurence of an item in the sequence:
.. code-block:: ipython
- In [46]: all_letters.index(u'd')
+ In [46]: all_letters.index('d')
Out[46]: 21
This causes a ``ValueError`` if the item is not in the sequence:
.. code-block:: ipython
- In [47]: all_letters.index(u'A')
+ In [47]: all_letters.index('A')
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
in ()
- ----> 1 all_letters.index(u'A')
+ ----> 1 all_letters.index('A')
ValueError: substring not found
@@ -381,25 +421,47 @@ appears:
.. code-block:: ipython
- In [52]: all_letters.count(u'o')
+ In [52]: all_letters.count('o')
Out[52]: 4
- In [53]: all_letters.count(u'the')
+ In [53]: all_letters.count('the')
Out[53]: 2
This does not raise an error if the item you seek is not present:
.. code-block:: ipython
- In [54]: all_letters.count(u'A')
+ In [54]: all_letters.count('A')
Out[54]: 0
Iteration
---------
-.. rst-class:: center large
+.. rst-class:: center mlarge
+
+ All sequences are "iterables" --
+
+ More on this in a while.
+
+Slicing LAB
+===========
+
+.. rst-class:: center medium
+
+ Let's practice Slicing!
+
+ :ref:`exercise_slicing`
+
+
+Lightning Talks
+----------------
-More on this in a while.
+|
+| Beatrice He
+|
+|
+| Bradley Baumel
+|
Lists, Tuples...
@@ -407,7 +469,7 @@ Lists, Tuples...
.. rst-class:: center large
-The *other* sequence types.
+The *primary* sequence types.
Lists
-----
@@ -434,6 +496,7 @@ Or by using the ``list`` type object as a constructor:
In [8]: list('abc')
Out[8]: ['a', 'b', 'c']
+It will take any "iterable"
.. nextslide:: List Elements
@@ -446,13 +509,13 @@ multiple names (or no name)
.. code-block:: ipython
- In [9]: name = u'Brian'
+ In [9]: name = 'Brian'
In [10]: a = [1, 2, name]
In [11]: b = [3, 4, name]
In [12]: a[2]
- Out[12]: u'Brian'
+ Out[12]: 'Brian'
In [13]: b[2]
- Out[13]: u'Brian'
+ Out[13]: 'Brian'
In [14]: a[2] is b[2]
Out[14]: True
@@ -497,14 +560,13 @@ But they *do* need commas...!
In [156]: t = ( 3 )
In [157]: type(t)
Out[157]: int
- In [158]: t = (3,)
+ In [158]: t = ( 3, )
In [160]: type(t)
Out[160]: tuple
.. nextslide:: Converting to Tuple
-You can also use the ``tuple`` type object to convert any sequence into a
-tuple:
+You can also use the ``tuple`` type object to convert any iterable(sequence) into a tuple:
.. code-block:: ipython
@@ -527,12 +589,12 @@ multiple names (or no name)
.. code-block:: ipython
- In [23]: name = u'Brian'
+ In [23]: name = 'Brian'
In [24]: other = name
In [25]: a = (1, 2, name)
In [26]: b = (3, 4, other)
In [27]: for i in range(3):
- ....: print a[i] is b[i],
+ ....: print(a[i] is b[i], end=' ')
....:
False False True
@@ -540,7 +602,7 @@ multiple names (or no name)
.. rst-class:: center large
-So Why Have Both?
+ So Why Have Both?
Mutability
@@ -569,18 +631,18 @@ Objects which are mutable may be *changed in place*.
Objects which are immutable may not be changed.
+Ever.
.. nextslide:: The Types We Know
-========= =======
+========= ===========
Immutable Mutable
-========= =======
-Unicode List
-String
-Integer
+========= ===========
+String List
+Integer Dictionary
Float
Tuple
-========= =======
+========= ===========
.. nextslide:: Lists Are Mutable
@@ -589,12 +651,12 @@ Try this out:
.. code-block:: ipython
- In [28]: food = [u'spam', u'eggs', u'ham']
+ In [28]: food = ['spam', 'eggs', 'ham']
In [29]: food
- Out[29]: [u'spam', u'eggs', u'ham']
- In [30]: food[1] = u'raspberries'
+ Out[29]: ['spam', 'eggs', 'ham']
+ In [30]: food[1] = 'raspberries'
In [31]: food
- Out[31]: [u'spam', u'raspberries', u'ham']
+ Out[31]: ['spam', 'raspberries', 'ham']
.. nextslide:: Tuples Are Not
@@ -603,14 +665,14 @@ And repeat the exercise with a Tuple:
.. code-block:: ipython
- In [32]: food = (u'spam', u'eggs', u'ham')
+ In [32]: food = ('spam', 'eggs', 'ham')
In [33]: food
- Out[33]: (u'spam', u'eggs', u'ham')
- In [34]: food[1] = u'raspberries'
+ Out[33]: ('spam', 'eggs', 'ham')
+ In [34]: food[1] = 'raspberries'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in ()
- ----> 1 food[1] = u'raspberries'
+ ----> 1 food[1] = 'raspberries'
TypeError: 'tuple' object does not support item assignment
@@ -665,7 +727,7 @@ Easy container setup, or deadly trap?
In [14]: bins
Out[14]: [[], [], [], [], []]
- In [15]: words = [u'one', u'three', u'rough', u'sad', u'goof']
+ In [15]: words = ['one', 'three', 'rough', 'sad', 'goof']
In [16]: for word in words:
....: bins[len(word)-1].append(word)
@@ -679,15 +741,15 @@ So, what is going to be in ``bins`` now?
In [65]: bins
Out[65]:
- [[u'one', u'three', u'rough', u'sad', u'goof'],
- [u'one', u'three', u'rough', u'sad', u'goof'],
- [u'one', u'three', u'rough', u'sad', u'goof'],
- [u'one', u'three', u'rough', u'sad', u'goof'],
- [u'one', u'three', u'rough', u'sad', u'goof']]
+ [['one', 'three', 'rough', 'sad', 'goof'],
+ ['one', 'three', 'rough', 'sad', 'goof'],
+ ['one', 'three', 'rough', 'sad', 'goof'],
+ ['one', 'three', 'rough', 'sad', 'goof'],
+ ['one', 'three', 'rough', 'sad', 'goof']]
We multiplied a sequence containing a single *mutable* object.
-We got a list containing five pointers to a single *mutable* object.
+We got a list containing five references to a single *mutable* object.
.. nextslide:: Mutable Default Argument
@@ -717,7 +779,7 @@ used to change the list.
You can find all these in the Standard Library Documentation:
-http://www.python.org/2/library/stdtypes.html#mutable-sequence-types
+https://docs.python.org/3/library/stdtypes.html#typesseq-mutable
Assignment
-----------
@@ -741,16 +803,16 @@ Growing the List
.. code-block:: ipython
- In [74]: food = [u'spam', u'eggs', u'ham']
- In [75]: food.append(u'sushi')
+ In [74]: food = ['spam', 'eggs', 'ham']
+ In [75]: food.append('sushi')
In [76]: food
- Out[76]: [u'spam', u'eggs', u'ham', u'sushi']
- In [77]: food.insert(0, u'beans')
+ Out[76]: ['spam', 'eggs', 'ham', 'sushi']
+ In [77]: food.insert(0, 'beans')
In [78]: food
- Out[78]: [u'beans', u'spam', u'eggs', u'ham', u'sushi']
- In [79]: food.extend([u'bread', u'water'])
+ Out[78]: ['beans', 'spam', 'eggs', 'ham', 'sushi']
+ In [79]: food.extend(['bread', 'water'])
In [80]: food
- Out[80]: [u'beans', u'spam', u'eggs', u'ham', u'sushi', u'bread', u'water']
+ Out[80]: ['beans', 'spam', 'eggs', 'ham', 'sushi', 'bread', 'water']
.. nextslide:: More on Extend
@@ -760,12 +822,12 @@ You can pass any sequence to ``.extend()``:
.. code-block:: ipython
In [85]: food
- Out[85]: [u'beans', u'spam', u'eggs', u'ham', u'sushi', u'bread', u'water']
- In [86]: food.extend(u'spaghetti')
+ Out[85]: ['beans', 'spam', 'eggs', 'ham', 'sushi', 'bread', 'water']
+ In [86]: food.extend('spaghetti')
In [87]: food
Out[87]:
- [u'beans', u'spam', u'eggs', u'ham', u'sushi', u'bread', u'water',
- u's', u'p', u'a', u'g', u'h', u'e', u't', u't', u'i']
+ ['beans', 'spam', 'eggs', 'ham', 'sushi', 'bread', 'water',
+ 's', 'p', 'a', 'g', 'h', 'e', 't', 't', 'i']
Shrinking the List
@@ -863,9 +925,7 @@ Consider this common pattern:
if should_be_removed(x):
somelist.remove(x)
-This looks benign enough, but changing a list while you are iterating over it
-can be the cause of some pernicious bugs.
-
+This looks benign enough, but changing a list while you are iterating over it can be the cause of some pernicious bugs.
.. nextslide:: The Problem
@@ -873,14 +933,14 @@ For example:
.. code-block:: ipython
- In [121]: list = range(10)
- In [122]: list
- Out[122]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- In [123]: for x in list:
- .....: list.remove(x)
- .....:
- In [124]: list
- Out[124]: [1, 3, 5, 7, 9]
+ In [27]: l = list(range(10))
+ In [28]: l
+ Out[28]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ In [29]: for item in l:
+ ....: l.remove(item)
+ ....:
+ In [30]: l
+ Out[30]: [1, 3, 5, 7, 9]
Was that what you expected?
@@ -890,12 +950,13 @@ Iterate over a copy, and mutate the original:
.. code-block:: ipython
- In [126]: list = range(10)
- In [127]: for x in list[:]:
- .....: list.remove(x)
- .....:
- In [128]: list
- Out[128]: []
+ In [33]: l = list(range(10))
+
+ In [34]: for item in l[:]:
+ ....: l.remove(item)
+ ....:
+ In [35]: l
+ Out[35]: []
.. nextslide:: Just Say It, Already
@@ -909,26 +970,25 @@ You can iterate over a sequence.
for element in sequence:
do_something(element)
+which is what we mean when we say a sequence is an "iterable".
-Again, we'll touch more on this in a short while, but first a few more words
-about Lists and Tuples.
+Again, we'll touch more on this in a short while, but first a few more words about Lists and Tuples.
Miscellaneous List Methods
--------------------------
-These methods change a list in place and are not available on immutable
-sequence types.
+These methods change a list in place and are not available on immutable sequence types.
``.reverse()``
.. code-block:: ipython
- In [129]: food = [u'spam', u'eggs', u'ham']
+ In [129]: food = ['spam', 'eggs', 'ham']
In [130]: food.reverse()
In [131]: food
- Out[131]: [u'ham', u'eggs', u'spam']
+ Out[131]: ['ham', 'eggs', 'spam']
``.sort()``
@@ -936,18 +996,16 @@ sequence types.
In [132]: food.sort()
In [133]: food
- Out[133]: [u'eggs', u'ham', u'spam']
+ Out[133]: ['eggs', 'ham', 'spam']
-Because these methods mutate the list in place, they have a return value of
-``None``
+Because these methods mutate the list in place, they have a return value of ``None``
.. nextslide:: Custom Sorting
``.sort()`` can take an optional ``key`` parameter.
-It should be a function that takes one parameter (list items one at a time) and
-returns something that can be used for sorting:
+It should be a function that takes one parameter (list items one at a time) and returns something that can be used for sorting:
.. code-block:: ipython
@@ -956,7 +1014,7 @@ returns something that can be used for sorting:
.....:
In [138]: food.sort(key=third_letter)
In [139]: food
- Out[139]: [u'spam', u'eggs', u'ham']
+ Out[139]: ['spam', 'eggs', 'ham']
@@ -966,16 +1024,16 @@ List Performance
.. rst-class:: build
* indexing is fast and constant time: O(1)
-* x in s proportional to n: O(n)
+* ``x in l`` is proportional to n: O(n)
* visiting all is proportional to n: O(n)
-* operating on the end of list is fast and constant time: O(1)
+* operating on the end of list is fast and constant time: O(1)
* append(), pop()
* operating on the front (or middle) of the list depends on n: O(n)
- * pop(0), insert(0, v)
- * But, reversing is fast. Also, collections.deque
+ * ``pop(0)``, ``insert(0, v)``
+ * But, reversing is fast. ``Also, collections.deque``
http://wiki.python.org/moin/TimeComplexity
@@ -994,10 +1052,12 @@ Here are a few guidelines on when to choose a list or a tuple:
Otherwise ... taste and convention
-.. nextslide:: Convention
+Convention
+-----------
+
Lists are Collections (homogeneous):
--- contain values of the same type
+-- contain values of the same type
-- simplifies iterating, sorting, etc
tuples are mixed types:
@@ -1005,7 +1065,8 @@ tuples are mixed types:
-- Kind of like simple C structs.
-.. nextslide:: Other Considerations
+Other Considerations
+--------------------
.. rst-class:: build
@@ -1035,10 +1096,51 @@ More Documentation
For more information, read the list docs:
-http://docs.python.org/2/library/stdtypes.html#mutable-sequence-types
+https://docs.python.org/3.5/library/stdtypes.html#mutable-sequence-types
(actually any mutable sequence....)
+One Last Trick
+---------------
+
+.. rst-class:: left
+
+For some of the exercises, you'll need to interact with a user at the
+command line.
+
+There's a nice built in function to do this - ``input``:
+
+.. code-block:: ipython
+
+ In [85]: fred = input('type something-->')
+ type something-->I've typed something
+
+ In [86]: print(fred)
+ I've typed something
+
+This will display a prompt to the user, allowing them to input text and
+allowing you to bind that input to a symbol.
+
+LAB
+====
+
+List Lab
+---------
+
+Let's play a bit with Python lists...
+
+:ref:`exercise_list_lab`
+
+
+
+Lightning Talks
+---------------
+
+|
+| Jerry Bearer
+|
+| Sheree Pena
+|
Iteration
=========
@@ -1056,7 +1158,7 @@ We've seen simple iteration over a sequence with ``for ... in``:
.. code-block:: ipython
In [170]: for x in "a string":
- .....: print x
+ .....: print(x)
.....:
a
s
@@ -1073,28 +1175,29 @@ Contrast this with other languages, where you must build and use an ``index``:
.. code-block:: javascript
- for(var i=0; i 50:
.....: break
.....:
@@ -1151,11 +1269,11 @@ allow iteration to continue:
.....: break
.....: if i < 25:
.....: continue
- .....: print i,
+ .....: print(i, end=' ')
.....:
25 26 27 28 29 ... 41 42 43 44 45 46 47 48 49 50
-.. nextslide:: Else
+.. nextslide:: else
For loops can also take an optional ``else`` block.
@@ -1167,14 +1285,14 @@ Executed only when the loop exits normally (not via break):
.....: if x == 11:
.....: break
.....: else:
- .....: print 'finished'
+ .....: print('finished')
finished
In [148]: for x in range(10):
.....: if x == 5:
- .....: print x
+ .....: print(x)
.....: break
.....: else:
- .....: print 'finished'
+ .....: print('finished')
5
This is a really nice unique Python feature!
@@ -1194,9 +1312,7 @@ It continues to execute the body until condition is not ``True``::
``while`` is more general than ``for``
--- you can always express ``for`` as ``while``,
-
-but not always vice-versa.
+-- you can always express ``for`` as ``while``, but not always vice-versa.
``while`` is more error-prone -- requires some care to terminate
@@ -1208,7 +1324,7 @@ potential error -- infinite loops:
i = 0;
while i < 5:
- print i
+ print(i)
.. nextslide:: Terminating a while Loop
@@ -1221,7 +1337,7 @@ Use ``break``:
.....: i += 1
.....: if i > 10:
.....: break
- .....: print i
+ .....: print(i)
.....:
1 2 3 4 5 6 7 8 9 10
@@ -1235,7 +1351,7 @@ Set a flag:
In [157]: keep_going = True
In [158]: while keep_going:
.....: num = random.choice(range(5))
- .....: print num
+ .....: print(num)
.....: if num == 3:
.....: keep_going = False
.....:
@@ -1249,7 +1365,7 @@ Use a condition:
In [161]: while i < 10:
.....: i += random.choice(range(4))
- .....: print i
+ .....: print(i)
.....:
0 0 2 3 4 6 8 8 8 9 12
@@ -1267,15 +1383,46 @@ loop terminates normally (no ``break``)
String Features
-=================
+================
.. rst-class:: center large
Fun with Strings
+Strings
+---------
-Manipulations
--------------
+A string literal creates a string type
+
+(we've seen this already...)
+
+::
+
+ "this is a string"
+
+ 'So is this'
+
+ """and this also"""
+
+You can also use ``str()``
+
+.. code-block:: ipython
+
+ In [256]: str(34)
+ Out[256]: '34'
+
+(demo)
+
+
+String Methods
+===============
+
+String objects have a lot of methods.
+
+Here are just a few:
+
+String Manipulations
+---------------------
``split`` and ``join``:
@@ -1289,353 +1436,292 @@ Manipulations
Out[170]: 'comma|separated|values'
-.. nextslide:: Case Switching
+Case Switching
+--------------
.. code-block:: ipython
- In [171]: sample = u'A long string of words'
+ In [171]: sample = 'A long string of words'
In [172]: sample.upper()
- Out[172]: u'A LONG STRING OF WORDS'
+ Out[172]: 'A LONG STRING OF WORDS'
In [173]: sample.lower()
- Out[173]: u'a long string of words'
+ Out[173]: 'a long string of words'
In [174]: sample.swapcase()
- Out[174]: u'a LONG STRING OF WORDS'
+ Out[174]: 'a LONG STRING OF WORDS'
In [175]: sample.title()
- Out[175]: u'A Long String Of Words'
+ Out[175]: 'A Long String Of Words'
-.. nextslide:: Testing
+Testing
+--------
.. code-block:: ipython
- In [181]: number = u"12345"
+ In [181]: number = "12345"
In [182]: number.isnumeric()
Out[182]: True
In [183]: number.isalnum()
Out[183]: True
In [184]: number.isalpha()
Out[184]: False
- In [185]: fancy = u"Th!$ $tr!ng h@$ $ymb0l$"
+ In [185]: fancy = "Th!$ $tr!ng h@$ $ymb0l$"
In [186]: fancy.isalnum()
Out[186]: False
-Ordinal values
---------------
+String Literals
+-----------------
-"ASCII" values: 1-127
+Common Escape Sequences::
-"ANSI" values: 1-255
+ \\ Backslash (\)
+ \a ASCII Bell (BEL)
+ \b ASCII Backspace (BS)
+ \n ASCII Linefeed (LF)
+ \r ASCII Carriage Return (CR)
+ \t ASCII Horizontal Tab (TAB)
+ \ooo Character with octal value ooo
+ \xhh Character with hex value hh
-To get the value:
+for example -- for tab-separated values:
.. code-block:: ipython
- In [109]: for i in 'Chris':
- .....: print ord(i),
- 67 104 114 105 115
- In [110]: for i in (67,104,114,105,115):
- .....: print chr(i),
- C h r i s
-
-
-Building Strings
-----------------
-
-You can, but please don't do this:
+ In [25]: s = "these\tare\tseparated\tby\ttabs"
-.. code-block:: python
+ In [26]: print(s)
+ these are separated by tabs
- 'Hello ' + name + '!'
+https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
+https://docs.python.org/3/library/stdtypes.html#string-methods
-Do this instead:
+Raw Strings
+------------
-.. code-block:: python
+Add an ``r`` in front of the string literal:
- 'Hello %s!' % name
+Escape Sequences Ignored
-It's much faster and safer, and easier to modify as code gets complicated.
+.. code-block:: ipython
-http://docs.python.org/library/stdtypes.html#string-formatting-operations
+ In [408]: print("this\nthat")
+ this
+ that
+ In [409]: print(r"this\nthat")
+ this\nthat
+**Gotcha**
-.. nextslide:: String Formatting
+.. code-block:: ipython
-The string format operator: ``%``
+ In [415]: r"\"
+ SyntaxError: EOL while scanning string literal
-.. code-block:: ipython
+(handy for regex, windows paths...)
- In [261]: u"an integer is: %i" % 34
- Out[261]: u'an integer is: 34'
- In [262]: u"a floating point is: %f" % 34.5
- Out[262]: u'a floating point is: 34.500000'
- In [263]: u"a string is: %s" % u"anything"
- Out[263]: u'a string is: anything'
-.. nextslide:: More Placeholders
+Ordinal values
+--------------
-Multiple placeholders:
+Characters in strings are stored as numeric values:
-.. code-block:: ipython
+* "ASCII" values: 1-127
- In [264]: u"the number %s is %i" % (u'five', 5)
- Out[264]: u'the number five is 5'
- In [266]: u"the first 3 numbers are: %i, %i, %i" % (1,2,3)
- Out[266]: u'the first 3 numbers are: 1, 2, 3'
+* Unicode values -- 1 - 1,114,111 (!!!)
-The counts must agree:
+To get the value:
.. code-block:: ipython
- In [187]: u"string with %i formatting %s" % (1, )
- ---------------------------------------------------------------------------
- ...
- TypeError: not enough arguments for format string
+ In [109]: for i in 'Chris':
+ .....: print(ord(i), end=' ')
+ 67 104 114 105 115
+ In [110]: for i in (67,104,114,105,115):
+ .....: print(chr(i), end='')
+ Chris
+(these days, stick with ASCII, or use full Unicode: more on that in a few weeks)
-.. nextslide::
-Named placeholders:
+Building Strings
+-----------------
-.. code-block:: ipython
+You can, but please don't do this:
- In [191]: u"Hello, %(name)s, whaddaya know?" % {u'name': "Joe"}
- Out[191]: u'Hello, Joe, whaddaya know?'
+.. code-block:: python
-You can use values more than once, and skip values:
+ 'Hello ' + name + '!'
-.. code-block:: ipython
+(I know -- we did that in the grid_printing excercise)
- In [193]: u"Hi, %(name)s. Howzit, %(name)s?" % {u'name': u"Bob", u'age': 27}
- Out[193]: u'Hi, Bob. Howzit, Bob?'
+Do this instead:
+.. code-block:: python
-.. nextslide:: New Formatting
+ 'Hello {}!'.format(name)
-In more recent versions of Python (2.6+) this is `being phased out`_ in favor of the ``.format()`` method on strings.
+It's much faster and safer, and easier to modify as code gets complicated.
-.. code-block:: ipython
+https://docs.python.org/3/library/string.html#string-formatting
- In [194]: u"Hello, {}, how's your {}".format(u"Bob", u"wife")
- Out[194]: u"Hello, Bob, how's your wife"
- In [195]: u"Hi, {name}. How's your {relation}?".format(name=u'Bob', relation=u'wife')
- Out[195]: u"Hi, Bob. How's your wife?"
+Old and New string formatting
+-----------------------------
+back in early python days, there was the string formatting operator: ``%``
-.. nextslide:: Complex Formatting
+.. code-block:: python
-For both of these forms of string formatting, there is a complete syntax for
-specifying all sorts of options.
+ " a string: %s and a number: %i "%("text", 45)
-It's well worth your while to spend some time getting to know this
-`formatting language`_. You can accomplish a great deal just with this.
+This is very similar to C-style string formatting (`sprintf`).
-.. _formatting language: https://docs.python.org/2/library/string.html#format-specification-mini-language
+It's still around, and handy --- but ...
-.. _being phased out: https://docs.python.org/2/library/stdtypes.html#str.format
+The "new" ``format()`` method is more powerful and flexible, so we'll focus on that in this class.
+.. nextslide:: String Formatting
-One Last Trick
-==============
+The string ``format()`` method:
-.. rst-class:: left
+.. code-block:: ipython
-For some of your homework, you'll need to interact with a user at the
-command line.
+ In [62]: "A decimal integer is: {:d}".format(34)
+ Out[62]: 'A decimal integer is: 34'
-.. rst-class:: left
+ In [63]: "a floating point is: {:f}".format(34.5)
+ Out[63]: 'a floating point is: 34.500000'
-There's a nice builtin function to do this - ``raw_input``:
+ In [64]: "a string is the default: {}".format("anything")
+ Out[64]: 'a string is the default: anything'
-.. rst-class:: left
-.. code-block:: python
+Multiple placeholders:
+-----------------------
- In [196]: fred = raw_input('type something-->')
- type something-->;alksdjf
- In [197]: fred
- Out[197]: ';alksdjf'
+.. code-block:: ipython
-.. rst-class:: left
+ In [65]: "the number is {} is {}".format('five', 5)
+ Out[65]: 'the number is five is 5'
-This will display a prompt to the user, allowing them to input text and
-allowing you to bind that input to a symbol.
+ In [66]: "the first 3 numbers are {}, {}, {}".format(1,2,3)
+ Out[66]: 'the first 3 numbers are 1, 2, 3'
+The counts must agree:
-Homework
-========
+.. code-block:: ipython
-Task 1
-------
+ In [67]: "string with {} formatting {}".format(1)
+ ---------------------------------------------------------------------------
+ IndexError Traceback (most recent call last)
+ in ()
+ ----> 1 "string with {} formatting {}".format(1)
-List Lab (after http://www.upriss.org.uk/python/session5.html)
+ IndexError: tuple index out of range
-In your student folder, create a new file called ``list_lab.py``.
-The file should be an executable python script. That is to say that one
-should be able to run the script directly like so:
+Named placeholders:
+-------------------
-.. code-block:: bash
+.. code-block:: ipython
- $ ./list_lab.py
-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.
+ In [69]: "Hello, {name}, whaddaya know?".format(name="Joe")
+ Out[69]: 'Hello, Joe, whaddaya know?'
-When the script is run, it should accomplish the following four series of
-actions:
+You can use values more than once, and skip values:
-.. nextslide:: Series 1
+.. code-block:: ipython
-- Create a list that contains "Apples", "Pears", "Oranges" and "Peaches".
-- Display the list.
-- Ask the user for another fruit and add it to the end of the list.
-- Display the list.
-- Ask the user for a number and display the number back to the user and the
- fruit corresponding to that number (on a 1-is-first basis).
-- Add another fruit to the beginning of the list using "+" and display the
- list.
-- Add another fruit to the beginning of the list using insert() and display the
- list.
-- Display all the fruits that begin with "P", using a for loop.
+ In [73]: "Hi, {name}. Howzit, {name}?".format(name='Bob')
+ Out[73]: 'Hi, Bob. Howzit, Bob?'
+.. nextslide::
-.. nextslide:: Series 2
+The format operator works with string variables, too:
-Using the list created in series 1 above:
+.. code-block:: ipython
-- Display the list.
-- Remove the last fruit from the list.
-- Display the list.
-- Ask the user for a fruit to delete and find it and delete it.
-- (Bonus: Multiply the list times two. Keep asking until a match is found. Once
- found, delete all occurrences.)
+ In [80]: s = "{:d} / {:d} = {:f}"
-.. nextslide:: Series 3
+ In [81]: a, b = 12, 3
-Again, using the list from series 1:
+ In [82]: s.format(a, b, a/b)
+ Out[82]: '12 / 3 = 4.000000'
-- Ask the user for input displaying a line like "Do you like apples?"
-- for each fruit in the list (making the fruit all lowercase).
-- For each "no", delete that fruit from the list.
-- For any answer that is not "yes" or "no", prompt the user to answer with one
- of those two values (a while loop is good here):
-- Display the list.
+So you can dynamically build a format string
-.. nextslide:: Series 4
+Complex Formatting
+------------------
-Once more, using the list from series 1:
+There is a complete syntax for specifying all sorts of options.
-- Make a copy of the list and reverse the letters in each fruit in the copy.
-- Delete the last item of the original list. Display the original list and the
- copy.
+It's well worth your while to spend some time getting to know this
+`formatting language`_. You can accomplish a great deal just with this.
+.. _formatting language: https://docs.python.org/3/library/string.html#format-specification-mini-language
-Task 2
-------
-ROT13
+String Formatting LAB
+=====================
-The ROT13 encryption scheme is a simple substitution cypher where each letter
-in a text is replace by the letter 13 away from it (imagine the alphabet as a
-circle, so it wraps around).
+Let's play with these a bit:
-Add a python module named ``rot13.py`` to your student folder. This module
-should provide at least one function called ``rot13`` that takes any amount of
-text and returns that same text encrypted by ROT13.
+:ref:`exercise_string_formatting`
-This function should preserve whitespace, punctuation and capitalization.
+Homework
+========
-Your module should include an ``if __name__ == '__main__':`` block with tests
-that demonstrate that your ``rot13`` function and any helper functions you add
-work properly.
+Task 1
+------
-.. nextslide:: A bit more
+Finish the List Lab from class
-There is a "short-cut" available that will help you accomplish this task. Some
-spelunking in `the documentation for strings`_ should help you to find it. If
-you do find it, using it is completely fair game.
+Finish the string formatting lab
-.. _the documentation for strings: https://docs.python.org/2/library/stdtypes.html#string-methods
+Task 2
+------
-As usual, add your new file to your local clone right away. Make commits early and often and include commit messages that are descriptive and concise.
+.. rst-class:: mlarge
-When you are done, push your changes to github and issue a pull request.
+ROT13
+:ref:`exercise_rot13`
Task 3
------
-"Mail Room"
-
-You work in the mail room at a local charity. Part of your job is to write
-incredibly boring, repetitive emails thanking your donors for their generous
-gifts. You are tired of doing this over an over again, so you've decided to let Python help you out of a jam.
+.. rst-class:: mlarge
-Write a small command-line script called ``mailroom.py``. As with Task 1, This script should be executable. The script should accomplish the following goals:
+Mail Room
-* It should have a data structure that holds a list of your donors and a
- history of the amounts they have donated. This structure should be populated
- at first with at least five donors, with between 1 and 3 donations each
-* The script should prompt the user (you) to choose from a menu of 2 actions:
- 'Send a Thank You' or 'Create a Report'.
+:ref:`exercise_mailroom`
-.. nextslide:: Sending a Thank You
-
-* If the user (you) selects 'Send a Thank You', prompt for a Full Name.
+Reading
+-------
- * If the user types 'list', show them a list of the donor names and re-prompt
- * If the user types a name not in the list, add that name to the data
- structure and use it.
- * If the user types a name in the list, use it.
- * Once a name has been selected, prompt for a donation amount.
- * Verify that the amount is in fact a number, and re-prompt if it isn't.
- * Once an amount has been given, add that amount to the donation history of
- the selected user.
- * Finally, use string formatting to compose an email thanking the donor for
- their generous donation. Print the email to the terminal and return to the
- original prompt.
+Think Python: Chapters 11, 13, 14
-**It is fine to forget new donors once the script quits running.**
+Learn Python the Hard way: 15-17, 39
-.. nextslide:: Creating a Report
+Dive Into Python3: Sections 2.6, 2.7, 11
-* If the user (you) selected 'Create a Report' Print a list of your donors,
- sorted by total historical donation amount.
+Next Week:
+===========
- - Include Donor Name, total donated, number of donations and average donation
- amount as values in each row.
- - Using string formatting, format the output rows as nicely as possible. The
- end result should be tabular (values in each column should align with those
- above and below)
- - After printing this report, return to the original prompt.
+.. rst-class:: mlarge
-* At any point, the user should be able to quit their current task and return
- to the original prompt.
+ **Lightning talks next week:**
-* From the original prompt, the user should be able to quit the script cleanly
+Abdishu Hagi
-.. nextslide:: Guidelines
+Enrique R Silva
-First, factor your script into separate functions. Each of the above
-tasks can be accomplished by a series of steps. Write discreet functions
-that accomplish individual steps and call them.
+Isaac Cowhey
-Second, use loops to control the logical flow of your program. Interactive
-programs are a classic use-case for the ``while`` loop.
+Paul G Anderson
-Put the functions you write into the script at the top.
-Put your main interaction into an ``if __name__ == '__main__'`` block.
-Finally, use only functions and the basic Python data types you've learned
-about so far. There is no need to go any farther than that for this assignment.
-.. nextslide:: Submission
-As always, put the new file in your student directory in a ``session03``
-directory, and add it to your clone early. Make frequent commits with
-good, clear messages about what you are doing and why.
-When you are done, push your changes and make a pull request.
diff --git a/slides_sources/source/session04.rst b/slides_sources/source/session04.rst
index 75c790af..77ee3d1d 100644
--- a/slides_sources/source/session04.rst
+++ b/slides_sources/source/session04.rst
@@ -1,11 +1,8 @@
-.. Foundations 2: Python slides file, created by
- Chris Barker: May 12, 2014.
-
-*******************************************************
-Session Four: Dictionaries, Sets, Exceptions, and Files
-*******************************************************
-
+.. include:: include.rst
+*******************************************
+Session Four: Dictionaries, Sets, and Files
+*******************************************
================
Review/Questions
@@ -32,9 +29,30 @@ Review of Previous Classes
Any questions?
-.. nextslide::
+Lightning Talks Today:
+----------------------
+
+.. rst-class:: medium
+
+ Abdishu Hagi
+
+ Enrique R Silva
+
+ Isaac Cowhey
+
+ Paul G Anderson
-A couple other nifty utilties with for loops:
+
+==============================
+Handy hints for/from Homework
+==============================
+
+.. rst-class:: mlarge
+
+ You almost never need to loop through the indexes of a sequence
+
+nifty for loop tricks
+---------------------
**tuple unpacking:**
@@ -51,16 +69,21 @@ You can do that in a for loop, also:
In [4]: l = [(1, 2), (3, 4), (5, 6)]
In [5]: for i, j in l:
- print "i:%i, j:%i"%(i, j)
+ print("i:{}, j:{}".format(i, j))
i:1, j:2
i:3, j:4
i:5, j:6
-Looping through two loops at once:
-----------------------------------
+(Mailroom example)
-**zip:**
+
+Looping through two iterables at once:
+--------------------------------------
+
+.. rst-class:: mlarge
+
+ ``zip``
.. code-block:: ipython
@@ -69,22 +92,47 @@ Looping through two loops at once:
In [11]: l2 = [3, 4, 5]
In [12]: for i, j in zip(l1, l2):
- ....: print "i:%i, j:%i"%(i, j)
- ....:
+ print("i:{}, j:{}".format(i, j))
+
i:1, j:3
i:2, j:4
i:3, j:5
+Can be more than two:
+.. code-block:: python
+
+ for i, j, k, l in zip(l1, l2, l3, l4):
+
+
+Need the index and the item?
+----------------------------
+
+.. rst-class:: mlarge
+
+ ``enumerate``
+
+.. code-block:: ipython
+
+ In [2]: l = ['this', 'that', 'the other']
-Homework comments
+ In [3]: for i, item in enumerate(l):
+ ...: print("the {:d}th item is: {:s}".format(i, item))
+ ...:
+ the 0th item is: this
+ the 1th item is: that
+ the 2th item is: the other
+
+
+
+Homework Comments
-----------------
Building up a long string.
The obvious thing to do is something like::
- msg = u""
+ msg = ""
for piece in list_of_stuff:
msg += piece
@@ -93,13 +141,57 @@ But: strings are immutable -- python needs to create a new string each time you
msg = []
for piece in list_of_stuff:
msg.append(piece)
- u" ".join(msg)
+ " ".join(msg)
appending to lists is efficient -- and so is the join() method of strings.
-
.. nextslide::
+.. rst-class:: center mlarge
+
+You can put a mutable item in an immutable object!
+
+(demo)
+
+.. nextslide:: A couple small things:
+
+|
+| Use string formatting
+|
+| The ``sum()`` function
+|
+| Deleting from list (list_lab)
+|
+
+__main__
+--------
+
+What is this::
+
+ if __name__ == __main__
+
+about?
+
+Every module has a __name__
+
+If the module is loaded by ``import`` then it's name is the filename.
+
+If the module is run at the command line, like:
+
+.. code-block:: bash
+
+ python3 the_module.py
+
+Then it's ``__name__`` will be "__main__"
+
+This can be used to run code only when a module is run as a command,
+but not when it is imported.
+
+(demo)
+
+assert
+------
+
What is ``assert`` for?
Testing -- NOT for issues expected to happen operationally::
@@ -111,10 +203,33 @@ in operational code should be::
if m < 0:
raise ValueError
-I'll cover Exceptions later this class...
+I'll cover more next week ...
(Asserts get ignored if optimization is turned on!)
+what the heck is reversed()?
+----------------------------
+
+I had a question in a PR:
+
+"what is ``reversed(x)``'s resultant object? what good is it?""
+
+.. nextslide::
+
+try it:
+
+.. code-block:: ipython
+
+ In [14]: type(reversed(l))
+ Out[14]: list_reverseiterator
+
+so it's a ``list_reverseiterator`` object -- not helpful, is it :-)
+
+But what it means is that it's an "iterable" that you can then do things like loop through with a for loop, etc. but it hasn't made a copy of the list -- it returns the items one by one as they are asked for. this has performance benefits, as it doesn't have to make a copy of the whole thing.
+
+So you use it if you want to loop through something in reversed order, but dont actually need an actual list with the order reversed.
+
+we'll get more into the details of iterators and iterables later in the class.
=================
A little warm up
@@ -127,13 +242,15 @@ Fun with strings
- for an arbitrary number of numbers...
-* Write a format string that will take:
-
- - ``( 2, 123.4567, 10000)``
+===============
+Lightning Talks
+===============
- - and produce:
-
- - `` "file_002 : 123.46, 1e+04" ``
+|
+| Isaac Cowhey
+|
+| Paul G Anderson
+|
=====================
Dictionaries and Sets
@@ -175,7 +292,7 @@ Dictionary Constructors
Dictionary Indexing
-------------------
::
-
+
>>> d = {'name': 'Brian', 'score': 42}
>>> d['score']
@@ -264,7 +381,7 @@ Dictionaries have no defined order
In [353]: d
Out[353]: {'one': 1, 'three': 3, 'two': 2}
In [354]: d.keys()
- Out[354]: ['three', 'two', 'one']
+ Out[354]: dict_keys(['three', 'two', 'one'])
Dictionary Iterating
--------------------
@@ -275,9 +392,9 @@ Dictionary Iterating
In [15]: d = {'name': 'Brian', 'score': 42}
- In [16]: for x in d:
- print x
- ....:
+ In [16]: for x in d:
+ print(x)
+ ....:
score
name
@@ -292,13 +409,13 @@ dict keys and values
In [20]: d = {'name': 'Brian', 'score': 42}
In [21]: d.keys()
- Out[21]: ['score', 'name']
+ Out[21]: dict_keys(['score', 'name'])
In [22]: d.values()
- Out[22]: [42, 'Brian']
+ Out[22]: dict_values([42, 'Brian'])
In [23]: d.items()
- Out[23]: [('score', 42), ('name', 'Brian')]
+ Out[23]: dict_items([('score', 42), ('name', 'Brian')])
dict keys and values
@@ -311,13 +428,13 @@ Iterating on everything
In [26]: d = {'name': 'Brian', 'score': 42}
In [27]: for k, v in d.items():
- print "%s: %s" % (k,v)
- ....:
+ print("%s: %s" % (k,v))
+ ....:
score: 42
name: Brian
-Dictionary Performance
+Dictionary Performance
-----------------------
* indexing is fast and constant time: O(1)
@@ -339,7 +456,7 @@ Other dict operations:
See them all here:
-https://docs.python.org/2/library/stdtypes.html#mapping-types-dict
+https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
Is it in there?
@@ -369,8 +486,8 @@ But you can specify a default
.. code-block:: ipython
- In [11]: d.get(u'something', u'a default')
- Out[11]: u'a default'
+ In [11]: d.get('something', 'a default')
+ Out[11]: 'a default'
Never raises an Exception (default default is None)
@@ -380,23 +497,34 @@ iterating
.. code-block:: ipython
- In [13]: for item in d.iteritems():
- ....: print item
- ....:
- ('this', 5)
- ('that', 7)
- In [15]: for key in d.iterkeys():
- print key
- ....:
+ In [13]: for item in d:
+ ....: print(item)
+ ....:
+ this
+ that
+
+which is equivalent to, but faster than:
+
+.. code-block:: ipython
+
+ In [15]: for key in d.keys():
+ print(key)
+ ....:
this
that
- In [16]: for val in d.itervalues():
- print val
- ....:
+
+.. nextslide::
+
+but to get values, must specify you want values:
+
+.. code-block:: ipython
+
+ In [16]: for val in d.values():
+ print(val)
+ ....:
5
7
-the ``iter*`` methods don't actually create the lists.
.. nextslide::
@@ -432,39 +560,51 @@ gets the value if it's there, sets it if it's not
.. code-block:: ipython
- In [27]: d.setdefault(u'something', u'a value')
- Out[27]: u'a value'
+ In [27]: d.setdefault('something', 'a value')
+ Out[27]: 'a value'
In [28]: d
- Out[28]: {u'something': u'a value'}
-
- In [29]: d.setdefault(u'something', u'a value')
- Out[29]: u'a value'
+ Out[28]: {'something': 'a value'}
- In [30]: d
- Out[30]: {u'something': u'a value'}
.. nextslide::
-dict View objects:
-
-Like ``keys()``, ``values()``, ``items()``, but maintain a link to the original dict
+Assignment maintains link to the original dict
.. code-block:: ipython
In [47]: d
- Out[47]: {u'something': u'a value'}
+ Out[47]: {'something': 'a value'}
- In [48]: item_view = d.viewitems()
+ In [48]: item_view = d
- In [49]: d['something else'] = u'another value'
+ In [49]: d['something else'] = 'another value'
In [50]: item_view
- Out[50]: dict_items([('something else', u'another value'), (u'something', u'a value')])
+ Out[50]: {'something': 'a value', 'something else': 'another value'}
+
+
+.. nextslide::
+
+Use explicit copy method to get a copy
+
+.. code-block:: ipython
+
+ In [51] item_copy = d.copy()
+
+ In [52]: d['another thing'] = 'different value'
+ In [53]: d
+ Out[53]:
+ {'another thing': 'different value',
+ 'something': 'a value',
+ 'something else': 'another value'}
+ In [54]: item_copy
+ Out[54]: {'something': 'a value', 'something else': 'another value'}
-Sets
+
+Sets
-----
``set`` is an unordered collection of distinct values
@@ -476,19 +616,19 @@ Set Constructors
.. code-block:: ipython
>>> set()
- set([])
+ set()
>>> set([1, 2, 3])
- set([1, 2, 3])
+ {1, 2, 3}
>>> {1, 2, 3}
- set([1, 2, 3])
+ {1, 2, 3}
>>> s = set()
>>> s.update([1, 2, 3])
>>> s
- set([1, 2, 3])
+ {1, 2, 3}
Set Properties
@@ -536,13 +676,13 @@ All the "set" operations from math class...
s.isdisjoint(other)
s.issubset(other)
-
+
s.union(other, ...)
-
+
s.intersection(other, ...)
-
+
s.difference(other, ...)
-
+
s.symmetric_difference( other, ...)
Frozen Set
@@ -562,209 +702,22 @@ immutable -- for use as a key in a dict
AttributeError: 'frozenset' object has no attribute 'add'
-==========
-Exceptions
-==========
-
-Exceptions
-----------
-
-Another Branching structure:
-
-.. code-block:: python
-
- try:
- do_something()
- f = open('missing.txt')
- process(f) # never called if file missing
- except IOError:
- print "couldn't open missing.txt"
-
-Exceptions
-----------
-Never Do this:
-
-.. code-block:: python
-
- try:
- do_something()
- f = open('missing.txt')
- process(f) # never called if file missing
- except:
- print "couldn't open missing.txt"
-
+LAB: Dictionaries and Sets lab
+==============================
-Exceptions
-----------
-
-Use Exceptions, rather than your own tests:
-
-Don't do this:
-
-.. code-block:: python
-
- do_something()
- if os.path.exists('missing.txt'):
- f = open('missing.txt')
- process(f) # never called if file missing
-
-It will almost always work -- but the almost will drive you crazy
-
-.. nextslide::
-
-Example from homework
-
-.. code-block:: python
-
- if num_in.isdigit():
- num_in = int(num_in)
-
-but -- ``int(num_in)`` will only work if the string can be converted to an integer.
-
-So you can do
-
-.. code-block:: python
-
- try:
- num_in = int(num_in)
- except ValueError:
- print u"Input must be an integer, try again."
+Have some fun with dictionaries and sets!
-Or let the Exception be raised....
-
-
-.. nextslide:: EAFP
-
-
-"it's Easier to Ask Forgiveness than Permission"
-
- -- Grace Hopper
-
-
-http://www.youtube.com/watch?v=AZDWveIdqjY
-
-(Pycon talk by Alex Martelli)
-
-.. nextslide:: Do you catch all Exceptions?
-
-For simple scripts, let exceptions happen.
-
-Only handle the exception if the code can and will do something about it.
-
-(much better debugging info when an error does occur)
-
-
-Exceptions -- finally
----------------------
-
-.. code-block:: python
+:ref:`exercise_dict_lab`
- try:
- do_something()
- f = open('missing.txt')
- process(f) # never called if file missing
- except IOError:
- print "couldn't open missing.txt"
- finally:
- do_some_clean-up
-The ``finally:`` clause will always run
-
-
-Exceptions -- else
--------------------
-
-.. code-block:: python
-
- try:
- do_something()
- f = open('missing.txt')
- except IOError:
- print "couldn't open missing.txt"
- else:
- process(f) # only called if there was no exception
-
-Advantage:
-
-you know where the Exception came from
-
-Exceptions -- using them
-------------------------
-
-.. code-block:: python
-
- try:
- do_something()
- f = open('missing.txt')
- except IOError as the_error:
- print the_error
- the_error.extra_info = "some more information"
- raise
-
-
-Particularly useful if you catch more than one exception:
-
-.. code-block:: python
-
- except (IOError, BufferError, OSError) as the_error:
- do_something_with (the_error)
-
-
-Raising Exceptions
--------------------
-
-.. code-block:: python
-
- def divide(a,b):
- if b == 0:
- raise ZeroDivisionError("b can not be zero")
- else:
- return a / b
-
-
-when you call it:
-
-.. code-block:: ipython
-
- In [515]: divide (12,0)
- ZeroDivisionError: b can not be zero
-
-
-Built in Exceptions
--------------------
-
-You can create your own custom exceptions
-
-But...
-
-.. code-block:: python
-
- exp = \
- [name for name in dir(__builtin__) if "Error" in name]
- len(exp)
- 32
-
-
-For the most part, you can/should use a built in one
-
-.. nextslide::
-
-Choose the best match you can for the built in Exception you raise.
-
-Example (for last week's ackerman homework)::
-
- if (not isinstance(m, int)) or (not isinstance(n, int)):
- raise ValueError
-
-Is it the *value* or the input the problem here?
-
-Nope: the *type* is the problem::
-
- if (not isinstance(m, int)) or (not isinstance(n, int)):
- raise TypeError
-
-but should you be checking type anyway? (EAFP)
+Lightning Talks
+---------------
+|
+| Abdishu Hagi
+|
+| Enrique R Silva
+|
========================
File Reading and Writing
@@ -777,16 +730,13 @@ Text Files
.. code-block:: python
- import io
- f = io.open('secrets.txt', codec='utf-8')
+ f = open('secrets.txt')
secret_data = f.read()
f.close()
-``secret_data`` is a (unicode) string
+``secret_data`` is a string
-``codec`` defaults to ``sys.getdefaultencoding()`` -- often NOT what you want.
-
-(There is also the regular ``open()`` built in, but it won't handle Unicode for you...)
+NOTE: these days, you probably need to use Unicode for text -- we'll get to that next week
.. nextslide::
@@ -794,11 +744,11 @@ Binary Files
.. code-block:: python
- f = io.open('secrets.bin', 'rb')
+ f = open('secrets.bin', 'rb')
secret_data = f.read()
f.close()
-``secret_data`` is a byte string
+``secret_data`` is a byte string
(with arbitrary bytes in it -- well, not arbitrary -- whatever is in the file.)
@@ -812,15 +762,15 @@ File Opening Modes
.. code-block:: python
- f = io.open('secrets.txt', [mode])
+ f = open('secrets.txt', [mode])
'r', 'w', 'a'
'rb', 'wb', 'ab'
r+, w+, a+
r+b, w+b, a+b
- U
- U+
-These follow the Unix conventions, and aren't all that well documented on the Python docs. But these BSD docs make it pretty clear:
+
+These follow the Unix conventions, and aren't all that well documented
+in the Python docs. But these BSD docs make it pretty clear:
http://www.manpagez.com/man/3/fopen/
@@ -833,8 +783,6 @@ Text is default
* Newlines are translated: ``\r\n -> \n``
* -- reading and writing!
* Use \*nix-style in your code: ``\n``
- * ``io.open()`` returns various "stream" objects -- but they act like file objects.
- * In text mode, io.open() defaults to "Universal" newline mode.
Gotcha:
@@ -843,27 +791,6 @@ Gotcha:
* breaks on Windows
-.. nextslide:: Other parameters to ``io.open()``:
-
-``io.open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True)``
-
- * ``file`` is generally a file name or full path
-
- * ``mode`` is the mode for opening: 'r', 'w', etc.
-
- * ``buffering`` controls the buffering mode (0 for no buffering)
-
- * ``encoding`` sets the unicode encoding -- only for text files -- when set, you can ONLY write unicode object to the file.
-
- * ``errors`` sets the encoding error mode: 'strict', 'ignore', 'replace',...
-
- * ``newline`` controls Universal Newline mode: lets you write DOS-type files on \*nix, for instance (text mode only).
-
- * ``closedfd`` controls close() behavior if a file descriptor, rather than a name is passed in (advanced usage!)
-
-(https://docs.python.org/2/library/io.html?highlight=io.open#io.open)
-
-
File Reading
------------
@@ -884,29 +811,46 @@ Common Idioms
.. code-block:: python
- for line in io.open('secrets.txt'):
- print line
+ for line in open('secrets.txt'):
+ print(line)
(the file object is an iterator!)
.. code-block:: python
- f = io.open('secrets.txt')
+ f = open('secrets.txt')
while True:
line = f.readline()
if not line:
break
do_something_with_line()
+.. nextslide::
+
+We will learn more about the keyword with later, but for now, just understand
+the syntax and the advantage over the try-finally block:
+
+.. code-block:: python
+
+ with open('workfile', 'r') as f:
+ read_data = f.read()
+ f.closed
+ True
+
File Writing
------------
.. code-block:: python
- outfile = io.open('output.txt', 'w')
+ outfile = open('output.txt', 'w')
for i in range(10):
outfile.write("this is line: %i\n"%i)
+ outfile.close()
+
+ with open('output.txt', 'w'):
+ for i in range(10):
+ f.write("this is line: %i\n"%i)
File Methods
@@ -920,41 +864,31 @@ Commonly Used Methods
f.write(str) f.writelines(seq)
- f.seek(offset) f.tell()
-
- f.flush()
+ f.seek(offset) f.tell() # for binary files, mostly
f.close()
-
-File Like Objects
------------------
-
-
-Many classes implement the file interface:
-
- * loggers
- * ``sys.stdout``
- * ``urllib.open()``
- * pipes, subprocesses
- * StringIO
-
-https://docs.python.org/2/library/stdtypes.html#file-objects
-
StringIO
--------
.. code-block:: python
- In [417]: import StringIO
- In [420]: f = StringIO.StringIO()
- In [421]: f.write(u"somestuff")
+ In [417]: import io
+ In [420]: f = io.StringIO()
+ In [421]: f.write("somestuff")
In [422]: f.seek(0)
In [423]: f.read()
Out[423]: 'somestuff'
+ Out[424]: stuff = f.getvalue()
+ Out[425]: f.close()
(handy for testing file handling code...)
+There is also cStringIO -- a bit faster.
+
+.. code-block:: python
+
+ from cStringIO import StringIO
=====================
Paths and Directories
@@ -969,14 +903,14 @@ Relative paths:
.. code-block:: python
- u'secret.txt'
- u'./secret.txt'
+ 'secret.txt'
+ './secret.txt'
Absolute paths:
.. code-block:: python
- u'/home/chris/secret.txt'
+ '/home/chris/secret.txt'
Either work with ``open()`` , etc.
@@ -988,10 +922,10 @@ os module
.. code-block:: python
- os.getcwd() -- os.getcwdu() (u for Unicode)
- chdir(path)
+ os.getcwd()
+ os.chdir(path)
os.path.abspath()
- os.path.relpath()
+ os.path.relpath()
.. nextslide:: os.path module
@@ -1020,16 +954,10 @@ os module
pathlib
-------
-``pathlib`` is a new package for handling paths in an OO way:
+``pathlib`` is a package for handling paths in an OO way:
http://pathlib.readthedocs.org/en/pep428/
-It is now part of the Python3 standard library, and has been back-ported for use with Python2:
-
-.. code-block:: bash
-
- $ pip install pathlib
-
All the stuff in os.path and more:
.. code-block:: ipython
@@ -1039,124 +967,44 @@ All the stuff in os.path and more:
In [66]: pth.is_dir()
Out[66]: True
In [67]: pth.absolute()
- Out[67]: PosixPath('/Users/Chris/PythonStuff/CodeFellowsClass/sea-f2-python-sept14/Examples/Session04')
+ Out[67]: PosixPath('/Users/Chris/PythonStuff/UWPCE/IntroPython2015')
In [68]: for f in pth.iterdir():
- print f
+ print(f)
junk2.txt
junkfile.txt
...
-=========
-Homework
-=========
+===
+LAB
+===
-Recommended Reading:
----------------------
- * Dive Into Python: Chapt. 13,14
- * Unicode: http://www.joelonsoftware.com/articles/Unicode.html
-
-Assignments:
--------------
+Files Lab: If there is time.
- * dict/sets lab
- * coding kata: trigrams
- * Exceptions
- * Update mailroom with dicts.
-
-
-Dictionaries and Sets
----------------------
+:ref:`exercise_file_lab`
-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.
-
-.. nextslide::
-2.
-* Using the dict constructor and zip, build a dictionary of numbers from zero to fifteen and the hexadecimal equivalent (string is fine).
-
-3.
-
-* Using the dictionary from item 1: Make a dictionary using the same keys but with the number of 'a's in each value.
-
-.. nextslide:: sets
-
-4.
-
-* 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).
-
-5.
-
-* 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.
-
-
-Text and files and dicts, and...
----------------------------------
-
- * Coding Kata 14 - Dave Thomas
-
- http://codekata.com/kata/kata14-tom-swift-under-the-milkwood/
-
- and in this doc:
-
- http://codefellows.github.io/sea-c15-python/supplements/kata_fourteen.html
-
- * Use The Adventures of Sherlock Holmes as input:
-
- http://codefellows.github.io/sea-c15-python/_downloads/sherlock.txt
-
- * This is intentionally open-ended and underspecified. There are many interesting decisions to make.
-
- * Experiment with different lengths for the lookup key. (3 words, 4 words, 3 letters, etc)
-
-Exceptions
------------
-
-Improving ``raw_input``
-
-* The ``raw_input()`` function can generate two exceptions: ``EOFError`` or ``KeyboardInterrupt`` on end-of-file(EOF) or canceled input.
+=========
+Homework
+=========
-* 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.
+Recommended Reading:
+---------------------
-* Update your mailroom program to use exceptions (and IBAFP) to handle malformed numeric input
+ * Dive Into Python 3: Chapt. 2.7 (and 4 if you haven't already)
+http://www.diveintopython3.net/native-datatypes.html#dictionaries
-Paths and File Processing
---------------------------
+ * Dive Into Python 3: Chapt. 11
- * write a program which prints the full path to all files in the current directory, one per line
+http://www.diveintopython3.net/files.html
- * write a program which copies a file from a source, to a destination (without using shutil, or the OS copy command)
- * update mailroom from last weeks homework to:
+Assignments:
+-------------
- - use dicts where appropriate
- - write a full set of letters to everyone to individual files on disk
- - see if you can use a dict to switch between the users selections
- - Try to use a dict and the .format() method to do the letter as one big template -- rather than building up a big string in parts.
+ * Finish the dict/sets lab: :ref:`exercise_dict_lab`
+ * Finish the files lab: :ref:`exercise_file_lab`
+ * Coding kata: trigrams: :ref:`exercise_trigrams`
+ * update mailroom with dicts :ref:`exercise_mailroom_plus`
diff --git a/slides_sources/source/session05.rst b/slides_sources/source/session05.rst
index c8cffe56..04b21d7a 100644
--- a/slides_sources/source/session05.rst
+++ b/slides_sources/source/session05.rst
@@ -1,12 +1,22 @@
+.. include:: include.rst
-.. Foundations 2: Python slides file, created by
- hieroglyph-quickstart on Wed Apr 2 18:42:06 2014.
+****************************************
+Session Five: Exceptions, Comprehensions
+****************************************
+======================
+Lightning Talks Today:
+======================
+
+.. rst-class:: medium
-********************************************************************************************************
-Session Five: Advanced Argument passing, List and Dict Comprehensions, Lambda and Functional programming
-********************************************************************************************************
+ Alexander C Truong
+ Darryl Wong
+
+ Madhumita Acharya
+
+ Matthew T Weidner
================
Review/Questions
@@ -16,1016 +26,751 @@ Review of Previous Class
------------------------
* Dictionaries
- * Exceptions
- * Files, etc.
-
-
-Homework review
----------------
-
-Homework Questions?
-
-My Solutions to the dict/set lab, and some others in the class repo in: ``Solutions``
-
-A few tidbits:
-
-.. nextslide:: Sorting stuff in dictionaries:
-
-dicts aren't sorted, so what if you want to do something in a sorted way?
-
-The "old" way:
-
-.. code-block:: python
-
- keys = d.keys()
- keys.sort()
- for key in keys:
- ...
-
-.. code-block:: python
-
- collections.OrderedDict
-
- sorted()
-
-(demo)
-
-=========================
-Advanced Argument Passing
-=========================
-
-Keyword arguments
------------------
-
-When defining a function, you can specify only what you need -- in any order
-
-.. code-block:: ipython
-
- In [151]: def fun(x,y=0,z=0):
- print x,y,z
- .....:
- In [152]: fun(1,2,3)
- 1 2 3
- In [153]: fun(1, z=3)
- 1 0 3
- In [154]: fun(1, z=3, y=2)
- 1 2 3
-
+ * Sets
+ * File processing, etc.
.. nextslide::
+.. rst-class:: center large
-A Common Idiom:
-
-.. code-block:: python
-
- def fun(x, y=None):
- if y is None:
- do_something_different
- go_on_here
-
-
+ How many of you finished ALL the homework?
.. nextslide::
-Can set defaults to variables
-
-.. code-block:: ipython
-
- In [156]: y = 4
- In [157]: def fun(x=y):
- print "x is:", x
- .....:
- In [158]: fun()
- x is: 4
+.. rst-class:: center large
+ Sorry about that!
.. nextslide::
-Defaults are evaluated when the function is defined
+.. rst-class:: medium
-.. code-block:: ipython
-
- In [156]: y = 4
- In [157]: def fun(x=y):
- print "x is:", x
- .....:
- In [158]: fun()
- x is: 4
- In [159]: y = 6
- In [160]: fun()
- x is: 4
+ * That was a lot.
+.. rst-class:: medium
+.. rst-class:: build
-Function arguments in variables
--------------------------------
+ * But it's all good stuff.
-function arguments are really just
+ * I'll take time to go over it in class.
-* a tuple (positional arguments)
-* a dict (keyword arguments)
+ * And this week is a light load, so you can catch up.
-.. code-block:: python
- def f(x, y, w=0, h=0):
- print "position: %s, %s -- shape: %s, %s"%(x, y, w, h)
+Homework review
+---------------
- position = (3,4)
- size = {'h': 10, 'w': 20}
+My Solutions to all the exercises in the class repo in:
- >>> f( *position, **size)
- position: 3, 4 -- shape: 20, 10
+``Solutions/Session04``
+A few tidbits, then I'll take specific questions.
-Function parameters in variables
---------------------------------
+The count() method
+------------------
-You can also pull the parameters out in the function as a tuple and a dict:
+All Python sequences (including strings) have a ``count()`` method:
.. code-block:: ipython
- def f(*args, **kwargs):
- print "the positional arguments are:", args
- print "the keyword arguments are:", kwargs
-
- In [389]: f(2, 3, this=5, that=7)
- the positional arguments are: (2, 3)
- the keyword arguments are: {'this': 5, 'that': 7}
+ In [1]: s = "This is an arbitrary string"
-Passing a dict to the ``string.format()`` method
-------------------------------------------------
+ In [2]: s.count('t')
+ Out[2]: 2
-Now that you know that keyword args are really a dict, you can do this nifty trick:
-
-The ``format`` method takes keyword arguments:
+What if you want a case-insensitive count?
.. code-block:: ipython
- In [24]: u"My name is {first} {last}".format(last=u"Barker", first=u"Chris")
- Out[24]: u'My name is Chris Barker'
-
-Build a dict of the keys and values:
-
-.. code-block:: ipython
-
- In [25]: d = {u"last":u"Barker", u"first":u"Chris"}
-
-And pass to ``format()``with ``**``
-
-.. code-block:: ipython
-
- In [26]: u"My name is {first} {last}".format(**d)
- Out[26]: u'My name is Chris Barker'
-
-
-
-
-LAB
----
-
-Let's do this right now:
-
-keyword arguments
-
-* Write a function that has four optional parameters (with defaults):
-
- - foreground_color
- - background_color
- - link_color
- - visited_link_color
-
-* Have it print the colors (use strings for the colors)
-* Call it with a couple different parameters set
-* Have it pull the parameters out with ``*args, **kwargs``
-
-=====================================
-A bit more on mutability (and copies)
-=====================================
+ In [3]: s.lower().count('t')
+ Out[3]: 3
-mutable objects
-----------------
-
-We've talked about this: mutable objects can have their contents changed in place.
-
-Immutable objects can not.
+set.update()
+------------
-This has implications when you have a container with mutable objects in it:
+If you want to add a bunch of stuff to a set, you can use update:
.. code-block:: ipython
- In [28]: list1 = [ [1,2,3], ['a','b'] ]
+ In [1]: s = set()
-one way to make a copy of a list:
+In [2]: s.update
+Out[2]:
-.. code-block:: ipython
+In [3]: s.update(['this', 'that'])
- In [29]: list2 = list1[:]
+In [4]: s
+Out[4]: {'that', 'this'}
- In [30]: list2 is list1
- Out[30]: False
+In [5]: s.update(['this', 'thatthing'])
-they are different lists.
+In [6]: s
+Out[6]: {'that', 'thatthing', 'this'}
-.. nextslide::
+**NOTE:** It's VERY often the case that when you find yourself writing a trivial loop -- there is a way to do it with a built in method!
-What if we set an element to a new value?
-.. code-block:: ipython
- In [31]: list1[0] = [5,6,7]
-
- In [32]: list1
- Out[32]: [[5, 6, 7], ['a', 'b']]
-
- In [33]: list2
- Out[33]: [[1, 2, 3], ['a', 'b']]
+Sorting stuff in dictionaries:
+-------------------------------
-So they are independent.
+dicts aren't sorted, so what if you want to do something in a sorted way?
-.. nextslide::
+The "standard" way:
-But what if we mutate an element?
+.. code-block:: python
-.. code-block:: ipython
+ for key in sorted(d.keys()):
+ ...
- In [34]: list1[1].append('c')
+Another option:
- In [35]: list1
- Out[35]: [[5, 6, 7], ['a', 'b', 'c']]
+.. code-block:: python
- In [36]: list2
- Out[36]: [[1, 2, 3], ['a', 'b', 'c']]
+ collections.OrderedDict
-uuh oh! mutating an element in one list mutated the one in the other list.
+Also other nifty stuff in the ``collections`` module:
-.. nextslide::
+https://docs.python.org/3.5/library/collections.html
-Why is that?
+Using files and "with"
+-----------------------
-.. code-block:: ipython
+Sorry for the confusion, but I'll be more clear now.
- In [38]: list1[1] is list2[1]
- Out[38]: True
+When working with files, unless you have a good reason not to, use ``with``:
-The elements are the same object!
+.. code-block:: python
-This is known as a "shallow" copy -- Python doesn't want to copy more than it needs to, so in this case, it makes a new list, but does not make copies of the contents.
+ with open(the_filename, 'w') as outfile:
+ outfile.write(something)
+ do_some_more...
+ # now done with out file -- it will be closed, regardless of errors, etc.
+ do_other_stuff
-Same for dicts (and any container type)
+``with`` invokes a context manager -- which can be confusing, but for now,
+just follow this pattern -- it really is more robust.
-If the elements are immutable, it doesn't really make a differnce -- but be very careful with mutable elements.
+And you can even do two at once:
+.. code-block:: python
-The copy module
---------------------
+ with open(source, 'rb') as infile, open(dest, 'wb') as outfile:
+ outfile.write(infile.read())
-most objects have a way to make copies (``dict.copy()`` for instance).
-but if not, you can use the ``copy`` module to make a copy:
+Binary files
+------------
-.. code-block:: ipython
+Python can open files in one of two modes:
- In [39]: import copy
+ * Text
+ * Binary
- In [40]: list3 = copy.copy(list2)
+This is just what you'd think -- if the file contains text, you want text mode. If the file contains arbitrary binary data, you want binary mode.
- In [41]: list3
- Out[41]: [[1, 2, 3], ['a', 'b', 'c']]
+All data in all files is binary -- that's how computers work. So in Python3, "text" actually means Unicode -- which is a particular system for matching characters to binary data.
-This is also a shallow copy.
+But this too is complicated -- there are multiple ways that binary data can be mapped to Unicode text, known as "encodings". In Python, text files are by default opened with the "utf-8" encoding. These days, that mostly "just works".
.. nextslide::
-But there is another option:
+But if you read a binary file as text, then Python will try to interpret the bytes as utf-8 encoded text -- and this will likely fail:
.. code-block:: ipython
- In [3]: list1
- Out[3]: [[1, 2, 3], ['a', 'b', 'c']]
-
- In [4]: list2 = copy.deepcopy(list1)
+ In [13]: open("a_photo.jpg").read()
+ ---------------------------------------------------------------------------
+ UnicodeDecodeError Traceback (most recent call last)
+ in ()
+ ----> 1 open("PassportPhoto.JPG").read()
- In [5]: list1[0].append(4)
+ /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/codecs.py in decode(self, input, final)
+ 319 # decode input (taking the buffer into account)
+ 320 data = self.buffer + input
+ --> 321 (result, consumed) = self._buffer_decode(data, self.errors, final)
+ 322 # keep undecoded input until the next call
+ 323 self.buffer = data[consumed:]
- In [6]: list1
- Out[6]: [[1, 2, 3, 4], ['a', 'b', 'c']]
-
- In [7]: list2
- Out[7]: [[1, 2, 3], ['a', 'b', 'c']]
-
-``deepcopy`` recurses through the object, making copies of everything as it goes.
+ UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
.. nextslide::
+In Python2, it's less likely that you'll get an error like this -- it doesn't try to decode the file as it's read -- even for text files -- so it's a bit tricky and more error prone.
-I happened on this thread on stack overflow:
-
-http://stackoverflow.com/questions/3975376/understanding-dict-copy-shallow-or-deep
-
-
-The OP is pretty confused -- can you sort it out?
-
-Make sure you understand the difference between a reference, a shallow copy, and a deep copy.
+**NOTE:** If you want to actually DO anything with a binary file, other than passing it around, then you'll need to know a lot about how the details of what the bytes in the file mean -- and most likely, you'll use a library for that -- like an image processing library for the jpeg example above.
-Mutables as default arguments:
-------------------------------
-Another "gotcha" is using mutables as default arguments:
+PEP 8 reminder
+--------------
-.. code-block:: ipython
+PEP 8 (Python Enhancement Proposal 8): https://www.python.org/dev/peps/pep-0008/
- In [11]: def fun(x, a=[]):
- ....: a.append(x)
- ....: print a
- ....:
+Is the "official" style guide for Python code.
-This makes sense: maybe you'd pass in a list, but the default is an empty list.
+Strictly speaking, you only need to follow it for code in the standard library.
-But:
+But style matters -- consistent style makes your code easier to read and understand.
-.. code-block:: ipython
+So **follow PEP 8**
- In [12]: fun(3)
- [3]
+**Exception:** if you have a company style guide -- follow that instead.
- In [13]: fun(4)
- [3, 4]
+Try the "pycodestyle" module on your code::
-Huh?!
-
-.. nextslide::
+ $ python3 -m pip install pycodestyle
+ $ pycodestyle my_python_file
-Remember that that default argument is defined when the function is created: there will be only one list, and every time the function is called, that same list is used.
+(demo)
+Naming things...
+----------------
-The solution:
+It matters what names you give your variables.
-The standard practice for such a mutable default argument:
+Python has rules about what it *allows*
-.. code-block:: ipython
+PEP8 has rules for style: capitalization, and underscores and all that.
- In [15]: def fun(x, a=None):
- ....: if a is None:
- ....: a = []
- ....: a.append(x)
- ....: print a
- In [16]: fun(3)
- [3]
- In [17]: fun(4)
- [4]
+But you still get to decide within those rules.
-You get a new list every time the function is called
+So use names that make sense to the reader.
+Naming Guidelines
+-----------------
-============================
-List and Dict Comprehensions
-============================
+Only use single-letter names for things with limited scope: indexes and the like:
-List comprehensions
--------------------
-A bit of functional programming
+.. code-block:: python
+ for i, item in enumerate(a_sequence):
+ do_something(i, item)
-consider this common for loop structure:
+**Don't** use a name like "item", when there is a meaning to what the item is:
-.. code-block:: python
+.. code-block:: python
- new_list = []
- for variable in a_list:
- new_list.append(expression)
+ for name in all_the_names:
+ do_something_with(name)
-This can be expressed with a single line using a "list comprehension"
+Use plurals for collections of things:
.. code-block:: python
- new_list = [expression for variable in a_list]
-
+ names = ['Fred', 'George', ...]
.. nextslide::
+**Do** re-use names when the use is essentially the same, and you don't need the old one:
-What about nested for loops?
+.. code-block:: python
-.. code-block:: python
+ line = line.strip()
+ line = line.replace(",", " ")
+ ....
- new_list = []
- for var in a_list:
- for var2 in a_list2:
- new_list.append(expression)
+Here's a nice talk about naming:
-Can also be expressed in one line:
+http://pyvideo.org/video/3792/name-things-once-0
-.. code-block:: python
- new_list = [exp for var in a_list for var2 in a_list2]
+Code Review
+------------
-You get the "outer product", i.e. all combinations.
+.. rst-class:: center medium
-(demo)
+Anyone stuck or confused that's willing to volunteer for a live code review?
-.. nextslide::
+My Solutions
+-------------
-But usually you at least have a conditional in the loop:
+Anyone look at my solutions?
-.. code-block:: python
+(yeah, not much time for that...)
- new_list = []
- for variable in a_list:
- if something_is_true:
- new_list.append(expression)
+Anything in particular you'd like me to go over?
-You can add a conditional to the comprehension:
-.. code-block:: python
+trigrams
+--------
- new_list = [expr for var in a_list if something_is_true]
+Let's take a close look at trigrams!
+Some of you have already done a nice solution to this.
+But some of you are not sure how to start.
-(demo)
+So let's start from the beginning...
-.. nextslide::
+NOTE: think about set vs list.
-Examples:
+(demo)
-.. code-block:: ipython
+Lightning Talks
+----------------
- In [341]: [x**2 for x in range(3)]
- Out[341]: [0, 1, 4]
+.. rst-class:: medium
- In [342]: [x+y for x in range(3) for y in range(5,7)]
- Out[342]: [5, 6, 6, 7, 7, 8]
-
- In [343]: [x*2 for x in range(6) if not x%2]
- Out[343]: [0, 4, 8]
+|
+| Alexander C Truong
+|
+|
+| Darryl Wong
+|
+==========
+Exceptions
+==========
+A really nifty python feature -- really handy!
-.. nextslide::
+Exceptions
+----------
-Remember this from last week?
+Another Branching structure:
-.. code-block:: python
+.. code-block:: python
- [name for name in dir(__builtin__) if "Error" in name]
- ['ArithmeticError',
- 'AssertionError',
- 'AttributeError',
- 'BufferError',
- 'EOFError',
- ....
+ try:
+ do_something()
+ f = open('missing.txt')
+ process(f) # never called if file missing
+ except IOError:
+ print("couldn't open missing.txt")
+Exceptions
+----------
+Never Do this:
-Set Comprehensions
-------------------
+.. code-block:: python
-You can do it with sets, too:
+ try:
+ do_something()
+ f = open('missing.txt')
+ process(f) # never called if file missing
+ except:
+ print "couldn't open missing.txt"
-.. code-block:: python
+**always** capture the *particular* Exception you know how to handle.
- new_set = { value for variable in a_sequence }
+Exceptions
+----------
-same as for loop:
+Use Exceptions, rather than your own tests:
-.. code-block:: python
+Don't do this:
- new_set = set()
- for key in a_list:
- new_set.add(value)
+.. code-block:: python
+ do_something()
+ if os.path.exists('missing.txt'):
+ f = open('missing.txt')
+ process(f)
+It will almost always work -- but the almost will drive you crazy
.. nextslide::
-Example: finding all the vowels in a string...
-
-.. code-block:: ipython
-
- In [19]: s = "a not very long string"
-
- In [20]: vowels = set('aeiou')
-
- In [21]: { let for let in s if let in vowels }
- Out[21]: {'a', 'e', 'i', 'o'}
-
-Side note: why did I do ``set('aeiou')`` rather than just `aeiou` ?
-
-
-Dict Comprehensions
--------------------
-
-Also with dictionaries
+Example from homework
.. code-block:: python
- new_dict = { key:value for variable in a_sequence}
+ if num_in.isdigit():
+ num_in = int(num_in)
+but -- ``int(num_in)`` will only work if the string can be converted to an integer.
-same as for loop:
+So you can do
.. code-block:: python
- new_dict = {}
- for key in a_list:
- new_dict[key] = value
-
-
-
-.. nextslide::
-
-Example
-
-.. code-block:: ipython
-
- In [22]: { i: "this_%i"%i for i in range(5) }
- Out[22]: {0: 'this_0', 1: 'this_1', 2: 'this_2',
- 3: 'this_3', 4: 'this_4'}
-
+ try:
+ num_in = int(num_in)
+ except ValueError:
+ print("Input must be an integer, try again.")
-(not as useful with the ``dict()`` constructor...)
+Or let the Exception be raised....
-===================
-Anonymous functions
-===================
+EAFP
+----
-lambda
-------
-.. code-block:: ipython
+"it's Easier to Ask Forgiveness than Permission"
- In [171]: f = lambda x, y: x+y
- In [172]: f(2,3)
- Out[172]: 5
+ -- Grace Hopper
-Content can only be an expression -- not a statement
-Anyone remember what the difference is?
+http://www.youtube.com/watch?v=AZDWveIdqjY
-Called "Anonymous": it doesn't need a name.
+(PyCon talk by Alex Martelli)
-.. nextslide::
-It's a python object, it can be stored in a list or other container
+.. nextslide:: Do you catch all Exceptions?
-.. code-block:: ipython
+For simple scripts, let exceptions happen.
- In [7]: l = [lambda x, y: x+y]
- In [8]: type(l[0])
- Out[8]: function
+Only handle the exception if the code can and will do something about it.
+(much better debugging info when an error does occur)
-And you can call it:
-.. code-block:: ipython
+Exceptions -- finally
+---------------------
- In [9]: l[0](3,4)
- Out[9]: 7
+.. code-block:: python
+ try:
+ do_something()
+ f = open('missing.txt')
+ process(f) # never called if file missing
+ except IOError:
+ print("couldn't open missing.txt")
+ finally:
+ do_some_clean-up
-Functions as first class objects
----------------------------------
+The ``finally:`` clause will always run
-You can do that with "regular" functions too:
-.. code-block:: ipython
+Exceptions -- else
+-------------------
- In [12]: def fun(x,y):
- ....: return x+y
- ....:
- In [13]: l = [fun]
- In [14]: type(l[0])
- Out[14]: function
- In [15]: l[0](3,4)
- Out[15]: 7
+.. code-block:: python
+ try:
+ do_something()
+ f = open('missing.txt')
+ except IOError:
+ print("couldn't open missing.txt")
+ else:
+ process(f) # only called if there was no exception
+Advantage:
-======================
-Functional Programming
-======================
+you know where the Exception came from
-map
----
+Exceptions -- using them
+------------------------
-``map`` "maps" a function onto a sequence of objects -- It applies the function to each item in the list, returning another list
+.. code-block:: python
+ try:
+ do_something()
+ f = open('missing.txt')
+ except IOError as the_error:
+ print(the_error)
+ the_error.extra_info = "some more information"
+ raise
-.. code-block:: ipython
- In [23]: l = [2, 5, 7, 12, 6, 4]
- In [24]: def fun(x):
- return x*2 + 10
- In [25]: map(fun, l)
- Out[25]: [14, 20, 24, 34, 22, 18]
+Particularly useful if you catch more than one exception:
+.. code-block:: python
-But if it's a small function, and you only need it once:
+ except (IOError, BufferError, OSError) as the_error:
+ do_something_with (the_error)
-.. code-block:: ipython
- In [26]: map(lambda x: x*2 + 10, l)
- Out[26]: [14, 20, 24, 34, 22, 18]
+Raising Exceptions
+-------------------
+.. code-block:: python
-filter
-------
+ def divide(a,b):
+ if b == 0:
+ raise ZeroDivisionError("b can not be zero")
+ else:
+ return a / b
-``filter`` "filters" a sequence of objects with a boolean function --
-It keeps only those for which the function is True
-To get only the even numbers:
+when you call it:
.. code-block:: ipython
- In [27]: l = [2, 5, 7, 12, 6, 4]
- In [28]: filter(lambda x: not x%2, l)
- Out[28]: [2, 12, 6, 4]
-
-
-
-reduce
-------
+ In [515]: divide (12,0)
+ ZeroDivisionError: b can not be zero
-``reduce`` "reduces" a sequence of objects to a single object with a function that combines two arguments
-To get the sum:
-
-.. code-block:: ipython
+Built in Exceptions
+-------------------
- In [30]: l = [2, 5, 7, 12, 6, 4]
- In [31]: reduce(lambda x,y: x+y, l)
- Out[31]: 36
+You can create your own custom exceptions
+But...
-To get the product:
+.. code-block:: python
-.. code-block:: ipython
+ exp = \
+ [name for name in dir(__builtin__) if "Error" in name]
+ len(exp)
+ 32
- In [32]: reduce(lambda x,y: x*y, l)
- Out[32]: 20160
+For the most part, you can/should use a built in one
-Comprehensions
---------------
-
-Couldn't you do all this with comprehensions?
+.. nextslide::
-Yes:
+Choose the best match you can for the built in Exception you raise.
-.. code-block:: ipython
+Example (from last week's exercises)::
- In [33]: [x+2 + 10 for x in l]
- Out[33]: [14, 17, 19, 24, 18, 16]
- In [34]: [x for x in l if not x%2]
- Out[34]: [2, 12, 6, 4]
+ if (not isinstance(m, int)) or (not isinstance(n, int)):
+ raise ValueError
+Is it the *value* or the input the problem here?
-(Except Reduce)
+Nope: the *type* is the problem::
-But Guido thinks almost all uses of reduce are really ``sum()``
+ if (not isinstance(m, int)) or (not isinstance(n, int)):
+ raise TypeError
-Functional Programming
-----------------------
+but should you be checking type anyway? (EAFP)
-Comprehensions and map, filter, reduce are all "functional programming" approaches}
+===
+LAB
+===
-``map, filter`` and ``reduce`` pre-date comprehensions in Python's history
+Exceptions Lab:
-Some people like that syntax better
-And "map-reduce" is a big concept these days for parallel processing of "Big Data" in NoSQL databases.
+:ref:`exercise_exceptions_lab`
-(Hadoop, MongoDB, etc.)
+Lightning Talks
+---------------
-A bit more about lambda
-------------------------
+.. rst-class:: medium
-Can also use keyword arguments}
+|
+| Madhumita Acharya
+|
+| Matthew T Weidner
-.. code-block:: ipython
-
- In [186]: l = []
- In [187]: for i in range(3):
- l.append(lambda x, e=i: x**e)
- .....:
- In [189]: for f in l:
- print f(3)
- 1
- 3
- 9
-
-Note when the keyword argument is evaluated: this turns out to be very handy!
-=========
-Homework
-=========
+============================
+List and Dict Comprehensions
+============================
List comprehensions
---------------------
+-------------------
-Note: this is a bit of a "backwards" exercise --
-we show you code, you figure out what it does.
+A bit of functional programming
-As a result, not much to submit -- but so we can give you credit, submit
-a file with a solution to the final problem.
+consider this common ``for`` loop structure:
.. code-block:: python
- >>> feast = ['lambs', 'sloths', 'orangutans', 'breakfast cereals', 'fruit bats']
-
- >>> comprehension = [delicacy.capitalize() for delicacy in feast]
+ new_list = []
+ for variable in a_list:
+ new_list.append(expression)
-What is the output of:
+This can be expressed with a single line using a "list comprehension"
.. code-block:: python
- >>> comprehension[0]
- ???
-
- >>> comprehension[2]
- ???
+ new_list = [expression for variable in a_list]
-(figure it out before you try it)
-.. nextslide:: 2. Filtering lists with list comprehensions
+.. nextslide::
+What about nested for loops?
.. code-block:: python
- >>> feast = ['spam', 'sloths', 'orangutans', 'breakfast cereals',
- 'fruit bats']
-
- >>> comprehension = [delicacy for delicacy in feast if len(delicacy) > 6]
+ new_list = []
+ for var in a_list:
+ for var2 in a_list2:
+ new_list.append(expression)
-What is the output of:
+Can also be expressed in one line:
.. code-block:: python
- >>> len(feast)
- ???
+ new_list = [exp for var in a_list for var2 in a_list2]
- >>> len(comprehension)
- ???
+You get the "outer product", i.e. all combinations.
-(figure it out first!)
+(demo)
-.. nextslide:: 3. Unpacking tuples in list comprehensions
+.. nextslide::
+But usually you at least have a conditional in the loop:
.. code-block:: python
- >>> list_of_tuples = [(1, 'lumberjack'), (2, 'inquisition'), (4, 'spam')]
-
- >>> comprehension = [ skit * number for number, skit in list_of_tuples ]
+ new_list = []
+ for variable in a_list:
+ if something_is_true:
+ new_list.append(expression)
-What is the output of:
+You can add a conditional to the comprehension:
.. code-block:: python
- >>> comprehension[0]
- ???
-
- >>> len(comprehension[2])
- ???
-
-.. nextslide:: 4. Double list comprehensions
-
-.. code-block:: python
+ new_list = [expr for var in a_list if something_is_true]
- >>> list_of_eggs = ['poached egg', 'fried egg']
- >>> list_of_meats = ['lite spam', 'ham spam', 'fried spam']
+(demo)
- >>> comprehension = [ '{0} and {1}'.format(egg, meat) for egg in list_of_eggs for meat in list_of_meats]
+.. nextslide::
-What is the output of:
+Examples:
-.. code-block:: python
+.. code-block:: ipython
- >>> len(comprehension)
- ???
+ In [341]: [x**2 for x in range(3)]
+ Out[341]: [0, 1, 4]
- >>> comprehension[0]
- ???
+ In [342]: [x+y for x in range(3) for y in range(5,7)]
+ Out[342]: [5, 6, 6, 7, 7, 8]
-.. nextslide:: 5. Set comprehensions
+ In [343]: [x*2 for x in range(6) if not x%2]
+ Out[343]: [0, 4, 8]
-.. code-block:: python
- >>> comprehension = { x for x in 'aabbbcccc'}
+.. nextslide::
-What is the output of:
+Remember this from earlier today?
.. code-block:: python
- >>> comprehension
- ???
-
-.. nextslide:: 6. Dictionary comprehensions
-
+ [name for name in dir(__builtin__) if "Error" in name]
+ ['ArithmeticError',
+ 'AssertionError',
+ 'AttributeError',
+ 'BufferError',
+ 'EOFError',
+ ....
-.. 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.iteritems() if weapon}
+Set Comprehensions
+------------------
-What is the output of:
+You can do it with sets, too:
.. code-block:: python
- >>> 'first' in dict_comprehension
- ???
- >>> 'FIRST' in dict_comprehension
- ???
- >>> len(dict_of_weapons)
- ???
- >>> len(dict_comprehension)
- ???
-
-.. nextslide:: Other resources
-
+ new_set = { value for variable in a_sequence }
-See also:
-https://github.com/gregmalcolm/python_koans
+same as for loop:
-https://github.com/gregmalcolm/python_koans/blob/master/python2/koans/about_comprehension.py
+.. code-block:: python
+ new_set = set()
+ for key in a_list:
+ new_set.add(value)
-.. nextslide:: 7. Count even numbers
+.. nextslide::
-(submit this one to gitHub for credit on this assignment)
+Example: finding all the vowels in a string...
-This is from CodingBat "count_evens" (http://codingbat.com/prob/p189616)
+.. code-block:: ipython
-*Using a list comprehension*, return the number of even ints in the given array.
+ In [19]: s = "a not very long string"
-Note: the % "mod" operator computes the remainder, e.g. ``5 % 2`` is 1.
+ In [20]: vowels = set('aeiou')
-.. code-block:: python
+ In [21]: { l for l in s if l in vowels }
+ Out[21]: {'a', 'e', 'i', 'o'}
- count_evens([2, 1, 2, 3, 4]) == 3
+Side note: why did I do ``set('aeiou')`` rather than just `aeiou` ?
- count_evens([2, 2, 0]) == 3
- count_evens([1, 3, 5]) == 0
+Dict Comprehensions
+-------------------
+Also with dictionaries
.. code-block:: python
- def count_evens(nums):
- one_line_comprehension_here
-
-
-``dict`` and ``set`` comprehensions
-------------------------------------
-
-Let's revisiting the dict/set lab -- see how much you can do with
-comprehensions instead.
+ new_dict = { key:value for variable in a_sequence}
-Specifically, look at these:
-First a slightly bigger, more interesting (or at least bigger..) dict:
+same as for loop:
.. code-block:: python
- food_prefs = {"name": u"Chris",
- u"city": u"Seattle",
- u"cake": u"chocolate",
- u"fruit": u"mango",
- u"salad": u"greek",
- u"pasta": u"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).
+ new_dict = {}
+ for key in a_list:
+ new_dict[key] = value
-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 three sets
-
- - loop through that sequence to build the sets up -- so no repeated code.
-
- 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!)
-
-
-lambda and keyword argument magic
------------------------------------
+Example
-Write a function that returns a list of n functions,
-such that each one, when called, will return the input value,
-incremented by an increasing number.
+.. code-block:: ipython
-Use a for loop, ``lambda``, and a keyword argument
+ In [22]: { i: "this_%i"%i for i in range(5) }
+ Out[22]: {0: 'this_0', 1: 'this_1', 2: 'this_2',
+ 3: 'this_3', 4: 'this_4'}
-( Extra credit ):
-Do it with a list comprehension, instead of a for loop
+(not as useful with the ``dict()`` constructor...)
+===
+LAB
+===
-Not clear? here's what you should get
+Here is a nice tutorial on list comprehensions:
-.. nextslide:: Example calling code
+http://treyhunner.com/2015/12/python-list-comprehensions-now-in-color/
-.. code-block:: ipython
+List comps exercises:
- In [96]: the_list = function_builder(4)
- ### so the_list should contain n functions (callables)
- In [97]: the_list[0](2)
- Out[97]: 2
- ## the zeroth element of the list is a function that add 0
- ## to the input, hence called with 2, returns 2
- In [98]: the_list[1](2)
- Out[98]: 3
- ## the 1st element of the list is a function that adds 1
- ## to the input value, thus called with 2, returns 3
- In [100]: for f in the_list:
- print f(5)
- .....:
- 5
- 6
- 7
- 8
- ### If you loop through them all, and call them, each one adds one more
- to the input, 5... i.e. the nth function in the list adds n to the input.
-
-
-
-
-Functional files
------------------
+:ref:`exercise_comprehensions`
-Write a program that takes a filename and "cleans" the file be removing all the leading and trailing whitespace from each line.
-Read in the original file and write out a new one, either creating a new file or overwriting the existing one.
-Give your user the option of which to perform.
+=========
+Homework
+=========
-Use ``map()`` to do the work.
+Catch up!
+---------
-Write a second version using a comprehension.
+* Finish the LABs from today
+ - Exceptions lab
-.. nextslide:: Hint
+* Catch up from last week.
-``sys.argv`` hold the command line arguments the user typed in. If the user types:
+ - Add Exception handling to mailroom
+ - And list (and dict, and set) comprehensions...
-.. code-block:: bash
+* If you've done all that -- check out the collections module:
- $ python the_script a_file_name
+ - https://docs.python.org/3.5/library/collections.html
+ - here's a good overview: https://pymotw.com/3/collections/
-Then:
+====================================
+Material to review before next week:
+====================================
-.. code-block:: python
+**Unit Testing:**
- import sys
- filename = sys.argv[1]
+* Dive into Python: chapter 9:
+ http://www.diveintopython3.net/unit-testing.html
-will get ``filename == "a_file_name"``
+NOTE: you will find that most introductions to unit testing with Python use the builtin ``unitest`` module. However, it is a bit heavyweight, and requires some knowledge of OOP -- classes, etc. So we'll be using pytest in this class: http://doc.pytest.org/en/latest/. But the principles of testing are the same.
+* Ned Batchelder's intro to testing presentation:
-Recommended Reading
----------------------
+ - http://nedbatchelder.com/text/test0.html
-* LPTHW: Ex 40 - 45
+** Advanced Argument Passing
-http://learnpythonthehardway.org/book/
+* arguments and parameters:
-* Dive Into Python: chapter 4, 5
+ - http://stupidpythonideas.blogspot.com/2013/08/arguments-and-parameters.html
-http://www.diveintopython.net/toc/index.html
+ - https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/
diff --git a/slides_sources/source/session06.rst b/slides_sources/source/session06.rst
index c995604c..d5e624b9 100644
--- a/slides_sources/source/session06.rst
+++ b/slides_sources/source/session06.rst
@@ -1,11 +1,20 @@
+.. include:: include.rst
-.. Foundations 2: Python slides file, created by
- hieroglyph-quickstart on Wed Apr 2 18:42:06 2014.
+***********************************************
+Session Six: Testing, Advanced Argument Passing
+***********************************************
-******************************************************************************************
-Session Six: Object oriented programming: Classes, instances, attributes, and subclassing
-******************************************************************************************
+======================
+Lightning Talks Today:
+======================
+.. rst-class:: medium
+
+ Adam Hollis
+
+ Nachiket Galande
+
+ Paul A Casey
================
Review/Questions
@@ -14,690 +23,812 @@ Review/Questions
Review of Previous Class
------------------------
-* Argument Passing: ``*args``, ``**kwargs``
+* Exceptions
-* comprehensions
-
-* ``lambda``
+* Comprehensions
+===============
Homework review
----------------
+===============
Homework Questions?
-If it seems harder than it should be -- it is!
+Notes from Homework:
+--------------------
-My Solution to the trigram:
+Comparing to "singletons":
- * (``dict.setdefault()`` trick...)
+Use:
-``global`` keyword?
+``if something is None``
-Unicode Notes
--------------
+Not:
-To put unicode in your source file, put:
+``if something == None``
-.. code-block:: python
+(also ``True`` and ``False``)
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
+rich comparisons: numpy
-at the top of your file ... and be sure to save it as utf-8!
-(file->save with encoding in Sublime)
+(demo)
-You also might want to put::
+.. nextslide::
- from __future__ import unicode_literals
+You don't actually need to use the result of a list comp:
+.. code-block:: python
-Additional notes on using Unicode in Python see:
+ for i, st in zip( divisors, sets):
+ [ st.add(j) for j in range(21) if not j%i ]
- :ref:`unicode_supplement`
+.. nextslide::
+Python functions are objects, so if you don't call them, you don't get an error, you just get the function object, usually not what you want::
-===========================
-Object Oriented Programming
-===========================
+ elif donor_name.lower == "exit":
-Object Oriented Programming
----------------------------
+this is comparing the string ``lower`` method to the string "exit" and they are never going to be equal!
-More about Python implementation than OO design/strengths/weaknesses
+That should be::
-One reason for this:
+ elif donor_name.lower() == "exit":
-Folks can't even agree on what OO "really" means
+This is actually a pretty common typo -- keep an eye out for it when you get strange errors, or something just doesn't seem to be getting triggered.
-See: The Quarks of Object-Oriented Development
+long strings
+------------
- - Deborah J. Armstrong
+if you need to do along string literal, sometimes a triple quoted string is perfect::
-http://agp.hx0.ru/oop/quarks.pdf
+ """this is a long string.
+ I want it to hvae multiple lines.
+ so having the line endings automatic is great.
+ """
+But you don't always want the line endings quite like that. And you may not want all that whitespace when fitting it into indented code.
-.. nextslide::
+It turns out that when you put a multiple strings together with no commas or anythign in between -- python will join them:
-Is Python a "True" Object-Oriented Language?
+.. code-block:: ipython
-(Doesn't support full encapsulation, doesn't *require*
-classes, etc...)
+ In [81]: "this is " "a string " "built up of parts"
+ Out[81]: 'this is a string built up of parts'
.. nextslide::
-.. rst-class:: center large
+If it's in parentheses, you can put the next chunk on the next line:
- I don't Care!
+.. code-block:: python
+ print("{} is from {}, and he likes "
+ "{} cake, {} fruit, {} salad, "
+ "and {} pasta.".format(food_prefs["name"],
+ food_prefs["city"],
+ food_prefs["cake"],
+ food_prefs["fruit"],
+ food_prefs["salad"],
+ food_prefs["pasta"]))
-Good software design is about code re-use, clean separation of concerns,
-refactorability, testability, etc...
+pretty print
+------------
-OO can help with all that, but:
- * It doesn't guarantee it
- * It can get in the way
+If you need to print our nested (or large) data structure in a more readable fashion, the "pretty print" module is handy:
-.. nextslide::
+.. code-block:: ipython
-Python is a Dynamic Language
+ from pprint import pprint
-That clashes with "pure" OO
+ In [28]: print(food_prefs)
+ {'pasta': 'lasagna', 'cake': 'chocolate', 'salad': 'greek', 'fruit': 'mango', 'name': 'Chris', 'city': 'Seattle'}
-Think in terms of what makes sense for your project
- -- not any one paradigm of software design.
+ In [29]: pprint(food_prefs)
+ {'cake': 'chocolate',
+ 'city': 'Seattle',
+ 'fruit': 'mango',
+ 'name': 'Chris',
+ 'pasta': 'lasagna',
+ 'salad': 'greek'}
+Exceptions
+----------
-.. nextslide::
+Adding stuff to an Exception:
-So what is "object oriented programming"?
+Example from slack
- "Objects can be thought of as wrapping their data
- within a set of functions designed to ensure that
- the data are used appropriately, and to assist in
- that use"
+Anything else?
+--------------
-http://en.wikipedia.org/wiki/Object-oriented_programming
+.. rst-class:: center medium
-.. nextslide::
+ Anything else you want me to go over?
-Even simpler:
+Lightning Talks
+----------------
-"Objects are data and the functions that act on them in one place."
+.. rst-class:: medium
-This is the core of "encapsulation"
+|
+| Adam Hollis
+|
+| Nachiket Galande
+|
-In Python: just another namespace.
+=======
+Testing
+=======
-.. nextslide::
+.. rst-class:: build left
+.. container::
-The OO buzzwords:
+ You've already seen a very basic testing strategy.
- * data abstraction
- * encapsulation
- * modularity
- * polymorphism
- * inheritance
+ You've written some tests using that strategy.
-Python does all of this, though it doesn't enforce it.
+ These tests were pretty basic, and a bit awkward in places (testing error
+ conditions in particular).
-.. nextslide::
+ .. rst-class:: centered large
-You can do OO in C
+ **It gets better**
-(see the GTK+ project)
+Test Runners
+------------
+So far our tests have been limited to code in an ``if __name__ == "__main__":``
+block.
-"OO languages" give you some handy tools to make it easier (and safer):
+.. rst-class:: build
- * polymorphism (duck typing gives you this anyway)
- * inheritance
+* They are run only when the file is executed
+* They are always run when the file is executed
+* You can't do anything else when the file is executed without running tests.
+.. rst-class:: build
+.. container::
-.. nextslide::
+ This is not optimal.
-OO is the dominant model for the past couple decades
+ Python provides testing systems to help.
-You will need to use it:
-- It's a good idea for a lot of problems
+Standard Library: ``unittest``
+-------------------------------
-- You'll need to work with OO packages
+The original testing system in Python.
-(Even a fair bit of the standard library is Object Oriented)
+``import unittest``
+More or less a port of ``Junit`` from Java
-.. nextslide:: Some definitions
+A bit verbose: you have to write classes & methods
-class
- A category of objects: particular data and behavior: A "circle" (same as a type in python)
+(And we haven't covered that yet!)
-instance
- A particular object of a class: a specific circle
-object
- The general case of a instance -- really any value (in Python anyway)
+Using ``unittest``
+-------------------
-attribute
- Something that belongs to an object (or class): generally thought of
- as a variable, or single object, as opposed to a ...
+You write subclasses of the ``unittest.TestCase`` class:
-method
- A function that belongs to a class
+.. code-block:: python
-.. nextslide::
+ # in test.py
+ import unittest
-.. rst-class:: center
+ class MyTests(unittest.TestCase):
+ def test_tautology(self):
+ self.assertEquals(1, 1)
- Note that in python, functions are first class objects, so a method *is* an attribute
+Then you run the tests by using the ``main`` function from the ``unittest``
+module:
+.. code-block:: python
-==============
-Python Classes
-==============
+ # in test.py
+ if __name__ == '__main__':
+ unittest.main()
-Python Classes
---------------
+.. nextslide:: Testing Your Code
-The ``class`` statement
+This way, you can write your code in one file and test it from another:
-``class`` creates a new type object:
+.. code-block:: python
-.. code-block:: ipython
+ # in my_mod.py
+ def my_func(val1, val2):
+ return val1 * val2
- In [4]: class C(object):
- pass
- ...:
- In [5]: type(C)
- Out[5]: type
+ # in test_my_mod.py
+ import unittest
+ from my_mod import my_func
-A class is a type -- interesting!
+ class MyFuncTestCase(unittest.TestCase):
+ def test_my_func(self):
+ test_vals = (2, 3)
+ expected = reduce(lambda x, y: x * y, test_vals)
+ actual = my_func(*test_vals)
+ self.assertEquals(expected, actual)
-It is created when the statement is run -- much like ``def``
+ if __name__ == '__main__':
+ unittest.main()
-You don't *have* to subclass from ``object``, but you *should*
+.. nextslide:: Advantages of ``unittest``
-(note on "new style" classes)
+.. rst-class:: build
+.. container::
-.. nextslide::
+ The ``unittest`` module is pretty full featured
-About the simplest class you can write
+ It comes with the standard Python distribution, no installation required.
-.. code-block:: python
+ It provides a wide variety of assertions for testing all sorts of situations.
- >>> class Point(object):
- ... x = 1
- ... y = 2
- >>> Point
-
- >>> Point.x
- 1
- >>> p = Point()
- >>> p
- <__main__.Point instance at 0x2de918>
- >>> p.x
- 1
+ It allows for a setup and tear down workflow both before and after all tests and before and after each test.
-.. nextslide::
+ It's well known and well understood.
-Basic Structure of a real class:
+.. nextslide:: Disadvantages:
-.. code-block:: python
+.. rst-class:: build
+.. container::
- class Point(object):
- # everything defined in here is in the class namespace
- def __init__(self, x, y):
- self.x = x
- self.y = y
+ It's Object Oriented, and quite "heavyweight".
- ## create an instance of the class
- p = Point(3,4)
+ - modeled after Java's ``junit`` and it shows...
- ## access the attributes
- print "p.x is:", p.x
- print "p.y is:", p.y
+ It uses the framework design pattern, so knowing how to use the features
+ means learning what to override.
+ Needing to override means you have to be cautious.
-see: ``Examples/Session06/simple_class``
+ Test discovery is both inflexible and brittle.
-.. nextslide::
+ And there is no built-in parameterized testing.
-The Initializer
+Other Options
+-------------
-The ``__init__`` special method is called when a new instance of a class is created.
+There are several other options for running tests in Python.
-You can use it to do any set-up you need
+* `Nose`: https://nose.readthedocs.org/
-.. code-block:: python
+* `pytest`: http://pytest.org/latest/
- class Point(object):
- def __init__(self, x, y):
- self.x = x
- self.y = y
+* ... (many frameworks supply their own test runners: e.g. django)
+Both are very capable and widely used. I have a personal preference for pytest
-It gets the arguments passed when you call the class object:
+-- so we'll use it for this class
-.. code-block:: python
+Installing ``pytest``
+---------------------
- Point(x, y)
+The first step is to install the package:
-.. nextslide::
+.. code-block:: bash
+ $ python3 -m pip install pytest
-What is this ``self`` thing?
+Once this is complete, you should have a ``py.test`` command you can run
+at the command line:
-The instance of the class is passed as the first parameter for every method.
+.. code-block:: bash
-"``self``" is only a convention -- but you DO want to use it.
+ $ py.test
-.. code-block:: python
+If you have any tests in your repository, that will find and run them.
- class Point(object):
- def a_function(self, x, y):
- ...
+.. rst-class:: build
+.. container::
+ **Do you?**
-Does this look familiar from C-style procedural programming?
+Pre-existing Tests
+------------------
+Let's take a look at some examples.
-.. nextslide::
+in ``IntroPython2016\Examples\Session06``
-Anything assigned to a ``self.`` attribute is kept in the instance
-name space -- ``self`` *is* the instance.
+.. code-block:: bash
-That's where all the instance-specific data is.
+ $ py.test
-.. code-block:: python
+You can also run py.test on a particular test file:
- class Point(object):
- size = 4
- color= "red"
- def __init__(self, x, y):
- self.x = x
- self.y = y
+.. code-block:: bash
-.. nextslide::
+ $ py.test test_random_unitest.py
-Anything assigned in the class scope is a class attribute -- every
-instance of the class shares the same one.
+The results you should have seen when you ran ``py.test`` above come
+partly from these files.
-Note: the methods defined by ``def`` are class attributes as well.
+Let's take a few minutes to look these files over.
-The class is one namespace, the instance is another.
+[demo]
+What's Happening Here.
+----------------------
-.. code-block:: python
+When you run the ``py.test`` command, ``pytest`` starts in your current
+working directory and searches the filesystem for things that might be tests.
- class Point(object):
- size = 4
- color= "red"
- ...
- def get_color():
- return self.color
- >>> p3.get_color()
- 'red'
+It follows some simple rules:
+* Any python file that starts with ``test_`` or ``_test`` is imported.
-class attributes are accessed with ``self`` also.
+* Any functions in them that start with ``test_`` are run as tests.
+* Any classes that start with ``Test`` are treated similarly, with methods that begin with ``test_`` treated as tests.
-.. nextslide::
+( don't worry about "classes" part just yet ;-) )
-Typical methods:
+pytest
+------
-.. code-block:: python
+This test running framework is simple, flexible and configurable.
- class Circle(object):
- color = "red"
+Read the documentation for more information:
- def __init__(self, diameter):
- self.diameter = diameter
+http://pytest.org/latest/getting-started.html#getstarted
- def grow(self, factor=2):
- self.diameter = self.diameter * factor
+It will run ``unittest`` tests for you.
+But in addition to finding and running tests, it makes writting tests simple, and provides a bunch of nifty utilities to support more complex testing.
-Methods take some parameters, manipulate the attributes in ``self``.
-They may or may not return something useful.
+Test Driven Development
+-----------------------
+in the Examples dir, try::
-.. nextslide::
+ $ py.test test_cigar_party
-Gotcha!
+What we've just done here is the first step in what is called:
-.. code-block:: python
+.. rst-class:: centered
- ...
- def grow(self, factor=2):
- self.diameter = self.diameter * factor
- ...
- In [205]: C = Circle(5)
- In [206]: C.grow(2,3)
+ **Test Driven Development**.
- TypeError: grow() takes at most 2 arguments (3 given)
+A bunch of tests exist, but the code to make them pass does not yet exist.
-Huh???? I only gave 2
+The red you see in the terminal when we run our tests is a goad to us to write the code that fixes these tests.
-``self`` is implicitly passed in for you by python.
+Let's do that next!
-(demo of bound vs. unbound methods)
+Test Driven development demo
+-----------------------------
-LAB / homework
----------------
+Open up:
-Let's say you need to render some html..
+``Examples/Session06/test_cigar_party.py``
-The goal is to build a set of classes that render an html page.
+and:
-``Examples/Session06/sample_html.html``
+``Examples/Session06/cigar_party.py``
-We'll start with a single class, then add some sub-classes to specialize the behavior
+and run::
-Details in:
+ $ py.teset test_cigar_party.py
-:ref:`homework_html_renderer`
+Now go in to ``cigar_party.py`` and let's fix the tests.
+Let's play with codingbat.py also...
-Let's see if we can do step 1. in class...
+===
+LAB
+===
+.. rst-class:: left
-=======================
-Subclassing/Inheritance
-=======================
+ Pick an example from codingbat:
-Inheritance
------------
+ ``http://codingbat.com``
-In object-oriented programming (OOP), inheritance is a way to reuse code of existing objects, or to establish a subtype from an existing object.
+ Do a bit of test-driven development on it:
+ * run something on the web site.
+ * write a few tests using the examples from the site.
+ * then write the function, and fix it 'till it passes the tests.
-Objects are defined by classes, classes can inherit attributes and behavior from pre-existing classes called base classes or super classes.
+ Do at least two of these...
-The resulting classes are known as derived classes or subclasses.
+Lightning Talk
+--------------
-(http://en.wikipedia.org/wiki/Inheritance_%28object-oriented_programming%29)
+.. rst-class:: medium
-Subclassing
------------
+ |
+ | Paul A Casey
+ |
-A subclass "inherits" all the attributes (methods, etc) of the parent class.
+=========================
+Advanced Argument Passing
+=========================
-You can then change ("override") some or all of the attributes to change the behavior.
+This is a very, very nifty Python feature -- it really lets you write dynamic programs.
-You can also add new attributes to extend the behavior.
+Keyword arguments
+-----------------
-The simplest subclass in Python:
+When defining a function, you can specify only what you need -- in any order
-.. code-block:: python
+.. code-block:: ipython
- class A_subclass(The_superclass):
- pass
+ In [151]: def fun(x=0, y=0, z=0):
+ print(x,y,z)
+ .....:
+ In [152]: fun(1,2,3)
+ 1 2 3
+ In [153]: fun(1, z=3)
+ 1 0 3
+ In [154]: fun(z=3, y=2)
+ 0 2 3
-``A_subclass`` now has exactly the same behavior as ``The_superclass``
-NOTE: when we put ``object`` in there, it means we are deriving from object -- getting core functionality of all objects.
+.. nextslide::
-Overriding attributes
----------------------
-Overriding is as simple as creating a new attribute with the same name:
+A Common Idiom:
.. code-block:: python
- class Circle(object):
- color = "red"
+ def fun(x, y=None):
+ if y is None:
+ do_something_different
+ go_on_here
+
- ...
+.. nextslide::
+
+Can set defaults to variables
- class NewCircle(Circle):
- color = "blue"
- >>> nc = NewCircle
- >>> print nc.color
- blue
+.. code-block:: ipython
+ In [156]: y = 4
+ In [157]: def fun(x=y):
+ print("x is:", x)
+ .....:
+ In [158]: fun()
+ x is: 4
-all the ``self`` instances will have the new attribute.
-Overriding methods
-------------------
+.. nextslide::
+
+Defaults are evaluated when the function is defined
+
+.. code-block:: ipython
+
+ In [156]: y = 4
+ In [157]: def fun(x=y):
+ print("x is:", x)
+ .....:
+ In [158]: fun()
+ x is: 4
+ In [159]: y = 6
+ In [160]: fun()
+ x is: 4
+
+This is a **very** important point -- I will repeat it!
+
+
+Function arguments in variables
+-------------------------------
-Same thing, but with methods (remember, a method *is* an attribute in python)
+When a function is called, its arguments are really just:
+
+* a tuple (positional arguments)
+* a dict (keyword arguments)
.. code-block:: python
- class Circle(object):
- ...
- def grow(self, factor=2):
- """grows the circle's diameter by factor"""
- self.diameter = self.diameter * factor
- ...
+ def f(x, y, w=0, h=0):
+ print("position: {}, {} -- shape: {}, {}".format(x, y, w, h))
- class NewCircle(Circle):
- ...
- def grow(self, factor=2):
- """grows the area by factor..."""
- self.diameter = self.diameter * math.sqrt(2)
+ position = (3,4)
+ size = {'h': 10, 'w': 20}
+ >>> f(*position, **size)
+ position: 3, 4 -- shape: 20, 10
-all the instances will have the new method
-.. nextslide::
+Function parameters in variables
+--------------------------------
-Here's a program design suggestion:
- whenever you override a method, the
- interface of the new method should be the same as the old. It should take
- the same parameters, return the same type, and obey the same preconditions
- and postconditions.
+You can also pull the parameters out in the function as a tuple and a dict:
- If you obey this rule, you will find that any function
- designed to work with an instance of a superclass, like a Deck, will also work
- with instances of subclasses like a Hand or PokerHand. If you violate this
- rule, your code will collapse like (sorry) a house of cards.
+.. code-block:: ipython
-[ThinkPython 18.10]
+ def f(*args, **kwargs):
+ print("the positional arguments are:", args)
+ print("the keyword arguments are:", kwargs)
+ In [389]: f(2, 3, this=5, that=7)
+ the positional arguments are: (2, 3)
+ the keyword arguments are: {'this': 5, 'that': 7}
-( Demo of class vs. instance attributes )
+This can be very powerful...
-===================
-More on Subclassing
-===================
+Passing a dict to str.format()
+-------------------------------
-Overriding \_\_init\_\_
------------------------
+Now that you know that keyword args are really a dict,
+you know how this nifty trick works:
-``__init__`` common method to override}
+The string ``format()`` method takes keyword arguments:
-You often need to call the super class ``__init__`` as well
+.. code-block:: ipython
-.. code-block:: python
+ In [24]: "My name is {first} {last}".format(last="Barker", first="Chris")
+ Out[24]: 'My name is Chris Barker'
- class Circle(object):
- color = "red"
- def __init__(self, diameter):
- self.diameter = diameter
- ...
- class CircleR(Circle):
- def __init__(self, radius):
- diameter = radius*2
- Circle.__init__(self, diameter)
+Build a dict of the keys and values:
+.. code-block:: ipython
+ In [25]: d = {"last":"Barker", "first":"Chris"}
-exception to: "don't change the method signature" rule.
+And pass to ``format()``with ``**``
-More subclassing
-----------------
-You can also call the superclass' other methods:
+.. code-block:: ipython
+
+ In [26]: "My name is {first} {last}".format(**d)
+ Out[26]: 'My name is Chris Barker'
+
+Kinda handy for the dict lab, eh?
+
+This:
-.. code-block:: python
+.. code-block:: ipython
+
+ print("{} is from {}, and he likes "
+ "{} cake, {} fruit, {} salad, "
+ "and {} pasta.".format(food_prefs["name"],
+ food_prefs["city"],
+ food_prefs["cake"],
+ food_prefs["fruit"],
+ food_prefs["salad"],
+ food_prefs["pasta"]))
- class Circle(object):
- ...
- def get_area(self, diameter):
- return math.pi * (diameter/2.0)**2
+Becomes:
+
+.. code-block:: ipython
+ print("{name} is from {city}, and he likes "
+ "{cake} cake, {fruit} fruit, {salad} salad, "
+ "and {pasta} pasta.".format(**food_prefs))
- class CircleR2(Circle):
- ...
- def get_area(self):
- return Circle.get_area(self, self.radius*2)
+LAB
+----
-There is nothing special about ``__init__`` except that it gets called
-automatically when you instantiate an instance.
+Time to play with all this to get a feel for it.
+:ref:`exercise_args_kwargs_lab`
-When to Subclass
+This is not all that clearly specified -- the goal is for you to
+experiment with various ways to define and call functions, so you
+can understand what's possible, and what happens with each call.
+
+
+=====================================
+A bit more on mutability (and copies)
+=====================================
+
+mutable objects
----------------
-"Is a" relationship: Subclass/inheritance
+We've talked about this: mutable objects can have their contents changed in place.
+
+Immutable objects can not.
+
+This has implications when you have a container with mutable objects in it:
+
+.. code-block:: ipython
+
+ In [28]: list1 = [ [1,2,3], ['a','b'] ]
-"Has a" relationship: Composition
+one way to make a copy of a list:
+
+.. code-block:: ipython
+
+ In [29]: list2 = list1[:]
+
+ In [30]: list2 is list1
+ Out[30]: False
+
+they are different lists.
.. nextslide::
-"Is a" vs "Has a"
+What if we set an element to a new value?
-You may have a class that needs to accumulate an arbitrary number of objects.
+.. code-block:: ipython
-A list can do that -- so should you subclass list?
+ In [31]: list1[0] = [5,6,7]
-Ask yourself:
+ In [32]: list1
+ Out[32]: [[5, 6, 7], ['a', 'b']]
--- **Is** your class a list (with some extra functionality)?
+ In [33]: list2
+ Out[33]: [[1, 2, 3], ['a', 'b']]
-or
+So they are independent.
--- Does you class **have** a list?
+.. nextslide::
-You only want to subclass list if your class could be used anywhere a list can be used.
+But what if we mutate an element?
+.. code-block:: ipython
-Attribute resolution order
---------------------------
+ In [34]: list1[1].append('c')
-When you access an attribute:
+ In [35]: list1
+ Out[35]: [[5, 6, 7], ['a', 'b', 'c']]
-``An_Instance.something``
+ In [36]: list2
+ Out[36]: [[1, 2, 3], ['a', 'b', 'c']]
-Python looks for it in this order:
+uuh oh! mutating an element in one list mutated the one in the other list.
- * Is it an instance attribute ?
- * Is it a class attribute ?
- * Is it a superclass attribute ?
- * Is it a super-superclass attribute ?
- * ...
+.. nextslide::
+Why is that?
-It can get more complicated...
+.. code-block:: ipython
-http://www.python.org/getit/releases/2.3/mro/
+ In [38]: list1[1] is list2[1]
+ Out[38]: True
-http://python-history.blogspot.com/2010/06/method-resolution-order.html
+The elements are the same object!
+This is known as a "shallow" copy -- Python doesn't want to copy more than it needs to, so in this case, it makes a new list, but does not make copies of the contents.
-What are Python classes, really?
---------------------------------
+Same for dicts (and any container type -- even tuples!)
-Putting aside the OO theory...
+If the elements are immutable, it doesn't really make a differnce -- but be very careful with mutable elements.
-Python classes are:
- * Namespaces
+The copy module
+----------------
- * One for the class object
- * One for each instance
+most objects have a way to make copies (``dict.copy()`` for instance).
- * Attribute resolution order
- * Auto tacking-on of ``self`` when methods are called
+but if not, you can use the ``copy`` module to make a copy:
+.. code-block:: ipython
-That's about it -- really!
+ In [39]: import copy
+ In [40]: list3 = copy.copy(list2)
-Type-Based dispatch
--------------------
+ In [41]: list3
+ Out[41]: [[1, 2, 3], ['a', 'b', 'c']]
-You'll see code that looks like this:
+This is also a shallow copy.
-.. code-block:: python
+.. nextslide::
- if isinstance(other, A_Class):
- Do_something_with_other
- else:
- Do_something_else
+But there is another option:
+.. code-block:: ipython
+
+ In [3]: list1
+ Out[3]: [[1, 2, 3], ['a', 'b', 'c']]
+
+ In [4]: list2 = copy.deepcopy(list1)
+
+ In [5]: list1[0].append(4)
-Usually better to use "duck typing" (polymorphism)
+ In [6]: list1
+ Out[6]: [[1, 2, 3, 4], ['a', 'b', 'c']]
-But when it's called for:
+ In [7]: list2
+ Out[7]: [[1, 2, 3], ['a', 'b', 'c']]
- * ``isinstance()``
- * ``issubclass()``
+``deepcopy`` recurses through the object, making copies of everything as it goes.
.. nextslide::
-GvR: "Five Minute Multi- methods in Python":
-http://www.artima.com/weblogs/viewpost.jsp?thread=101605
+I happened on this thread on stack overflow:
+
+http://stackoverflow.com/questions/3975376/understanding-dict-copy-shallow-or-deep
+
+The OP is pretty confused -- can you sort it out?
+
+Make sure you understand the difference between a reference, a shallow copy, and a deep copy.
+
+Mutables as default arguments:
+------------------------------
-http://www.python.org/getit/releases/2.3/mro/
+Another "gotcha" is using mutables as default arguments:
-http://python-history.blogspot.com/2010/06/method-resolution-order.html
+.. code-block:: ipython
+ In [11]: def fun(x, a=[]):
+ ....: a.append(x)
+ ....: print(a)
+ ....:
-Wrap Up
--------
+This makes sense: maybe you'd pass in a specific list, but if not, the default is an empty list.
-Thinking OO in Python:
+But:
-Think about what makes sense for your code:
+.. code-block:: ipython
-* Code re-use
-* Clean APIs
-* ...
+ In [12]: fun(3)
+ [3]
-Don't be a slave to what OO is *supposed* to look like.
+ In [13]: fun(4)
+ [3, 4]
-Let OO work for you, not *create* work for you
+Huh?!
.. nextslide::
-OO in Python:
+Remember that that default argument is defined when the function is created: there will be only one list, and every time the function is called, that same list is used.
-The Art of Subclassing: *Raymond Hettinger*
-http://pyvideo.org/video/879/the-art-of-subclassing
+The solution:
-"classes are for code re-use -- not creating taxonomies"
+The standard practice for such a mutable default argument:
-Stop Writing Classes: *Jack Diederich*
+.. code-block:: ipython
-http://pyvideo.org/video/880/stop-writing-classes
+ In [15]: def fun(x, a=None):
+ ....: if a is None:
+ ....: a = []
+ ....: a.append(x)
+ ....: print(a)
+ In [16]: fun(3)
+ [3]
+ In [17]: fun(4)
+ [4]
-"If your class has only two methods -- and one of them is ``__init__``
--- you don't need a class"
+You get a new list every time the function is called
+========
Homework
---------
+========
-Build an html rendering system:
+.. rst-class:: left
-:ref:`homework_html_renderer`
+ Finish up the Labs
-|
+ Write a complete set of unit tests for your mailroom program.
+
+ * You will likely find that it is really hard to test without refactoring.
+
+ * This is Good!
+
+ * If code is hard to test -- it probably should be refactored.
+
+
+
+Material to review for next week
+--------------------------------
+
+Next week, we'll get started on Object Oriented Methods. It's a good idea to read up on it first -- so we can dive right in:
+
+ * Dive into Python3: 7.2 -- 7.3
+ http://www.diveintopython3.net/iterators.html#defining-classes
+
+ * Think Python: 15 -- 18
+ http://www.greenteapress.com/thinkpython/html/thinkpython016.html
+
+ * LPTHW: 40 -- 44
+ http://learnpythonthehardway.org/book/ex40.html
+
+[note that in py3 you don't need to inherit from object]
-You will build an html generator, using:
+Talk by Raymond Hettinger:
-* A Base Class with a couple methods
-* Subclasses overriding class attributes
-* Subclasses overriding a method
-* Subclasses overriding the ``__init__``
+Video of talk: https://youtu.be/HTLu2DFOdTg
-These are the core OO approaches
+Slides: https://speakerdeck.com/pyconslides/pythons-class-development-toolkit-by-raymond-hettinger
diff --git a/slides_sources/source/session07.rst b/slides_sources/source/session07.rst
index 68a4b19f..46bbd8e4 100644
--- a/slides_sources/source/session07.rst
+++ b/slides_sources/source/session07.rst
@@ -1,976 +1,919 @@
+.. include:: include.rst
-.. Foundations 2: Python slides file, created by
- hieroglyph-quickstart on Wed Apr 2 18:42:06 2014.
+***************************
+Object Oriented Programming
+***************************
-*******************************
-Session Seven: Testing, More OO
-*******************************
+Lightning Talks today
+---------------------
-.. rst-class:: large centered
-
-| Testing,
-| Multiple Inheritance,
-| Properties,
-| Class and Static Methods,
-| Special (Magic) Methods
+.. rst-class:: medium
+ |
+ | Charles E Robison
+ |
+ | Paul Vosper
+ |
+================
Review/Questions
================
Review of Previous Class
------------------------
-* Unicode
+.. rst-class:: medium
-* Object Oriented Programming
+ Advanced Argument passing
+ Testing
-Homework review
----------------
+Any questions?
-Homework Questions?
+Should I go over my solution(s)?
-How is progress going on the HTML Renderer?
+Notes from homework:
+--------------------
-Testing
-=======
+**chaining or...**
-.. rst-class:: build left
-.. container::
+Consider this:
- You've already seen some a very basic testing strategy.
+``elif selection == '3' or 'exit':``
- You've written some tests using that strategy.
+Careful here: you want to check if selection is '3' or 'exit', but that is no quite what this means:
- These tests were pretty basic, and a bit awkward in places (testing error
- conditions in particular).
+You want:
- .. rst-class:: centered
+``(selection == '3') or (selection == 'exit')``
- **It gets better**
+== has higher precedence than or, so you don't need the parentheses.
-Test Runners
-------------
+``selection == '3' or selection == 'exit'``
-So far our tests have been limited to code in an ``if __name__ == "__main__":``
-block.
+That feels like more typing, but that's what you have to do.
-.. rst-class:: build
+.. nextslide::
-* They are run only when the file is executed
-* They are always run when the file is executed
-* You can't do anything else when the file is executed without running tests.
+So what does the first version mean?
-.. rst-class:: build
-.. container::
+It would return true for '3', but would never fail. Due to operator precedence, it is:
- This is not optimal.
+``(selection == '3') or 'exit'``
- Python provides testing systems to help.
+so first it's checking if selection == '3', which will return True or False.
+Then it does the or: ``True or 'exit'`` or ``False or 'exit'``
-.. nextslide:: Standard Library: ``unittest``
+``or`` returns the first "truthy" value it finds, to it will return either True or 'exit', regardless of the value of selection. 'exit' is truthy, so this if clause will always run.
-The original testing system in Python.
+(let's try this out in iPython)
-You write subclasses of the ``unittest.TestCase`` class:
-.. code-block:: python
+===========================
+Object Oriented Programming
+===========================
- # in test.py
- import unittest
+.. rst-class:: medium centered
- class MyTests(unittest.TestCase):
- def test_tautology(self):
- self.assertEquals(1, 1)
+.. container::
-Then you run the tests by using the ``main`` function from the ``unittest``
-module:
+ Classes
-.. code-block:: python
+ Instances
- # in test.py
- if __name__ == '__main__':
- unittest.main()
+ Class and instance attributes
-.. nextslide:: Testing Your Code
+ Subclassing
-This way, you can write your code in one file and test it from another:
+ Overriding methods
-.. code-block:: python
- # in my_mod.py
- def my_func(val1, val2):
- return val1 * val2
- # in test_my_mod.py
- import unittest
- from my_mod import my_func
- class MyFuncTestCase(unittest.TestCase):
- def test_my_func(self):
- test_vals = (2, 3)
- expected = reduce(lambda x, y: x * y, test_vals)
- actual = my_func(*test_vals)
- self.assertEquals(expected, actual)
+===========================
+Object Oriented Programming
+===========================
- if __name__ == '__main__':
- unittest.main()
+A Core approach to organizing code.
-.. nextslide:: Advantages of ``unittest``
+I'm going to go through this fast.
-.. rst-class:: build
-.. container::
+So we can get to the actual coding.
- The ``unittest`` module is great.
- It comes with the standard Python distribution, no installation required.
+Object Oriented Programming
+---------------------------
- It provides a wide variety of assertions for testing all sorts of situations.
+More about Python implementation than OO design/strengths/weaknesses
- It allows for a setup and tear down workflow both before and after all tests
- and before and after each test.
+One reason for this:
- It's well known and well understood.
+Folks can't even agree on what OO "really" means
-.. nextslide:: Disadvantages:
+See: The Quarks of Object-Oriented Development
+
+ - Deborah J. Armstrong
+
+http://agp.hx0.ru/oop/quarks.pdf
-.. rst-class:: build
-.. container::
+.. nextslide::
- It's Object Oriented, and quite heavy.
+Is Python a "True" Object-Oriented Language?
- It uses the framework design pattern, so knowing how to use the features
- means learning what to override.
+(Doesn't support full encapsulation, doesn't *require*
+classes, etc...)
- Needing to override means you have to be cautious.
+.. nextslide::
- Test discovery is both inflexible and brittle.
+.. rst-class:: center large
-.. nextslide:: Other Options
+ I don't Care!
-There are several other options for running tests in Python.
+Good software design is about code re-use, clean separation of concerns,
+refactorability, testability, etc...
-* `Nose`_
-* `pytest`_
-* ... (many frameworks supply their own test runners)
+OO can help with all that, but:
+ * It doesn't guarantee it
+ * It can get in the way
-We are going to play today with pytest
+.. nextslide::
-.. _Nose: https://nose.readthedocs.org/
-.. _pytest: http://pytest.org/latest/
+Python is a Dynamic Language
+That clashes with "pure" OO
-.. nextslide:: Installing ``pytest``
+Think in terms of what makes sense for your project
-The first step is to install the package:
+-- not any one paradigm of software design.
-.. code-block:: bash
- $ workon cff2py
- (cff2py)$ pip install pytest
+.. nextslide::
-Once this is complete, you should have a ``py.test`` command you can run at the
-command line:
+So what is "object oriented programming"?
-.. code-block:: bash
+|
+ "Objects can be thought of as wrapping their data
+ within a set of functions designed to ensure that
+ the data are used appropriately, and to assist in
+ that use"
- (cff2py)$ py.test
+|
-If you have any tests in your repository, that will find and run them.
+http://en.wikipedia.org/wiki/Object-oriented_programming
-.. rst-class:: build
-.. container::
+.. nextslide::
+
+Even simpler:
- **Do you?**
-.. nextslide:: Pre-existing Tests
+"Objects are data and the functions that act on them in one place."
-I've added two files to the ``code/session07`` folder, along with a python
-source code file called ``circle.py``.
+This is the core of "encapsulation"
-The results you should have seen when you ran ``py.test`` above come partly
-from these files.
+In Python: just another namespace.
-Let's take a few minutes to look these files over.
+.. nextslide::
+
+The OO buzzwords:
-[demo]
+ * data abstraction
+ * encapsulation
+ * modularity
+ * polymorphism
+ * inheritance
-.. nextslide:: What's Happening Here.
+Python does all of this, though it doesn't enforce it.
+
+.. nextslide::
-When you run the ``py.test`` command, ``pytest`` starts in your current working
-directory and searches the filesystem for things that might be tests.
+You can do OO in C
-It follows some simple rules:
+(see the GTK+ project)
-.. rst-class:: build
-* Any python file that starts with ``test_`` or ``_test`` is imported.
-* Any functions in them that start with ``test_`` are run as tests.
-* Any classes that start with ``Test`` are treated similarly, with methods that
- begin with ``test_`` treated as tests.
+"OO languages" give you some handy tools to make it easier (and safer):
+
+ * polymorphism (duck typing gives you this anyway)
+ * inheritance
.. nextslide::
-This test running framework is simple, flexible and configurable.
+OO is the dominant model for the past couple decades
-`Read the documentation`_ for more information.
+You will need to use it:
-.. _Read the documentation: http://pytest.org/latest/getting-started.html#getstarted
+- It's a good idea for a lot of problems
-.. nextslide:: Test Driven Development
+- You'll need to work with OO packages
-What we've just done here is the first step in what is called **Test Driven
-Development**.
+(Even a fair bit of the standard library is Object Oriented)
-A bunch of tests exist, but the code to make them pass does not yet exist.
-The red we see in the terminal when we run our tests is a goad to us to write
-the code that fixes these tests.
+.. nextslide:: Some definitions
-Let's do that next!
+class
+ A category of objects: particular data and behavior: A "circle" (same as a type in python)
+instance
+ A particular object of a class: a specific circle
-More on Subclassing
-===================
+object
+ The general case of a instance -- really any value (in Python anyway)
-Watch This Video:
+attribute
+ Something that belongs to an object (or class): generally thought of
+ as a variable, or single object, as opposed to a ...
-http://pyvideo.org/video/879/the-art-of-subclassing
+method
+ A function that belongs to a class
+
+.. nextslide::
+
+.. rst-class:: center
+
+ Note that in python, functions are first class objects, so a method *is* an attribute
+
+
+==============
+Python Classes
+==============
.. rst-class:: left
-Seriously, well worth the time.
+ The ``class`` statement
-What's a Subclass For?
-----------------------
+ ``class`` creates a new type object:
-The most salient points from that video are as follows:
+ .. code-block:: ipython
-**Subclassing is not for Specialization**
+ In [4]: class C:
+ pass
+ ...:
+ In [5]: type(C)
+ Out[5]: type
-**Subclassing is for Reusing Code**
+ A class is a type -- interesting!
-**Bear in mind that the subclass is in charge**
+ It is created when the statement is run -- much like ``def``
+Python Classes
+--------------
-Multiple Inheritance
---------------------
+About the simplest class you can write
-Multiple inheritance: Inheriting from more than one class
+.. code-block:: python
-Simply provide more than one parent.
+ >>> class Point:
+ ... x = 1
+ ... y = 2
+ >>> Point
+
+ >>> Point.x
+ 1
+ >>> p = Point()
+ >>> p
+ <__main__.Point instance at 0x2de918>
+ >>> p.x
+ 1
+
+.. nextslide::
+
+Basic Structure of a real class:
.. code-block:: python
- class Combined(Super1, Super2, Super3):
- def __init__(self, something, something else):
- # some custom initialization here.
- Super1.__init__(self, ......)
- Super2.__init__(self, ......)
- Super3.__init__(self, ......)
- # possibly more custom initialization
+ class Point:
+ # everything defined in here is in the class namespace
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
-(calls to the super class ``__init__`` are optional -- case dependent)
+ ## create an instance of the class
+ p = Point(3,4)
-.. nextslide:: Method Resolution Order
+ ## access the attributes
+ print("p.x is:", p.x)
+ print("p.y is:", p.y)
+
+
+see: ``Examples/Session07/simple_classes.py``
+
+.. nextslide::
+
+The Initializer
+
+The ``__init__`` special method is called when a new instance of a class is created.
+
+You can use it to do any set-up you need
.. code-block:: python
- class Combined(Super1, Super2, Super3)
+ class Point(object):
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
-Attributes are located bottom-to-top, left-to-right
-* Is it an instance attribute ?
-* Is it a class attribute ?
-* Is it a superclass attribute ?
+It gets the arguments passed when you call the class object:
- * is the it an attribute of the left-most superclass?
- * is the it an attribute of the next superclass?
- * and so on up the hierarchy...
+.. code-block:: python
-* Is it a super-superclass attribute ?
-* ... also left to right ...
+ Point(x, y)
-http://python-history.blogspot.com/2010/06/method-resolution-order.html
+.. nextslide::
-.. nextslide:: Mix-ins
-Provides an subset of expected functionality in a re-usable package.
+What is this ``self`` thing?
-Why would you want to do this?
+The instance of the class is passed as the first parameter for every method.
-Hierarchies are not always simple:
+"``self``" is only a convention -- but you DO want to use it.
-* Animal
+.. code-block:: python
- * Mammal
+ class Point:
+ def a_function(self, x, y):
+ ...
- * GiveBirth()
-
- * Bird
-
- * LayEggs()
-
-Where do you put a Platypus?
-Real World Example: `FloatCanvas`_
+Does this look familiar from C-style procedural programming?
-.. _FloatCanvas: https://github.com/svn2github/wxPython/blob/master/3rdParty/FloatCanvas/floatcanvas/FloatCanvas.py#L485
-**Careful About This Pattern**
+.. nextslide::
+Anything assigned to a ``self`` attribute is kept in the instance
+name space
-.. nextslide:: New-Style Classes
+-- ``self`` *is* the instance.
-All the class definitions we've been showing inherit from ``object``.
+That's where all the instance-specific data is.
-This is referred to as a "new style" class.
+.. code-block:: python
-They were introduced in python2.2 to better merge types and classes, and clean
-up a few things.
+ class Point(object):
+ size = 4
+ color= "red"
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
-There are differences in method resolution order and properties.
+.. nextslide::
-**Always Make New-Style Classes.**
+Anything assigned in the class scope is a class attribute -- every
+instance of the class shares the same one.
-The differences are subtle, and may not appear until they jump up to bite you.
+Note: the methods defined by ``def`` are class attributes as well.
+The class is one namespace, the instance is another.
-.. nextslide:: ``super()``
+.. code-block:: python
-``super()``: use it to call a superclass method, rather than explicitly calling
-the unbound method on the superclass.
+ class Point:
+ size = 4
+ color= "red"
+ ...
+ def get_color():
+ return self.color
+ >>> p3.get_color()
+ 'red'
-instead of:
-.. code-block:: python
+class attributes are accessed with ``self`` also.
- class A(B):
- def __init__(self, *args, **kwargs)
- B.__init__(self, *argw, **kwargs)
- ...
-You can do:
+.. nextslide::
-.. code-block:: python
+Typical methods:
- class A(B):
- def __init__(self, *args, **kwargs)
- super(A, self).__init__(*argw, **kwargs)
- ...
+.. code-block:: python
-.. nextslide:: Caveats
+ class Circle:
+ color = "red"
-Caution: There are some subtle differences with multiple inheritance.
+ def __init__(self, diameter):
+ self.diameter = diameter
-You can use explicit calling to ensure that the 'right' method is called.
+ def grow(self, factor=2):
+ self.diameter = self.diameter * factor
-.. nextslide:: Background
+Methods take some parameters, manipulate the attributes in ``self``.
-Two seminal articles about ``super()``:
+They may or may not return something useful.
-"Super Considered Harmful" -- James Knight
+.. nextslide::
-https://fuhm.net/super-harmful/
+Gotcha!
-"super() considered super!" -- Raymond Hettinger
+.. code-block:: python
-http://rhettinger.wordpress.com/2011/05/26/super-considered-super/}
+ ...
+ def grow(self, factor=2):
+ self.diameter = self.diameter * factor
+ ...
+ In [205]: C = Circle(5)
+ In [206]: C.grow(2,3)
-(Both worth reading....)
+ TypeError: grow() takes at most 2 arguments (3 given)
+Huh???? I only gave 2
-Properties
-==========
+``self`` is implicitly passed in for you by python.
-.. rst-class:: left
-.. container::
+(demo of bound vs. unbound methods)
- One of the strengths of Python is lack of clutter.
+LAB
+----
+.. rst-class:: medium
- Attributes are simple and concise:
+ We now know enough to do something useful.
- .. code-block:: ipython
+Let's say you need to render some html...
- In [5]: class C(object):
- def __init__(self):
- self.x = 5
- In [6]: c = C()
- In [7]: c.x
- Out[7]: 5
- In [8]: c.x = 8
- In [9]: c.x
- Out[9]: 8
+The goal is to build a set of classes that render an html
+page.
+We'll start with a single class, then add some sub-classes
+to specialize the behavior
-Getter and Setters?
--------------------
+Details in:
-But what if you need to add behavior later?
+:ref:`exercise_html_renderer`
-.. rst-class:: build
+Let's get a start with step 1. in class.
-* do some calculation
-* check data validity
-* keep things in sync
+I'll give you a few minutes to think about it -- then we'll get started as a group.
-.. nextslide::
+Lightning Talks
+----------------
-.. code-block:: ipython
+.. rst-class:: medium
- In [5]: class C(object):
- ...: def __init__(self):
- ...: self.x = 5
- ...: def get_x(self):
- ...: return self.x
- ...: def set_x(self, x):
- ...: self.x = x
- ...:
- In [6]: c = C()
- In [7]: c.get_x()
- Out[7]: 5
- In [8]: c.set_x(8)
- In [9]: c.get_x()
- Out[9]: 8
+ |
+ | Charles E Robisons
+ |
+ | Paul Vosper
+ |
+=======================
+Subclassing/Inheritance
+=======================
- This is ugly and verbose -- `Java`_?
+Inheritance
+-----------
-.. _Java: http://dirtsimple.org/2004/12/python-is-not-java.html
+In object-oriented programming (OOP), inheritance is a way to reuse code
+of existing objects, or to establish a subtype from an existing object.
-.. nextslide:: properties
+Objects are defined by classes, classes can inherit attributes and behavior
+from pre-existing classes called base classes or super classes.
-When (and if) you need them:
+The resulting classes are known as derived classes or subclasses.
+
+(http://en.wikipedia.org/wiki/Inheritance_%28object-oriented_programming%29)
+
+Subclassing
+-----------
+
+A subclass "inherits" all the attributes (methods, etc) of the parent class.
+
+You can then change ("override") some or all of the attributes to change the behavior.
+
+You can also add new attributes to extend the behavior.
+
+The simplest subclass in Python:
.. code-block:: python
- class C(object):
- def __init__(self, x=5):
- self._x = x
- def _getx(self):
- return self._x
- def _setx(self, value):
- self._x = value
- def _delx(self):
- del self._x
- x = property(_getx, _setx, _delx, doc="docstring")
+ class A_subclass(The_superclass):
+ pass
+
+``A_subclass`` now has exactly the same behavior as ``The_superclass``
-Now the interface is still like simple attribute access!
+Overriding attributes
+---------------------
-.. rst-class:: centered small
+Overriding is as simple as creating a new attribute with the same name:
-[demo: :download:`properties_example.py <./supplements/properties_example.py>`]
+.. code-block:: python
+ class Circle:
+ color = "red"
-.. nextslide:: "Read Only" Attributes
+ ...
-Not all the arguments to ``property`` are required.
+ class NewCircle(Circle):
+ color = "blue"
+ >>> nc = NewCircle
+ >>> print(nc.color)
+ blue
-You can use this to create attributes that are "read only":
-.. code-block:: ipython
+all the ``self`` instances will have the new attribute.
- In [11]: class D(object):
- ....: def __init__(self, x=5):
- ....: self._x = 5
- ....: def getx(self):
- ....: return self._x
- ....: x = property(getx, doc="I am read only")
- ....:
- In [12]: d = D()
- In [13]: d.x
- Out[13]: 5
- In [14]: d.x = 6
- ---------------------------------------------------------------------------
- AttributeError Traceback (most recent call last)
- in ()
- ----> 1 d.x = 6
- AttributeError: can't set attribute
+Overriding methods
+------------------
+Same thing, but with methods (remember, a method *is* an attribute in python)
-.. nextslide:: Syntactic Sugar
+.. code-block:: python
-This *imperative* style of adding a ``property`` to you class is clear, but
-it's still a little verbose.
+ class Circle:
+ ...
+ def grow(self, factor=2):
+ """grows the circle's diameter by factor"""
+ self.diameter = self.diameter * factor
+ ...
-It also has the effect of leaving all those defined method objects laying
-around:
+ class NewCircle(Circle):
+ ...
+ def grow(self, factor=2):
+ """grows the area by factor..."""
+ self.diameter = self.diameter * math.sqrt(2)
-.. code-block:: ipython
- In [19]: d.x
- Out[19]: 5
- In [20]: d.getx
- Out[20]: >
- In [21]: d.getx()
- Out[21]: 5
+all the instances will have the new method
.. nextslide::
-Python provides us with a way to solve both these issues at once, using a
-syntactic feature called **decorators** (more about these next session):
-
-.. code-block:: ipython
-
- In [22]: class E(object):
- ....: def __init__(self, x=5):
- ....: self._x = x
- ....: @property
- ....: def x(self):
- ....: return self._x
- ....: @x.setter
- ....: def x(self, value):
- ....: self._x = value
- ....:
- In [23]: e = E()
- In [24]: e.x
- Out[24]: 5
- In [25]: e.x = 6
- In [26]: e.x
- Out[26]: 6
-
-
-Static and Class Methods
-========================
-
-.. rst-class:: left build
-.. container::
+Here's a program design suggestion:
- You've seen how methods of a class are *bound* to an instance when it is
- created.
+"""
- And you've seen how the argument ``self`` is then automatically passed to
- the method when it is called.
+Whenever you override a method, the interface of the new method should be the same as the old. It should take the same parameters, return the same type, and obey the same preconditions and postconditions.
- And you've seen how you can call *unbound* methods on a class object so
- long as you pass an instance of that class as the first argument.
+If you obey this rule, you will find that any function designed to work with an instance of a superclass, like a Deck, will also work with instances of subclasses like a Hand or PokerHand. If you violate this rule, your code will collapse like (sorry) a house of cards.
- .. rst-class:: centered
+"""
- **But what if you don't want or need an instance?**
+|
+| [ThinkPython 18.10]
+|
+| ( Demo of class vs. instance attributes )
-Static Methods
---------------
-
-A *static method* is a method that doesn't get self:
+===================
+More on Subclassing
+===================
-.. code-block:: ipython
+Overriding \_\_init\_\_
+-----------------------
- In [36]: class StaticAdder(object):
- ....: def add(a, b):
- ....: return a + b
- ....: add = staticmethod(add)
- ....:
+``__init__`` common method to override
- In [37]: StaticAdder.add(3, 6)
- Out[37]: 9
+You often need to call the super class ``__init__`` as well
-.. rst-class:: centered
+.. code-block:: python
-[demo: :download:`static_method.py <./supplements/static_method.py>`]
+ class Circle:
+ color = "red"
+ def __init__(self, diameter):
+ self.diameter = diameter
+ ...
+ class CircleR(Circle):
+ def __init__(self, radius):
+ diameter = radius*2
+ Circle.__init__(self, diameter)
-.. nextslide:: Syntactic Sugar
+exception to: "don't change the method signature" rule.
-Like ``properties``, static methods can be written *declaratively* using the
-``staticmethod`` built-in as a *decorator*:
+More subclassing
+----------------
+You can also call the superclass' other methods:
.. code-block:: python
- class StaticAdder(object):
- @staticmethod
- def add(a, b):
- return a + b
+ class Circle:
+ ...
+ def get_area(self, diameter):
+ return math.pi * (diameter/2.0)**2
-.. nextslide:: Why?
-.. rst-class:: build
-.. container::
+ class CircleR2(Circle):
+ ...
+ def get_area(self):
+ return Circle.get_area(self, self.radius*2)
- Where are static methods useful?
+There is nothing special about ``__init__`` except that it gets called
+automatically when you instantiate an instance.
- Usually they aren't
- 99% of the time, it's better just to write a module-level function
+When to Subclass
+----------------
- An example from the Standard Library (tarfile.py):
+"Is a" relationship: Subclass/inheritance
- .. code-block:: python
-
- class TarInfo(object):
- # ...
- @staticmethod
- def _create_payload(payload):
- """Return the string payload filled with zero bytes
- up to the next 512 byte border.
- """
- blocks, remainder = divmod(len(payload), BLOCKSIZE)
- if remainder > 0:
- payload += (BLOCKSIZE - remainder) * NUL
- return payload
+"Has a" relationship: Composition
+.. nextslide::
-Class Methods
--------------
+"**Is** a" vs "**Has** a"**
-A class method gets the class object, rather than an instance, as the first
-argument
+You may have a class that needs to accumulate an arbitrary number of objects.
-.. code-block:: ipython
+A list can do that -- so should you subclass list?
- In [41]: class Classy(object):
- ....: x = 2
- ....: def a_class_method(cls, y):
- ....: print "in a class method: ", cls
- ....: return y ** cls.x
- ....: a_class_method = classmethod(a_class_method)
- ....:
- In [42]: Classy.a_class_method(4)
- in a class method:
- Out[42]: 16
+Ask yourself:
-.. rst-class:: centered
+-- **Is** your class a list (with some extra functionality)?
-[demo: :download:`class_method.py <./supplements/class_method.py>`]
+or
-.. nextslide:: Syntactic Sugar
+-- Does you class **have** a list?
-Once again, the ``classmethod`` built-in can be used as a *decorator* for a
-more declarative style of programming:
+You only want to subclass list if your class could be used anywhere a list can be used.
-.. code-block:: python
- class Classy(object):
- x = 2
- @classmethod
- def a_class_method(cls, y):
- print "in a class method: ", cls
- return y ** cls.x
+Attribute resolution order
+--------------------------
-.. nextslide:: Why?
+When you access an attribute:
-.. rst-class:: build
-.. container::
+``an_instance.something``
- Unlike static methods, class methods are quite common.
+Python looks for it in this order:
- They have the advantage of being friendly to subclassing.
+ * Is it an instance attribute ?
+ * Is it a class attribute ?
+ * Is it a superclass attribute ?
+ * Is it a super-superclass attribute ?
+ * ...
- Consider this:
- .. code-block:: ipython
-
- In [44]: class SubClassy(Classy):
- ....: x = 3
- ....:
+It can get more complicated...
- In [45]: SubClassy.a_class_method(4)
- in a class method:
- Out[45]: 64
+https://www.python.org/download/releases/2.3/mro/
-.. nextslide:: Alternate Constructors
+http://python-history.blogspot.com/2010/06/method-resolution-order.html
-Because of this friendliness to subclassing, class methods are often used to
-build alternate constructors.
-Consider the case of wanting to build a dictionary with a given iterable of
-keys:
+What are Python classes, really?
+--------------------------------
-.. code-block:: ipython
+Putting aside the OO theory...
- In [57]: d = dict([1,2,3])
- ---------------------------------------------------------------------------
- TypeError Traceback (most recent call last)
- in ()
- ----> 1 d = dict([1,2,3])
+Python classes are:
- TypeError: cannot convert dictionary update sequence element #0 to a sequence
+ * Namespaces
+ * One for the class object
+ * One for each instance
-.. nextslide:: ``dict.fromkeys()``
+ * Attribute resolution order
+ * Auto tacking-on of ``self`` when methods are called
-The stock constructor for a dictionary won't work this way. So the dict object
-implements an alternate constructor that *can*.
-.. code-block:: python
+That's about it -- really!
- @classmethod
- def fromkeys(cls, iterable, value=None):
- '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
- If not specified, the value defaults to None.
- '''
- self = cls()
- for key in iterable:
- self[key] = value
- return self
+Type-Based dispatch
+-------------------
-(this is actually from the OrderedDict implementation in ``collections.py``)
+You'll see code that looks like this:
-See also datetime.datetime.now(), etc....
+.. code-block:: python
-.. nextslide:: Curious?
+ if isinstance(other, A_Class):
+ Do_something_with_other
+ else:
+ Do_something_else
-Properties, Static Methods and Class Methods are powerful features of Pythons
-OO model.
-They are implemented using an underlying structure called *descriptors*
+Usually better to use "duck typing" (polymorphism)
-`Here is a low level look`_ at how the descriptor protocol works.
+But when it's called for:
-The cool part is that this mechanism is available to you, the programmer, as
-well.
+ * ``isinstance()``
+ * ``issubclass()``
-.. _Here is a low level look: https://docs.python.org/2/howto/descriptor.html
+.. nextslide::
+
+GvR: "Five Minute Multi- methods in Python":
+http://www.artima.com/weblogs/viewpost.jsp?thread=101605
-Kicking the Tires
------------------
+https://www.python.org/download/releases/2.3/mro/
-Copy the file ``code/session07/circly.py`` to your student folder.
+http://python-history.blogspot.com/2010/06/method-resolution-order.html
-In it, write a simple "Circle" class:
-.. code-block:: ipython
+Wrap Up
+-------
- In [13]: c = Circle(3)
- In [15]: c.diameter
- Out[15]: 6.0
- In [16]: c.diameter = 8
- In [17]: c.radius
- Out[17]: 4.0
- In [18]: c.area
- Out[18]: 50.26548245743669
+Thinking OO in Python:
+Think about what makes sense for your code:
-Use ``properties`` so you can keep the radius and diameter in sync, and the
-area computed on the fly.
+* Code re-use
+* Clean APIs
+* ...
-Extra Credit: use a class method to make an alternate constructor that takes
-the diameter instead.
+Don't be a slave to what OO is *supposed* to look like.
+Let OO work for you, not *create* work for you
.. nextslide::
-Also copy the file ``test_circle1.py`` to your student folder.
+OO in Python:
-As you work, run the tests:
+The Art of Subclassing: *Raymond Hettinger*
-.. code-block:: bash
+http://pyvideo.org/video/879/the-art-of-subclassing
+
+"classes are for code re-use -- not creating taxonomies"
- (cff2py)$ py.test test_circle1.py
+Stop Writing Classes: *Jack Diederich*
-As each of the requirements from above are fulfilled, you'll see tests 'turn
-green'.
+http://pyvideo.org/video/880/stop-writing-classes
-When all your tests are passing, you've completed the job.
+"If your class has only two methods -- and one of them is ``__init__``
+-- you don't need a class"
-(This clear finish line is another of the advantages of TDD)
+===
+LAB
+===
-Special Methods
-===============
+.. rst-class:: left medium
+
+ * html renderer: let's see how much more we can do!
.. rst-class:: left
-.. container::
- Special methods (also called *magic* methods) are the secret sauce to Python's
- Duck typing.
+ :ref:`exercise_html_renderer`
- Defining the appropriate special methods in your classes is how you make your
- class act like standard classes.
+ Now we have a base class, and we can:
-What's in a Name?
------------------
+ * Subclass overriding class attributes
+ * Subclass overriding a method
+ * Subclass overriding the ``__init__``
-We've seen at least one special method so far::
+ These are the core OO approaches
- __init__
-It's all in the double underscores...
+===================
+More on Subclassing
+===================
-Pronounced "dunder" (or "under-under")
+.. rst-class:: left
-try: ``dir(2)`` or ``dir(list)``
+ This is a great talk (yes, I'm repeating):
-.. nextslide:: Protocols
+ The Art of Subclassing: *Raymond Hettinger*
-.. rst-class:: build
-.. container::
+ http://pyvideo.org/video/879/the-art-of-subclassing
- The set of special methods needed to emulate a particular type of Python object
- is called a *protocol*.
+ If you haven't watched it, It's well worth your time
- Your classes can "become" like Python built-in classes by implementing the
- methods in a given protocol.
+What's a Subclass For?
+----------------------
- Remember, these are more *guidelines* than laws. Implement what you need.
+The most salient points from that video are as follows:
+* **Subclassing is not for Specialization**
-.. nextslide:: The Numerics Protocol
+* **Subclassing is for Reusing Code**
-Do you want your class to behave like a number? Implement these methods:
+* **Bear in mind that the subclass is in charge**
-.. code-block:: python
- object.__add__(self, other)
- object.__sub__(self, other)
- object.__mul__(self, other)
- object.__floordiv__(self, other)
- object.__mod__(self, other)
- object.__divmod__(self, other)
- object.__pow__(self, other[, modulo])
- object.__lshift__(self, other)
- object.__rshift__(self, other)
- object.__and__(self, other)
- object.__xor__(self, other)
- object.__or__(self, other)
+Multiple Inheritance
+--------------------
-.. nextslide:: The Container Protocol
+Multiple inheritance: Inheriting from more than one class
-Want to make a container type? Here's what you need:
+Simply provide more than one parent.
.. code-block:: python
- object.__len__(self)
- object.__getitem__(self, key)
- object.__setitem__(self, key, value)
- object.__delitem__(self, key)
- object.__iter__(self)
- object.__reversed__(self)
- object.__contains__(self, item)
- object.__getslice__(self, i, j)
- object.__setslice__(self, i, j, sequence)
- object.__delslice__(self, i, j)
+ class Combined(Super1, Super2, Super3):
+ def __init__(self, something, something else):
+ # some custom initialization here.
+ Super1.__init__(self, ......)
+ Super2.__init__(self, ......)
+ Super3.__init__(self, ......)
+ # possibly more custom initialization
+
+(calls to the super class ``__init__`` are optional -- case dependent)
+.. nextslide:: Method Resolution Order
-.. nextslide:: An Example
+.. code-block:: python
-Each of these methods supports a common Python operation.
+ class Combined(Super1, Super2, Super3)
-For example, to make '+' work with a sequence type in a vector-like fashion, implement ``__add__``:
+Attributes are located bottom-to-top, left-to-right
-.. code-block:: python
+* Is it an instance attribute ?
+* Is it a class attribute ?
+* Is it a superclass attribute ?
- def __add__(self, v):
- """return the element-wise vector sum of self and v
- """
- assert len(self) == len(v)
- return vector([x1 + x2 for x1, x2 in zip(self, v)])
+ - Is it an attribute of the left-most superclass?
+ - Is it an attribute of the next superclass?
+ - and so on up the hierarchy...
-.. rst-class:: centered
+* Is it a super-superclass attribute ?
+* ... also left to right ...
-[a more complete example may be seen :download:`here <./supplements/vector.py>`]
+http://python-history.blogspot.com/2010/06/method-resolution-order.html
+.. nextslide:: Mix-ins
-.. nextslide:: Generally Useful Special Methods
+So why would you want to do this? One reason: *mixins*
-You only *need* to define the special methods that will be used by your class.
+Provides an subset of expected functionality in a re-usable package.
-However, even in the absence of wanting to duck-type, you should almost always
-define these:
+Huh? this is why --
-``object.__str__``:
- Called by the str() built-in function and by the print statement to compute
- the *informal* string representation of an object.
+Hierarchies are not always simple:
-``object.__unicode__``:
- Called by the unicode() built-in function. This converts an object to an
- *informal* unicode representation.
+* Animal
-``object.__repr__``:
- Called by the repr() built-in function and by string conversions (reverse
- quotes) to compute the *official* string representation of an object.
+ * Mammal
- (ideally: ``eval( repr(something) ) == something``)
+ * GiveBirth()
-.. nextslide:: Summary
+ * Bird
-Use special methods when you want your class to act like a "standard" class in
-some way.
+ * LayEggs()
-Look up the special methods you need and define them.
+Where do you put a Platypus?
-There's more to read about the details of implementing these methods:
+Real World Example: `FloatCanvas`_
-* https://docs.python.org/2/reference/datamodel.html#special-method-names
-* http://www.rafekettler.com/magicmethods.html
+.. _FloatCanvas: https://github.com/wxWidgets/wxPython/blob/master/wx/lib/floatcanvas/FloatCanvas.py#L485
-Be a bit cautious about the code examples in that last one. It uses quite a bit
-of old-style class definitions, which should not be emulated.
+``super()``
+-----------
-Kicking the Tires
------------------
+``super()``: use it to call a superclass method, rather than explicitly calling
+the unbound method on the superclass.
-Extend your "Circle" class:
+instead of:
-* Add ``__str__`` and ``__repr__`` methods
-* Write an ``__add__`` method so you can add two circles
-* Make it so you can multiply a circle by a number....
+.. code-block:: python
-.. code-block:: ipython
+ class A(B):
+ def __init__(self, *args, **kwargs)
+ B.__init__(self, *argw, **kwargs)
+ ...
- In [22]: c1 = Circle(3)
- In [23]: c2 = Circle(4)
- In [24]: c3 = c1+c2
- In [25]: c3.radius
- Out[25]: 7
- In [26]: c1*3
- Out[26]: Circle(9)
+You can do:
-If you have time: compare them... (``c1 > c2`` , etc)
+.. code-block:: python
+ class A(B):
+ def __init__(self, *args, **kwargs)
+ super().__init__(*argw, **kwargs)
+ ...
-.. nextslide::
+.. nextslide:: Caveats
-As you work, run the tests in ``test_circle2.py``:
+Caution: There are some subtle differences with multiple inheritance.
-.. code-block:: bash
+You can use explicit calling to ensure that the 'right' method is called.
- (cff2py)$ py.test test_circle2.py
+.. rst-class:: medium
-As each of the requirements from above are fulfilled, you'll see tests 'turn
-green'.
+ **Background**
-When all your tests are passing, you've completed the job.
+Two seminal articles about ``super()``:
+"Super Considered Harmful" -- James Knight
-Homework
-========
+https://fuhm.net/super-harmful/
-.. rst-class:: centered large
+"super() considered super!" -- Raymond Hettinger
+
+http://rhettinger.wordpress.com/2011/05/26/super-considered-super/
-Testing, Testing, 1 2 3
+(Both worth reading....)
+========
+Homework
+========
-Assignment
-----------
+Complete your html renderer.
-If you are not yet done, complete the ``Circle`` class so that all tests in
-``test_circle2.py`` pass.
+Watch these videos:
-Go back over some of your assignments from the last weeks.
+Python class toolkit: *Raymond Hettinger* -- https://youtu.be/HTLu2DFOdTg
-Convert tests that are currently in the ``if __name__ == '__main__':`` blocks
-into standalone pytest files.
+https://speakerdeck.com/pyconslides/pythons-class-development-toolkit-by-raymond-hettinger
-Name each test file so that it is clear with which source file it belongs::
+The Art of Subclassing: *Raymond Hettinger* -- http://pyvideo.org/video/879/the-art-of-subclassing
- test_rot13.py -> rot13.py
+Stop Writing Classes: *Jack Diederich* -- http://pyvideo.org/video/880/stop-writing-classes
-Add unit tests for the HTML Renderer that you are currently constructing.
+Read up on super()
-Create at least 4 test files with tests that well exercise the features built
-in each source file.
diff --git a/slides_sources/source/session08.rst b/slides_sources/source/session08.rst
index c3152d53..609a26e1 100644
--- a/slides_sources/source/session08.rst
+++ b/slides_sources/source/session08.rst
@@ -1,1047 +1,934 @@
-**********************************************************************
-Session Eight: Generators, Iterators, Decorators, and Context Managers
-**********************************************************************
+.. include:: include.rst
-.. rst-class:: large centered
-
-The tools of Pythonicity
+****************************************************
+Session Eight: More OO: Properties, Special methods.
+****************************************************
+================
Review/Questions
================
Review of Previous Class
------------------------
-* Advanced OO Concepts
+* Basic OO Concepts
- * Properties
- * Special Methods
+ * Classes
+ * class vs. instance attributes
+ * subclassing
+ * overriding methods / attributes
-* Testing with pytest
+Lightning Talks Today:
+-----------------------
-Homework review
----------------
-
-* Circle Class
-* Writing Tests using the ``pytest`` module
-
+.. rst-class:: medium
-Decorators
-==========
+ Paul Briant
-**A Short Digression**
+ Jay Raina
-.. rst-class:: left build
-.. container::
+ Josh Hicks
- Functions are things that generate values based on input (arguments).
- In Python, functions are first-class objects.
+Personal Project
+-----------------
- This means that you can bind symbols to them, pass them around, just like
- other objects.
+The bulk of the homework for the rest of the class will be a personal project:
- Because of this fact, you can write functions that take functions as
- arguments and/or return functions as values:
+* It can be for fun, or something you need for your job.
+* It should be large enough to take a few weeks homework time to do.
+* **It should demostrate that you can do something useful with python.**
+* It should follow PEP8 (https://www.python.org/dev/peps/pep-0008)
+* It should have unit tests!
+* Ideally, it will be in version control (gitHub)
+* I don't require any specific python features (i.e. classes): use
+ what is appropriate for your project
- .. code-block:: python
+* Due the Sunday after the last class (December 11)
- def substitute(a_function):
- def new_function(*args, **kwargs):
- return "I'm not that other function"
- return new_function
+|
+| By next week, send me a project proposal: short and sweet.
+|
-A Definition
-------------
+Homework review
+---------------
-There are many things you can do with a simple pattern like this one. So many,
-that we give it a special name:
+* html renderer
+* Test-driven development
-.. rst-class:: centered
+Homework Notes:
+---------------
-**Decorator**
+``**kwargs`` will always define a ``kwargs`` dict: it just may be empty.
-.. rst-class:: build
-.. container::
+And there is no need to check if it's empty before trying to loop through it.
- A decorator is a function that takes a function as an argument and
- returns a function as a return value.
+.. code-block:: python
- That's nice and all, but why is that useful?
+ if self.attributes != {}:
+ for key, value in self.attributes.items():
+ self.atts += ' {}="{}"'.format(key, value)
-An Example
-----------
+no need for ``!= {}`` -- an empty dict is "Falsey"
-Imagine you are trying to debug a module with a number of functions like this
-one:
+**but** no need for that check at all. If the dict (or list, or tuple) is
+empty, then the loop is a do-nothing operation:
.. code-block:: python
- def add(a, b):
- return a + b
+ for key, value in self.attributes.items():
+ self.atts += ' {}="{}"'.format(key, value)
-.. rst-class:: build
-.. container::
+will not run if self.attributes is an empty dict.
- You want to see when each function is called, with what arguments and with what
- result. So you rewrite each function as follows:
- .. code-block:: python
+Dynamic typing and class attributes
+-----------------------------------
- def add(a, b):
- print "Function 'add' called with args: %r" % locals()
- result = a + b
- print "\tResult --> %r" % result
- return result
+* what happens if we change a class attribute after creating instances??
-.. nextslide::
+ - let's try ``Element.indent`` ...
-That's not particularly nice, especially if you have lots of functions in your
-module.
+* setting an instance attribute overwrites class attributes:
-Now imagine we defined the following, more generic *decorator*:
+``self.tag =`` overrights the class attribute (sort of!)
-.. code-block:: python
+Let's experiment with that.
- def logged_func(func):
- def logged(*args, **kwargs):
- print "Function %r called" % func.__name__
- if args:
- print "\twith args: %r" % args
- if kwargs:
- print "\twith kwargs: %r" % kwargs
- result = func(*args, **kwargs)
- print "\t Result --> %r" % result
- return result
- return logged
-.. nextslide::
+dict as switch
+--------------
-We could then make logging versions of our module functions:
+.. rst-class:: medium
-.. code-block:: python
+ What to use instead of "switch-case"?
- logging_add = logged_func(add)
+A number of languages have a "switch-case" construct::
-Then, where we want to see the results, we can use the logged version:
+ switch(argument) {
+ case 0:
+ return "zero";
+ case 1:
+ return "one";
+ case 2:
+ return "two";
+ default:
+ return "nothing";
+ };
-.. code-block:: ipython
+How do you spell this in python?
- In [37]: logging_add(3, 4)
- Function 'add' called
- with args: (3, 4)
- Result --> 7
- Out[37]: 7
+``if-elif`` chains
+-------------------
-.. rst-class:: build
-.. container::
+The obvious way to spell it is a chain of ``elif`` statements:
- This is nice, but we have to call the new function wherever we originally
- had the old one.
+.. code-block:: python
- It'd be nicer if we could just call the old function and have it log.
+ if argument == 0:
+ return "zero"
+ elif argument == 1:
+ return "one"
+ elif argument == 2:
+ return "two"
+ else:
+ return "nothing"
+
+And there is nothing wrong with that, but....
.. nextslide::
-Remembering that you can easily rebind symbols in Python using *assignment
-statements* leads you to this form:
+The ``elif`` chain is neither elegant nor efficient.
+
+There are a number of ways to spell it in python -- one elegant one is to use a dict:
.. code-block:: python
- def logged_func(func):
- # implemented above
+ arg_dict = {0:"zero", 1:"one", 2: "two"}
+ dict.get(argument, "nothing")
- def add(a, b):
- return a + b
- add = logged_func(add)
+Simple, elegant, and fast.
-.. rst-class:: build
-.. container::
+You can do a dispatch table by putting functions as the value.
- And now you can simply use the code you've already written and calls to
- ``add`` will be logged:
+Example: Chris' mailroom2 solution.
- .. code-block:: ipython
+Polymorphism as switch:
+-----------------------
- In [41]: add(3, 4)
- Function 'add' called
- with args: (3, 4)
- Result --> 7
- Out[41]: 7
+It turns out that a lot of uses of switch-case in non-OO languages is to
+change behaviour depending on teh type of object being worked on::
-Syntax
-------
+ switch(object.tag) {
+ case 'html':
+ render_html_element;
+ case 'p':
+ render_p_element;
+ ...
-Rebinding the name of a function to the result of calling a decorator on that
-function is called **decoration**.
+I saw some of this in the html renderer:
-Because this is so common, Python provides a special operator to perform it
-more *declaratively*: the ``@`` operator:
+.. nextslide::
.. code-block:: python
- # this is the imperative version:
- def add(a, b):
- return a + b
- add = logged_func(add)
+ def render(out_file, ind=""):
+ ....
+ if self.tag == 'html':
+ tag = ""
+ end_tag = ""
+ elif self.tag == 'p':
+ tag = "
"
+ end_tag = "
"
- # and this declarative form is exactly equal:
- @logged_func
- def add(a, b):
- return a + b
+This will work, of course, but:
-.. rst-class:: build
-.. container::
-
- The declarative form (called a decorator expression) is far more common,
- but both have the identical result, and can be used interchangeably.
-
-Callables
----------
+* it means you need to know every tag that you might render when you write this render method.
-Our original definition of a *decorator* was nice and simple, but a tiny bit
-incomplete.
+* In a more complex system, you will need to go update all sorts of things all over teh place when you add a tag.
-In reality, decorators can be used with anything that is *callable*.
+* It means anyone extending the system with more tags needs to edit the core base class.
-In python a *callable* is a function, a method on a class, or even a class that
-implements the ``__call__`` special method.
-
-So in fact the definition should be updated as follows:
+Polymorphism
+------------
-.. rst-class:: centered
+The alternative is to use polymorphism:
-A decorator is a callable that takes a callable as an argument and
-returns a callable as a return value.
+Your ``render()`` method doesn't need to know what all the objects are
+that it may need to render.
-An Example
-----------
+All it needs to know is that they all will have a method
+that does the right thing.
-Consider a decorator that would save the results of calling an expensive
-function with given arguments:
+So the above becomes, simply:
.. code-block:: python
- class Memoize:
- """
- memoize decorator from avinash.vora
- http://avinashv.net/2008/04/python-decorators-syntactic-sugar/
- """
- def __init__(self, function): # runs when memoize class is called
- self.function = function
- self.memoized = {}
-
- def __call__(self, *args): # runs when memoize instance is called
- try:
- return self.memoized[args]
- except KeyError:
- self.memoized[args] = self.function(*args)
- return self.memoized[args]
+ def render(out_file, ind=""):
+ ....
+ tag, end_tag = self.make_tags()
+
+This is known as polymorphism, because many different objects are behave
+the same way.
.. nextslide::
-Let's try that out with a potentially expensive function:
+This is usally handled by subclassing, so they all get all teh same
+methods by default, and you only need to specialize the ones that need it.
-.. code-block:: ipython
+But in Python -- it can be done with duck-typing instead, as the TextWrapper example.
- In [56]: @Memoize
- ....: def sum2x(n):
- ....: return sum(2 * i for i in xrange(n))
- ....:
+Duck typing and EAFP
+--------------------
- In [57]: sum2x(10000000)
- Out[57]: 99999990000000
+* notes on Duck Typing: :ref:`exercise_html_renderer`
- In [58]: sum2x(10000000)
- Out[58]: 99999990000000
+* put the ``except`` as close as you can to where you expect an exception to be raised!
-It's nice to see that in action, but what if we want to know *exactly* how much
-difference it made?
+* Let's look at a couple ways to do that.
-Nested Decorators
------------------
+Code Review
+-----------
-You can stack decorator expressions. The result is like calling each decorator
-in order, from bottom to top:
+* anyone stuck that wants to work through your code?
-.. code-block:: python
+* And/or go through mine...
- @decorator_two
- @decorator_one
- def func(x):
- pass
+Lightning Talks:
+----------------
- # is exactly equal to:
- def func(x):
- pass
- func = decorator_two(decorator_one(func))
+.. rst-class:: medium
-.. nextslide::
+ |
+ | Paul Briant
+ |
+ | Jay Raina
+ |
+ | Josh Hicks
-Let's define another decorator that will time how long a given call takes:
-.. code-block:: python
- 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
- return result
- return timed
+==========
+Properties
+==========
-.. nextslide::
+.. rst-class:: left
+.. container::
-And now we can use this new decorator stacked along with our memoizing
-decorator:
+ One of the strengths of Python is lack of clutter.
-.. code-block:: ipython
+ Attributes are simple and concise:
- In [71]: @timed_func
- ....: @Memoize
- ....: def sum2x(n):
- ....: return sum(2 * i for i in xrange(n))
- In [72]: sum2x(10000000)
- time expired: 0.997071027756
- Out[72]: 99999990000000
- In [73]: sum2x(10000000)
- time expired: 4.05311584473e-06
- Out[73]: 99999990000000
+ .. code-block:: ipython
-Examples from the Standard Library
-----------------------------------
+ In [5]: class C:
+ def __init__(self):
+ self.x = 5
+ In [6]: c = C()
+ In [7]: c.x
+ Out[7]: 5
+ In [8]: c.x = 8
+ In [9]: c.x
+ Out[9]: 8
-It's going to be a lot more common for you to use pre-defined decorators than
-for you to be writing your own.
-Let's see a few that might help you with work you've been doing recently.
+Getter and Setters?
+-------------------
-For example, a ``staticmethod()`` can be implemented with a decorator
-expression:
+But what if you need to add behavior later?
-.. code-block:: python
+.. rst-class:: build
- # the way we saw last week:
- class C(object):
- def add(a, b):
- return a + b
- add = staticmethod(add)
+* do some calculation
+* check data validity
+* keep things in sync
- # and the decorator form
- class C(object):
- @staticmethod
- def add(a, b):
- return a + b
.. nextslide::
-The ``classmethod()`` builtin can do the same thing:
-
-.. code-block:: python
-
- # in imperative style:
- class C(object):
- def from_iterable(cls, seq):
- # method body
- from_iterable = classmethod(from_iterable)
-
- # and in declarative style
- class C(object):
- @classmethod
- def from_iterable(cls, seq):
- # method body
-
-.. nextslide::
+.. code-block:: ipython
-Perhaps most commonly, you'll see the ``property()`` builtin used this way.
+ In [5]: class C:
+ ...: def __init__(self):
+ ...: self.x = 5
+ ...: def get_x(self):
+ ...: return self.x
+ ...: def set_x(self, x):
+ ...: self.x = x
+ ...:
+ In [6]: c = C()
+ In [7]: c.get_x()
+ Out[7]: 5
+ In [8]: c.set_x(8)
+ In [9]: c.get_x()
+ Out[9]: 8
-Last week we saw this code:
-.. code-block:: python
+ This is ugly and verbose -- `Java`_?
- class C(object):
- def __init__(self):
- self._x = None
- def getx(self):
- return self._x
- def setx(self, value):
- self._x = value
- def delx(self):
- del self._x
- x = property(getx, setx, delx,
- "I'm the 'x' property.")
+.. _Java: http://dirtsimple.org/2004/12/python-is-not-java.html
-.. nextslide::
-Used in a decorator statement, it looks like this:
+properties
+-----------
-.. code-block:: python
+.. code-block:: ipython
- class C(object):
- def __init__(self):
- self._x = None
+ class C:
+ _x = None
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
- @x.deleter
- def x(self):
- del self._x
-Note that in this case, the decorator object returned by the property decorator
-itself implements additional decorators as attributes on the returned method
-object.
+ In [28]: c = C()
+ In [30]: c.x = 5
+ In [31]: print(c.x)
+ 5
-Iterators and Generators
-=========================
+Now the interface is like simple attribute access!
-Iterators
----------
-Iterators are one of the main reasons Python code is so readable:
+.. nextslide::
-.. code-block:: python
-
- for x in just_about_anything:
- do_stuff(x)
+What's up with the "@" symbols?
-It does not have to be a "sequence": list, tuple, etc.
+Those are "decorations" it's a syntax for wrapping functions up with something special.
-Rather: you can loop through anything that satisfies the "iterator protocol"
+We'll cover that in detail in a couple weeks, but for now -- just copy the syntax.
-http://docs.python.org/library/stdtypes.html#iterator-types
+.. code-block:: python
-The Iterator Protocol
-----------------------
+ @property
+ def x(self):
-An iterator must have the following methods:
+means: make a property called x with this as the "getter".
.. code-block:: python
-
- an_iterator.__iter__()
-Returns the iterator object itself. This is required to allow both containers
-and iterators to be used with the ``for`` and ``in`` statements.
+ @x.setter
+ def x(self, value):
-.. code-block:: python
-
- an_iterator.next()
+means: make the "setter" of the 'x' property this new function
-Returns the next item from the container. If there are no further items,
-raises the ``StopIteration`` exception.
+"Read Only" Attributes
+----------------------
-List as an Iterator:
---------------------
+You do not need to define a setter. If you don't, you get a "read only" attribute:
.. code-block:: ipython
- In [10]: a_list = [1,2,3]
+ In [11]: class D():
+ ....: def __init__(self, x=5):
+ ....: self._x = 5
+ ....: @property
+ ....: def getx(self):
+ ....: """I am read only"""
+ ....: return self._x
+ ....:
+ In [12]: d = D()
+ In [13]: d.x
+ Out[13]: 5
+ In [14]: d.x = 6
+ ---------------------------------------------------------------------------
+ AttributeError Traceback (most recent call last)
+ in ()
+ ----> 1 d.x = 6
+ AttributeError: can't set attribute
- In [11]: list_iter = a_list.__iter__()
+Deleters
+---------
- In [12]: list_iter.next()
- Out[12]: 1
+If you want to do something special when a property is deleted, you can define
+a deleter is well:
- In [13]: list_iter.next()
- Out[13]: 2
+.. code-block:: ipython
- In [14]: list_iter.next()
- Out[14]: 3
+ In [11]: class D():
+ ....: def __init__(self, x=5):
+ ....: self._x = 5
+ ....: @property
+ ....: def x(self):
+ ....: return self._x
+ ....: @x.deleter
+ ....: def x(self):
+ ....: del self._x
- In [15]: list_iter.next()
- --------------------------------------------------
- StopIteration Traceback (most recent call last)
- in ()
- ----> 1 list_iter.next()
- StopIteration:
+If you leave this out, the property can't be deleted, which is usually
+what you want.
-Making an Iterator
--------------------
+.. rst-class:: centered
-A simple version of ``xrange()``
+[demo: :download:`properties_example.py <../../Examples/Session08/properties_example.py>`]
-.. code-block:: python
-
- class IterateMe_1(object):
- def __init__(self, stop=5):
- self.current = 0
- self.stop = stop
- def __iter__(self):
- return self
- def next(self):
- if self.current < self.stop:
- self.current += 1
- return self.current
- else:
- raise StopIteration
-
-(demo: ``code/iterator_1.py``)
-
-``iter()``
------------
-How doyou get the iterator object (the thing with the next() method) from an "iterable"?
+===
+LAB
+===
-The ``iter()`` function:
+Let's use some of this to build a nice class to represent a Circle.
-.. code-block:: ipython
+For now, Let's do steps 1-4 of:
- In [20]: iter([2,3,4])
- Out[20]:
+:ref:`exercise_circle_class`
- In [21]: iter("a string")
- Out[21]:
- In [22]: iter( ('a', 'tuple') )
- Out[22]:
+========================
+Static and Class Methods
+========================
-for an arbitrary object, ``iter()`` calls the ``__iter__`` method. But it knows about some object (``str``, for instance) that don't have a ``__iter__`` method.
+.. rst-class:: left build
+.. container::
+ You've seen how methods of a class are *bound* to an instance when it is
+ created.
-What does ``for`` do?
-----------------------
+ And you've seen how the argument ``self`` is then automatically passed to
+ the method when it is called.
-Now that we know the iterator protocol, we can write something like a for loop:
+ And you've seen how you can call *unbound* methods on a class object so
+ long as you pass an instance of that class as the first argument.
-(``code/session08/my_for.py``)
-.. code-block:: python
+ .. rst-class:: centered
- def my_for(an_iterable, func):
- """
- Emulation of a for loop.
+ **But what if you don't want or need an instance?**
- func() will be called with each item in an_iterable
- """
- # equiv of "for i in l:"
- iterator = iter(an_iterable)
- while True:
- try:
- i = iterator.next()
- except StopIteration:
- break
- func(i)
+Static Methods
+--------------
-Itertools
----------
+A *static method* is a method that doesn't get self:
-``itertools`` is a collection of utilities that make it easy to
-build an iterator that iterates over sequences in various common ways
+.. code-block:: ipython
-http://docs.python.org/library/itertools.html
+ In [36]: class StaticAdder:
-NOTE:
+ ....: @staticmethod
+ ....: def add(a, b):
+ ....: return a + b
+ ....:
-iterators are not *only* for ``for``
+ In [37]: StaticAdder.add(3, 6)
+ Out[37]: 9
-They can be used with anything that expexts an iterator:
+.. rst-class:: centered
-``sum``, ``tuple``, ``sorted``, and ``list``
+[demo: :download:`static_method.py <../../Examples/Session08/static_method.py>`]
-For example.
-LAB / Homework
---------------
+.. nextslide:: Why?
-In the ``code/session08`` dir, you will find: ``iterator_1.py``
+.. rst-class:: build
+.. container::
-* Extend (``iterator_1.py`` ) to be more like ``xrange()`` -- add three input parameters: ``iterator_2(start, stop, step=1)``
-
-* See what happens if you break out in the middle of the loop:
+ Where are static methods useful?
-.. code-block:: python
+ Usually they aren't
- it = IterateMe_2(2, 20, 2)
- for i in it:
- if i > 10: break
- print i
+ 99% of the time, it's better just to write a module-level function
-And then pick up again:
+ An example from the Standard Library (tarfile.py):
-.. code-block:: python
-
- for i in it:
- print i
+ .. code-block:: python
-* Does ``xrange()`` behave the same?
-
- - make yours match ``xrange()``
+ class TarInfo:
+ # ...
+ @staticmethod
+ def _create_payload(payload):
+ """Return the string payload filled with zero bytes
+ up to the next 512 byte border.
+ """
+ blocks, remainder = divmod(len(payload), BLOCKSIZE)
+ if remainder > 0:
+ payload += (BLOCKSIZE - remainder) * NUL
+ return payload
-Generators
-----------
-Generators give you the iterator immediately:
+Class Methods
+-------------
-* no access to the underlying data ... if it even exists
+A class method gets the class object, rather than an instance, as the first
+argument
+.. code-block:: ipython
-Conceptually:
- Iterators are about various ways to loop over data, generators generate the data on the fly
+ In [41]: class Classy:
+ ....: x = 2
+ ....: @classmethod
+ ....: def a_class_method(cls, y):
+ ....: print("in a class method: ", cls)
+ ....: return y ** cls.x
+ ....:
+ In [42]: Classy.a_class_method(4)
+ in a class method:
+ Out[42]: 16
-Practically:
- You can use either either way (and a generator is one type of iterator
+.. rst-class:: centered
- Generators do some of the book-keeping for you.
+[demo: :download:`class_method.py <../../Examples/Session08/class_method.py>`]
-yield
------
-``yield`` is a way to make a quickie generator with a function:
+Why?
+----
-.. code-block:: python
+.. rst-class:: build
+.. container::
- def a_generator_function(params):
- some_stuff
- yield something
+ Unlike static methods, class methods are quite common.
-Generator functions "yield" a value, rather than returning a value.
+ They have the advantage of being friendly to subclassing.
-State is preserved in between yields.
+ Consider this:
+ .. code-block:: ipython
-.. nextslide::
+ In [44]: class SubClassy(Classy):
+ ....: x = 3
+ ....:
-A function with ``yield`` in it is a "factory" for a generator
+ In [45]: SubClassy.a_class_method(4)
+ in a class method:
+ Out[45]: 64
-Each time you call it, you get a new generator:
+Alternate Constructors
+-----------------------
-.. code-block:: python
+Because of this friendliness to subclassing, class methods are often used to
+build alternate constructors.
- gen_a = a_generator()
- gen_b = a_generator()
+Consider the case of wanting to build a dictionary with a given iterable of
+keys:
-Each instance keeps its own state.
+.. code-block:: ipython
+
+ In [57]: d = dict([1,2,3])
+ ---------------------------------------------------------------------------
+ TypeError Traceback (most recent call last)
+ in ()
+ ----> 1 d = dict([1,2,3])
-Really just a shorthand for an iterator class that does the book keeping for you.
+ TypeError: cannot convert dictionary update sequence element #0 to a sequence
-.. nextslide::
-An example: like ``xrange()``
+.. nextslide:: ``dict.fromkeys()``
+
+The stock constructor for a dictionary won't work this way. So the dict object
+implements an alternate constructor that *can*.
.. code-block:: python
- def y_xrange(start, stop, step=1):
- i = start
- while i < stop:
- yield i
- i += step
+ @classmethod
+ def fromkeys(cls, iterable, value=None):
+ '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
+ If not specified, the value defaults to None.
+ '''
+ self = cls()
+ for key in iterable:
+ self[key] = value
+ return self
-Real World Example from FloatCanvas:
+(this is actually from the OrderedDict implementation in ``collections.py``)
-https://github.com/svn2github/wxPython/blob/master/3rdParty/FloatCanvas/floatcanvas/FloatCanvas.py#L100
+See also datetime.datetime.now(), etc....
+.. nextslide:: Curious?
-.. nextslide::
+Properties, Static Methods and Class Methods are powerful features of Python's
+OO model.
-Note:
+They are implemented using an underlying structure called *descriptors*
-.. code-block:: ipython
+`Here is a low level look`_ at how the descriptor protocol works.
- In [164]: gen = y_xrange(2,6)
- In [165]: type(gen)
- Out[165]: generator
- In [166]: dir(gen)
- Out[166]:
- ...
- '__iter__',
- ...
- 'next',
+The cool part is that this mechanism is available to you, the programmer, as
+well.
+.. _Here is a low level look: https://docs.python.org/2/howto/descriptor.html
-So the generator **is** an iterator
-.. nextslide::
+For the Circle Lab: use a class method to make an alternate constructor that takes
+the diameter instead.
-A generator function can also be a method in a class
+===============
+Special Methods
+===============
+.. rst-class:: left
+.. container::
-More about iterators and generators:
+ Special methods (also called *magic* methods) are the secret sauce to Python's Duck typing.
-http://www.learningpython.com/2009/02/23/iterators-iterables-and-generators-oh-my/
+ Defining the appropriate special methods in your classes is how you make your class act like standard classes.
-``code/session08/yield_example.py``
+What's in a Name?
+-----------------
+We've seen at least one special method so far::
-generator comprehension
------------------------
+ __init__
-yet another way to make a generator:
+It's all in the double underscores...
-.. code-block:: python
+Pronounced "dunder" (or "under-under")
- >>> [x * 2 for x in [1, 2, 3]]
- [2, 4, 6]
- >>> (x * 2 for x in [1, 2, 3])
- at 0x10911bf50>
- >>> for n in (x * 2 for x in [1, 2, 3]):
- ... print n
- ... 2 4 6
+try: ``dir(2)`` or ``dir(list)``
+.. nextslide:: Generally Useful Special Methods
-More interesting if [1, 2, 3] is also a generator
+Most classes should at least have these special methods:
-Generator LAB / Homework
--------------------------
+``object.__str__``:
+ Called by the str() built-in function and by the print function to compute
+ the *informal* string representation of an object.
+``object.__repr__``:
+ Called by the repr() built-in function to compute the *official* string representation of an object.
-Write a few generators:
+ (ideally: ``eval( repr(something) ) == something``)
-* Sum of integers
-* Doubler
-* Fibonacci sequence
-* Prime numbers
+(demo)
-(test code in ``code/session08/test_generator.py``)
+Protocols
+----------
-Descriptions:
+.. rst-class:: build
+.. container::
-Sum of the integers:
- keep adding the next integer
+ The set of special methods needed to emulate a particular type of Python object is called a *protocol*.
- 0 + 1 + 2 + 3 + 4 + 5 + ...
+ Your classes can "become" like Python built-in classes by implementing the
+ methods in a given protocol.
- so the sequence is:
+ Remember, these are more *guidelines* than laws. Implement what you need.
- 0, 1, 3, 6, 10, 15 .....
-.. nextslide::
+.. nextslide:: The Numerics Protocol
-Doubler:
- Each value is double the previous value:
+Do you want your class to behave like a number? Implement these methods:
- 1, 2, 4, 8, 16, 32,
+.. code-block:: python
-Fibonacci sequence:
- The fibonacci sequence as a generator:
+ object.__add__(self, other)
+ object.__sub__(self, other)
+ object.__mul__(self, other)
+ object.__floordiv__(self, other)
+ object.__mod__(self, other)
+ object.__divmod__(self, other)
+ object.__pow__(self, other[, modulo])
+ object.__lshift__(self, other)
+ object.__rshift__(self, other)
+ object.__and__(self, other)
+ object.__xor__(self, other)
+ object.__or__(self, other)
- f(n) = f(n-1) + f(n-2)
+.. nextslide:: The Container Protocol
- 1, 1, 2, 3, 5, 8, 13, 21, 34...
+Want to make a container type? Here's what you need:
-Prime numbers:
- Generate the prime numbers (numbers only divisible by them self and 1):
+.. code-block:: python
- 2, 3, 5, 7, 11, 13, 17, 19, 23...
+ object.__len__(self)
+ object.__getitem__(self, key)
+ object.__setitem__(self, key, value)
+ object.__delitem__(self, key)
+ object.__iter__(self)
+ object.__reversed__(self)
+ object.__contains__(self, item)
+ object.__getslice__(self, i, j)
+ object.__setslice__(self, i, j, sequence)
+ object.__delslice__(self, i, j)
-Others to try:
- Try x^2, x^3, counting by threes, x^e, counting by minus seven, ...
+.. nextslide:: An Example
+Each of these methods supports a common Python operation.
-Context Managers
-================
+For example, to make '+' work with a sequence type in a vector-like fashion,
+implement ``__add__``:
-**A Short Digression**
+.. code-block:: python
-.. rst-class:: left build
-.. container::
+ def __add__(self, v):
+ """return the element-wise vector sum of self and v
+ """
+ assert len(self) == len(v)
+ return vector([x1 + x2 for x1, x2 in zip(self, v)])
- Repetition in code stinks.
+.. rst-class:: centered
- A large source of repetition in code deals with the handling of externals
- resources.
+A more complete example may be seen in:
- As an example, how many times do you think you might type the following
- code:
+Examples/Session08/vector.py
- .. code-block:: python
+or: :download:`here <../../Examples/Session08/vector.py>`
- file_handle = open('filename.txt', 'r')
- file_content = file_handle.read()
- file_handle.close()
- # do some stuff with the contents
+.. nextslide:: Summary
- What happens if you forget to call ``.close()``?
+Use special methods when you want your class to act like a "standard" class in
+some way.
- What happens if reading the file raises an exception?
+Look up the special methods you need and define them.
-Resource Handling
------------------
+There's more to read about the details of implementing these methods:
-Leaving an open file handle laying around is bad enough. What if the resource
-is a network connection, or a database cursor?
+* https://docs.python.org/3.5/reference/datamodel.html#special-method-names
+* https://github.com/RafeKettler/magicmethods/blob/master/magicmethods.markdown
-You can write more robust code for handling your resources:
+===
+LAB
+===
-.. code-block:: python
+Let's complete our nifty Circle class:
- try:
- file_handle = open('filename.txt', 'r')
- file_content = file_handle.read()
- finally:
- file_handle.close()
- # do something with file_content here
+Steps 5-8 of:
-But what exceptions do you want to catch? And do you really want to have to
-remember all that **every** time you open a resource?
+:ref:`exercise_circle_class`
-.. nextslide:: It Gets Better
-Starting in version 2.5, Python provides a structure for reducing the
-repetition needed to handle resources like this.
+=========================
+Emulating Standard types
+=========================
-.. rst-class:: centered
+.. rst-class:: medium
-**Context Managers**
+ Making your classes behave like the built-ins
-You can encapsulate the setup, error handling and teardown of resources in a
-few simple steps.
-The key is to use the ``with`` statement.
+Callable classes
+-----------------
+
+We've been using functions a lot:
+
+.. code-block:: python
-.. nextslide:: ``with`` a little help
+ def my_fun(something):
+ do_something
+ ...
+ return something
-Since the introduction of the ``with`` statement in `pep343`_, the above six
-lines of defensive code have been replaced with this simple form:
+And then we can call it:
.. code-block:: python
- with open('filename', 'r') as file_handle:
- file_content = file_handle.read()
- # do something with file_content
+ result = my_fun(some_arguments)
-``open`` builtin is defined as a *context manager*.
+.. nextslide::
-The resource it returnes (``file_handle``) is automatically and reliably closed
-when the code block ends.
+But what if we need to store some data to know how to evaluate that function?
-.. _pep343: http://legacy.python.org/dev/peps/pep-0343/
+Example: a function that computes a quadratic function:
-.. nextslide:: A Growing Trend
+.. math::
-At this point in Python history, many functions you might expect to behave this
-way do:
+ y = a x^2 + bx + c
-.. rst-class:: build
+You could pass in a, b and c each time:
-* ``open`` and ``codecs.open`` both work as context managers
-* networks connections via ``socket`` do as well.
-* most implementations of database wrappers can open connections or cursors as
- context managers.
-* ...
+.. code-block:: python
+
+ def quadratic(x, a, b, c):
+ return a * x**2 + b * x + c
-But what if you are working with a library that doesn't support this
-(``urllib``)?
+But what if you are using the same a, b, and c numerous times?
-.. nextslide:: Close It Automatically
+Or what if you need to pass this in to something
+(like map) that requires a function that takes a single argument?
-There are a couple of ways you can go.
+"Callables"
+-----------
-If the resource in questions has a ``.close()`` method, then you can simply use
-the ``closing`` context manager from ``contextlib`` to handle the issue:
+Various places in python expect a "callable" -- something that you can
+call like a function:
.. code-block:: python
- import urllib
- from contextlib import closing
+ a_result = something(some_arguments)
- with closing(urllib.urlopen('http://google.com/')) as web_connection:
- # do something with the open resource
- # and here, it will be closed automatically
+"something" in this case is often a function, but can be anything else
+that is "callable".
-But what if the thing doesn't have a ``close()`` method, or you're creating the thing and it shouldn't?
+What have we been introduced to recently that is "callable", but not a
+function object?
-.. nextslide:: Do It Yourself
+Custom callable objects
+------------------------
-You can also define a context manager of your own.
+The trick is one of Python's "magic methods"
-The interface is simple. It must be a class that implements these two *special
-methods*:
+.. code-block:: python
-``__enter__(self)``:
- Called when the ``with`` statement is run, it should return something to work
- with in the created context.
+ __call__(*args, **kwargs)
-``__exit__(self, e_type, e_val, e_traceback)``:
- Clean-up that needs to happen is implemented here.
+If you define a ``__call__`` method in your class, it will be used when
+code "calls" an instance of your class:
- The arguments will be the exception raised in the context.
+.. code-block:: python
- If the exception will be handled here, return True. If not, return False.
+ class Callable:
+ def __init__(self, .....)
+ some_initilization
+ def __call__(self, some_parameters)
-Let's see this in action to get a sense of what happens.
+Then you can do:
-An Example
-----------
+.. code-block:: python
-Consider this code:
+ callable_instance = Callable(some_arguments)
-.. code-block:: python
+ result = callable_instance(some_arguments)
- class Context(object):
- """from Doug Hellmann, PyMOTW
- http://pymotw.com/2/contextlib/#module-contextlib
- """
- def __init__(self, handle_error):
- print '__init__(%s)' % handle_error
- self.handle_error = handle_error
- def __enter__(self):
- 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
-.. nextslide::
+Writing your own sequence type
+-------------------------------
-This class doesn't do much of anything, but playing with it can help clarify
-the order in which things happen:
+Python has a handful of nifty sequence types built in:
-.. code-block:: ipython
+ * lists
+ * tuples
+ * strings
+ * ...
- In [46]: with Context(True) as foo:
- ....: print 'This is in the context'
- ....: raise RuntimeError('this is the error message')
- __init__(True)
- __enter__()
- This is in the context
- __exit__(, this is the error message, )
+But what if you need a sequence that isn't built in?
-.. rst-class:: build
-.. container::
+A Sparse array
+--------------
- Because the exit method returns True, the raised error is 'handled'.
+Example: Sparse Array
-.. nextslide::
+Sometimes we have data sets that are "sparse" -- i.e. most of the values are zero.
-What if we try with ``False``?
+So you may not want to store a huge bunch of zeros.
-.. code-block:: ipython
+But you do want the array to look like a regular old sequence.
- In [47]: with Context(False) as foo:
- ....: print 'This is in the context'
- ....: raise RuntimeError('this is the error message')
- __init__(False)
- __enter__()
- This is in the context
- __exit__(, this is the error message, )
- ---------------------------------------------------------------------------
- RuntimeError Traceback (most recent call last)
- in ()
- 1 with Context(False) as foo:
- 2 print 'This is in the context'
- ----> 3 raise RuntimeError('this is the error message')
- 4
- RuntimeError: this is the error message
+So how do you do that?
-.. nextslide:: ``contextmanager`` decorator
+The Sequence protocol
+----------------------
-``contextlib.contextmanager`` turns generator functions into context managers
+You can make your class look like a regular python sequence by defining
+the set of special methods you need:
-Consider this code:
+https://docs.python.org/3/reference/datamodel.html#emulating-container-types
-.. code-block:: python
+and
- from contextlib import contextmanager
-
- @contextmanager
- def context(boolean):
- print "__init__ code here"
- try:
- print "__enter__ code goes here"
- yield object()
- except Exception as e:
- print "errors handled here"
- if not boolean:
- raise
- finally:
- print "__exit__ cleanup goes here"
+https://github.com/RafeKettler/magicmethods/blob/master/magicmethods.markdown#sequence
-.. nextslide::
+The key ones are:
-The code is similar to the class defined previously.
++-------------------+-----------------------+
+| ``__len__`` | for ``len(sequence)`` |
++-------------------+-----------------------+
+| ``__getitem__`` | for ``x = seq[i]`` |
++-------------------+-----------------------+
+| ``__setitem__`` | for ``seq[i] = x`` |
++-------------------+-----------------------+
+| ``__delitem__`` | for ``del seq[i]`` |
++-------------------+-----------------------+
+| ``__contains__`` | for ``x in seq`` |
++-------------------+-----------------------+
-And using it has similar results. We can handle errors:
+====
+LAB
+====
-.. code-block:: ipython
+.. rst-class:: medium
- In [50]: with context(True):
- ....: print "in the context"
- ....: raise RuntimeError("error raised")
- __init__ code here
- __enter__ code goes here
- in the context
- errors handled here
- __exit__ cleanup goes here
+ Let's do the previous motivating examples.
-.. nextslide::
+Callables:
+-----------
-Or, we can allow them to propagate:
+Write a class for a quadratic equation.
-.. code-block:: ipython
+* The initializer for that class should take the parameters: ``a, b, c``
- In [51]: with context(False):
- ....: print "in the context"
- ....: raise RuntimeError("error raised")
- __init__ code here
- __enter__ code goes here
- in the context
- errors handled here
- __exit__ cleanup goes here
- ---------------------------------------------------------------------------
- RuntimeError Traceback (most recent call last)
- in ()
- 1 with context(False):
- 2 print "in the context"
- ----> 3 raise RuntimeError("error raised")
- 4
- RuntimeError: error raised
+* It should store those parameters as attributes.
-Homework
-========
+* The resulting instance should evaluate the function when called, and return the result:
-Python Power
+.. code-block:: python
-Assignments
------------
+ my_quad = Quadratic(a=2, b=3, c=1)
-Task 1: Timing Context Manager
+ my_quad(0)
-Create a context manager that will print to stdout the elapsed time taken to
-run all the code inside the context:
+Sparse Array:
+-------------
-.. code-block:: ipython
+Write a class for a sparse array:
- In [3]: with Timer() as t:
- ...: for i in range(100000):
- ...: i = i ** 20
- ...:
- this code took 0.206805 seconds
+:ref:`exercise_sparse_array`
-**Extra Credit**: allow the ``Timer`` context manager to take a file-like
-object as an argument (the default should be sys.stdout). The results of the
-timing should be printed to the file-like object.
+========
+Homework
+========
-.. nextslide::
+.. rst-class:: left
-Task 2: ``p-wrapper`` Decorator
+ Reading:
-Write a simple decorator you can apply to a function that returns a string.
-Decorating such a function should result in the original output, wrapped by an
-HTML 'p' tag:
+ Lambda:
-.. code-block:: ipython
+ http://www.blog.pythonlibrary.org/2015/10/28/python-101-lambda-basics/
- In [4]: @p_wrapper
- ...: def return_a_string(string):
- ...: return string
- ...:
+ https://pythonconquerstheuniverse.wordpress.com/2011/08/29/lambda_tutorial/
- In [5]: return_a_string("this is a string")
- Out[5]: '
this is a string
'
+ Complete the Circle class
-.. nextslide::
+ Complete the Sparse Array class
-Task 3: Generator Homework (documented above)
+ Decide what you are going to do for your project, and send me a simple proposal. Get started if you can.
-Task 4: Iterator Homework (documented above)
+ Good book:
+ Python 3 Object Oriented Programming: *Dusty Phillips*
+ (Dusty is a local boy and co-founder of PuPPy)
diff --git a/slides_sources/source/session09.rst b/slides_sources/source/session09.rst
new file mode 100644
index 00000000..e6d953d7
--- /dev/null
+++ b/slides_sources/source/session09.rst
@@ -0,0 +1,656 @@
+.. include:: include.rst
+
+************************************************************
+Anonymous Functions and Iterators, Iterables, and Generators
+************************************************************
+
+====================
+Lightning Talks Now:
+====================
+
+.. rst-class:: medium
+
+ Jack M Hefner
+
+ Ninad Naik
+
+ Simbarashe P Change
+
+
+===================
+Anonymous functions
+===================
+
+lambda
+------
+
+.. code-block:: ipython
+
+ In [171]: f = lambda x, y: x+y
+ In [172]: f(2,3)
+ Out[172]: 5
+
+Content of function can only be an expression -- not a statement
+
+Anyone remember what the difference is?
+
+Called "Anonymous": it doesn't get a name.
+
+.. nextslide::
+
+It's a python object, it can be stored in a list or other container
+
+.. code-block:: ipython
+
+ In [7]: l = [lambda x, y: x+y]
+ In [8]: type(l[0])
+ Out[8]: function
+
+
+And you can call it:
+
+.. code-block:: ipython
+
+ In [9]: l[0](3,4)
+ Out[9]: 7
+
+
+Functions as first class objects
+---------------------------------
+
+You can do that with "regular" functions too:
+
+.. code-block:: ipython
+
+ In [12]: def fun(x,y):
+ ....: return x+y
+ ....:
+ In [13]: l = [fun]
+ In [14]: type(l[0])
+ Out[14]: function
+ In [15]: l[0](3,4)
+ Out[15]: 7
+
+
+
+======================
+Functional Programming
+======================
+
+No real consensus about what that means.
+
+But there are some "classic" methods available in Python.
+
+map
+---
+
+``map`` "maps" a function onto a sequence of objects -- It applies the function to each item in the list, returning another list
+
+
+.. code-block:: ipython
+
+ In [23]: l = [2, 5, 7, 12, 6, 4]
+ In [24]: def fun(x):
+ return x*2 + 10
+ In [25]: map(fun, l)
+ Out[25]: