diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..72b5e14
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,19 @@
+
+py101code\.wpr
+
+py101code\.wpu
+
+py101_2nd_code.wpr
+
+py101_2nd_code.wpu
+
+.DS_Store
+
+.ipynb_checkpoints
+chapter22_type_hints/.mypy_cache/
+
+*.pyc
+*.zip
+*.db
+*.pdf
+*.mypy_cache
\ No newline at end of file
diff --git a/Appendix A/backers.csv b/Appendix A/backers.csv
deleted file mode 100644
index 7e95d94..0000000
--- a/Appendix A/backers.csv
+++ /dev/null
@@ -1,3 +0,0 @@
-Mike Driscoll,test@py.com
-Andy Hunter,andwa@hunter.org
-Toby Mac,macdaddy@gotee.com
\ No newline at end of file
diff --git a/Appendix A/book_maker.py b/Appendix A/book_maker.py
deleted file mode 100644
index 47e0099..0000000
--- a/Appendix A/book_maker.py
+++ /dev/null
@@ -1,56 +0,0 @@
-import os
-import subprocess
-
-chapters = ['chapter_1.rst',
- 'chapter_2.rst',
- 'chapter_3.rst']
-
-def read_chapter(chapter):
- """
- Reads a chapter and returns the stream
- """
- path = os.path.join("data", chapter)
- try:
- with open(path) as chp_handler:
- data = chp_handler.read()
- except (IOError, OSError):
- raise Exception("Unable to open chapter: %s" % chapter)
- return data
-
-def make_book(name="Mike", email_address="test@py.com"):
- """
- Creates Python 101 book
- """
- book_path = "output/python101.rst"
- pdf_path = "output/python101.pdf"
- page_break = """
-.. raw:: pdf
-
- PageBreak
- """
- footer = """
-.. footer::
-
- Copyright |copy| 2014 by Michael Driscoll, all rights reserved.
- Licensed to %s <%s>
-
-.. |copy| unicode:: 0xA9 .. copyright sign
- """ % (name, email_address)
- try:
- with open(book_path, "w") as book:
- book.write(footer + "\n")
- for chapter in chapters:
- data = read_chapter(chapter)
- book.write(data)
- book.write("\n")
- book.write(page_break + "\n")
- except:
- print("Error writing book!")
- raise
-
- cmd = [r"C:\Python27\Scripts\rst2pdf.exe",
- book_path, "-o", pdf_path]
- subprocess.call(cmd)
-
-if __name__ == "__main__":
- make_book()
\ No newline at end of file
diff --git a/Appendix A/book_maker2.py b/Appendix A/book_maker2.py
deleted file mode 100644
index 3d52f04..0000000
--- a/Appendix A/book_maker2.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import csv
-import os
-import subprocess
-
-chapters = ['chapter_1.rst',
- 'chapter_2.rst',
- 'chapter_3.rst']
-
-def read_chapter(chapter):
- """
- Reads a chapter and returns the stream
- """
- path = os.path.join("data", chapter)
- try:
- with open(path) as chp_handler:
- data = chp_handler.read()
- except (IOError, OSError):
- raise Exception("Unable to open chapter: %s" % chapter)
- return data
-
-def make_book(name="Mike", email_address="test@py.com"):
- """
- Creates Python 101 book
- """
- book_path = "output/python101.rst"
- pdf_path = "output/python101.pdf"
- page_break = """
-.. raw:: pdf
-
- PageBreak
- """
- footer = """
-.. footer::
-
- Copyright |copy| 2014 by Michael Driscoll, all rights reserved.
- Licensed to %s <%s>
-
-.. |copy| unicode:: 0xA9 .. copyright sign
- """ % (name, email_address)
- try:
- with open(book_path, "w") as book:
- book.write(footer + "\n")
- for chapter in chapters:
- data = read_chapter(chapter)
- book.write(data)
- book.write("\n")
- book.write(page_break + "\n")
- except:
- print("Error writing book!")
- raise
-
- cmd = [r"C:\Python27\Scripts\rst2pdf.exe",
- book_path, "-o", pdf_path]
- subprocess.call(cmd)
-
-def main(path):
- """"""
- try:
- with open(path) as csv_file:
- reader = csv.reader(csv_file)
- for line in reader:
- name, email = line
- make_book(name, email)
- except IOError:
- print("Error reading file: %s" % path)
- raise
-
-if __name__ == "__main__":
- main("backers.csv")
\ No newline at end of file
diff --git a/Appendix A/book_maker3.py b/Appendix A/book_maker3.py
deleted file mode 100644
index b91b9aa..0000000
--- a/Appendix A/book_maker3.py
+++ /dev/null
@@ -1,116 +0,0 @@
-import csv
-import os
-import smtplib
-import subprocess
-
-from email import encoders
-from email.mime.text import MIMEText
-from email.mime.base import MIMEBase
-from email.mime.multipart import MIMEMultipart
-from email.utils import formatdate
-
-chapters = ['chapter_1.rst',
- 'chapter_2.rst',
- 'chapter_3.rst']
-
-def make_book(name="Mike", email_address="test@py.com"):
- """
- Creates Python 101 book
- """
- book_path = "output/python101.rst"
- pdf_path = "output/python101.pdf"
- page_break = """
-.. raw:: pdf
-
- PageBreak
- """
- footer = """
-.. footer::
-
- Copyright |copy| 2014 by Michael Driscoll, all rights reserved.
- Licensed to %s <%s>
-
-.. |copy| unicode:: 0xA9 .. copyright sign
- """ % (name, email_address)
- try:
- with open(book_path, "w") as book:
- book.write(footer + "\n")
- for chapter in chapters:
- data = read_chapter(chapter)
- book.write(data)
- book.write("\n")
- book.write(page_break + "\n")
- except:
- print("Error writing book!")
- raise
-
- cmd = [r"C:\Python27\Scripts\rst2pdf.exe",
- book_path, "-o", pdf_path]
- subprocess.call(cmd)
- return pdf_path
-
-def read_chapter(chapter):
- """
- Reads a chapter and returns the stream
- """
- path = os.path.join("data", chapter)
- try:
- with open(path) as chp_handler:
- data = chp_handler.read()
- except (IOError, OSError):
- raise Exception("Unable to open chapter: %s" % chapter)
- return data
-
-def send_email(email, pdf):
- """
- Send an email out
- """
- header0 = 'Content-Disposition'
- header1 ='attachment; filename="%s"' % os.path.basename(pdf)
- header = header0, header1
-
- host = "mail.server.com"
- server = smtplib.SMTP(host)
- subject = "Test email from Python"
- to = email
- from_addr = "test@pylib.com"
- body_text = "Here is the Alpha copy of Python 101, Part I"
-
- # create the message
- msg = MIMEMultipart()
- msg["From"] = from_addr
- msg["Subject"] = subject
- msg["Date"] = formatdate(localtime=True)
- msg["To"] = email
-
- msg.attach( MIMEText(body_text) )
-
- attachment = MIMEBase('application', "octet-stream")
- try:
- with open(pdf, "rb") as fh:
- data = fh.read()
- attachment.set_payload( data )
- encoders.encode_base64(attachment)
- attachment.add_header(*header)
- msg.attach(attachment)
- except IOError:
- msg = "Error opening attachment file %s" % file_to_attach
- print(msg)
-
- server.sendmail(from_addr, to, msg.as_string())
-
-def main(path):
- """"""
- try:
- with open(path) as csv_file:
- reader = csv.reader(csv_file)
- for line in reader:
- name, email = line
- pdf = make_book(name, email)
- send_email(email, pdf)
- except IOError:
- print("Error reading file: %s" % path)
- raise
-
-if __name__ == "__main__":
- main("backers.csv")
\ No newline at end of file
diff --git a/Appendix A/csv_reader.py b/Appendix A/csv_reader.py
deleted file mode 100644
index b3b96f5..0000000
--- a/Appendix A/csv_reader.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import csv
-
-def read_csv(path):
- """"""
- try:
- with open(path) as csv_file:
- reader = csv.reader(csv_file)
- for line in reader:
- name, email = line
- print(name)
- print(email)
- except IOError:
- print("Error reading file: %s" % path)
- raise
-
-if __name__ == "__main__":
- path = "backers.csv"
- read_csv(path)
\ No newline at end of file
diff --git a/Appendix A/send_email.py b/Appendix A/send_email.py
deleted file mode 100644
index 150bf99..0000000
--- a/Appendix A/send_email.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import os
-import smtplib
-
-from email import encoders
-from email.mime.text import MIMEText
-from email.mime.base import MIMEBase
-from email.mime.multipart import MIMEMultipart
-from email.utils import formatdate
-
-def send_email(email, pdf):
- """
- Send an email out
- """
- header0 = 'Content-Disposition'
- header1 ='attachment; filename="%s"' % os.path.basename(pdf)
- header = header0, header1
-
- host = "mail.server.com"
- server = smtplib.SMTP(host)
- subject = "Test email from Python"
- to = email
- from_addr = "test@pylib.com"
- body_text = "Here is the Alpha copy of Python 101, Part I"
-
- # create the message
- msg = MIMEMultipart()
- msg["From"] = from_addr
- msg["Subject"] = subject
- msg["Date"] = formatdate(localtime=True)
- msg["To"] = email
-
- msg.attach( MIMEText(body_text) )
-
- attachment = MIMEBase('application', "octet-stream")
- try:
- with open(pdf, "rb") as fh:
- data = fh.read()
- attachment.set_payload( data )
- encoders.encode_base64(attachment)
- attachment.add_header(*header)
- msg.attach(attachment)
- except IOError:
- msg = "Error opening attachment file %s" % file_to_attach
- print(msg)
-
- server.sendmail(from_addr, to, msg.as_string())
-
-if __name__ == "__main__":
- send_email("mike@example.org", "output/python101.pdf")
\ No newline at end of file
diff --git a/Chapter 10 - Functions/add.py b/Chapter 10 - Functions/add.py
deleted file mode 100644
index c273f7b..0000000
--- a/Chapter 10 - Functions/add.py
+++ /dev/null
@@ -1,14 +0,0 @@
-def add(a, b):
- return a + b
-
-# call the function with arguments
-add(1, 2)
-
-# call the function with the wrong number of arguments
-add(1) # causes a TypeError
-
-# call the function with keyword arguments
-add(a=2, b=3)
-
-# assign the result to a variable
-total = add(b=4, a=5)
\ No newline at end of file
diff --git a/Chapter 10 - Functions/args_and_kwargs.py b/Chapter 10 - Functions/args_and_kwargs.py
deleted file mode 100644
index c90a85e..0000000
--- a/Chapter 10 - Functions/args_and_kwargs.py
+++ /dev/null
@@ -1,5 +0,0 @@
-def many(*args, **kwargs):
- print(args)
- print(kwargs)
-
-many(1, 2, 3, name="Mike", job="programmer")
\ No newline at end of file
diff --git a/Chapter 10 - Functions/kw_func.py b/Chapter 10 - Functions/kw_func.py
deleted file mode 100644
index ca09806..0000000
--- a/Chapter 10 - Functions/kw_func.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# create a function with defaults
-def keyword_function(a=1, b=2):
- return a+b
-
-# call it with keyword arguments
-keyword_function(b=4, a=5)
-
-# call the function without arguments (i.e. use the defaults)
-keyword_function()
\ No newline at end of file
diff --git a/Chapter 10 - Functions/kw_func2.py b/Chapter 10 - Functions/kw_func2.py
deleted file mode 100644
index ad271b0..0000000
--- a/Chapter 10 - Functions/kw_func2.py
+++ /dev/null
@@ -1,8 +0,0 @@
-def mixed_function(a, b=2, c=3):
- return a+b+c
-
-# call the function with one argument and 2 keyword arguments
-mixed_function(1, b=4, c=5)
-
-# call the argument with just the required argument
-mixed_function(1)
\ No newline at end of file
diff --git a/Chapter 10 - Functions/scope.py b/Chapter 10 - Functions/scope.py
deleted file mode 100644
index 546d8ed..0000000
--- a/Chapter 10 - Functions/scope.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# this script demonstrates scope issues and will
-# raise a NameError if run
-
-def function_a():
- a = 1
- b = 2
- return a+b
-
-def function_b():
- c = 3
- return a+c
-
-print( function_a() )
-print( function_b() )
\ No newline at end of file
diff --git a/Chapter 10 - Functions/scope2.py b/Chapter 10 - Functions/scope2.py
deleted file mode 100644
index 91abbe8..0000000
--- a/Chapter 10 - Functions/scope2.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# this script demonstrates how to use a global
-# to fic the scope issue in scope.py
-
-def function_a():
- global a
- a = 1
- b = 2
- return a+b
-
-def function_b():
- c = 3
- return a+c
-
-print(function_a())
-print(function_b())
\ No newline at end of file
diff --git a/Chapter 10 - Functions/simple_function.py b/Chapter 10 - Functions/simple_function.py
deleted file mode 100644
index d5914b1..0000000
--- a/Chapter 10 - Functions/simple_function.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# create a simple function
-def a_function():
- print("You just created a function!")
\ No newline at end of file
diff --git a/Chapter 10 - Functions/stub.py b/Chapter 10 - Functions/stub.py
deleted file mode 100644
index 61a6746..0000000
--- a/Chapter 10 - Functions/stub.py
+++ /dev/null
@@ -1,2 +0,0 @@
-def empty_function():
- pass
\ No newline at end of file
diff --git a/Chapter 11 - Classes/car_subclass.py b/Chapter 11 - Classes/car_subclass.py
deleted file mode 100644
index 24ed722..0000000
--- a/Chapter 11 - Classes/car_subclass.py
+++ /dev/null
@@ -1,19 +0,0 @@
-class Car(Vehicle):
- """
- The Car class
- """
-
-
- def brake(self):
- """
- Override brake method
- """
- return "The car class is breaking slowly!"
-
-
-if __name__ == "__main__":
- car = Car("yellow", 2, 4, "car")
- car.brake()
- 'The car class is breaking slowly!'
- car.drive()
- "I'm driving a yellow car!"
\ No newline at end of file
diff --git a/Chapter 11 - Classes/simple_class_2.x.py b/Chapter 11 - Classes/simple_class_2.x.py
deleted file mode 100644
index fe4eef4..0000000
--- a/Chapter 11 - Classes/simple_class_2.x.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Python 2.x syntax
-class Vehicle(object):
- """docstring"""
-
- def __init__(self):
- """Constructor"""
- pass
\ No newline at end of file
diff --git a/Chapter 11 - Classes/simple_class_3.x.py b/Chapter 11 - Classes/simple_class_3.x.py
deleted file mode 100644
index 02702ec..0000000
--- a/Chapter 11 - Classes/simple_class_3.x.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Python 3.x syntax
-class Vehicle:
- """docstring"""
-
- def __init__(self):
- """Constructor"""
- pass
\ No newline at end of file
diff --git a/Chapter 11 - Classes/vehicle.py b/Chapter 11 - Classes/vehicle.py
deleted file mode 100644
index e06da5b..0000000
--- a/Chapter 11 - Classes/vehicle.py
+++ /dev/null
@@ -1,30 +0,0 @@
-class Vehicle(object):
- """docstring"""
-
-
- def __init__(self, color, doors, tires):
- """Constructor"""
- self.color = color
- self.doors = doors
- self.tires = tires
-
-
- def brake(self):
- """
- Stop the car
- """
- return "Braking"
-
-
- def drive(self):
- """
- Drive the car
- """
- return "I'm driving!"
-
-
-if __name__ == "__main__":
- car = Vehicle("blue", 5, 4)
- print(car.color)
- truck = Vehicle("red", 3, 6)
- print(truck.color)
\ No newline at end of file
diff --git a/Chapter 11 - Classes/vehicle2.py b/Chapter 11 - Classes/vehicle2.py
deleted file mode 100644
index 43dded1..0000000
--- a/Chapter 11 - Classes/vehicle2.py
+++ /dev/null
@@ -1,33 +0,0 @@
-class Vehicle(object):
- """docstring"""
-
-
- def __init__(self, color, doors, tires, vtype):
- """Constructor"""
- self.color = color
- self.doors = doors
- self.tires = tires
- self.vtype = vtype
-
-
- def brake(self):
- """
- Stop the car
- """
- return "%s braking" % self.vtype
-
-
- def drive(self):
- """
- Drive the car
- """
- return "I'm driving a %s %s!" % (self.color, self.vtype)
-
-
-if __name__ == "__main__":
- car = Vehicle("blue", 5, 4, "car")
- print(car.brake())
- print(car.drive())
- truck = Vehicle("red", 3, 6, "truck")
- print(truck.drive())
- print(truck.brake())
\ No newline at end of file
diff --git a/Chapter 12 - Introspection/readme.txt b/Chapter 12 - Introspection/readme.txt
deleted file mode 100644
index 5803d6c..0000000
--- a/Chapter 12 - Introspection/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-This chapter was skipped because it just demonstrates different ways of importing modules. The examples in chapter 12 should be practiced in IDLE or a Python editor of your choice.
\ No newline at end of file
diff --git a/Chapter 13 - csv/TB_data_dictionary_2014-02-26.csv b/Chapter 13 - csv/TB_data_dictionary_2014-02-26.csv
deleted file mode 100644
index bd7473a..0000000
--- a/Chapter 13 - csv/TB_data_dictionary_2014-02-26.csv
+++ /dev/null
@@ -1,265 +0,0 @@
-"variable_name","dataset","code_list","definition"
-"country","Country identification",,"Country or territory name"
-"iso_numeric","Country identification",,"ISO numeric country/territory code"
-"iso2","Country identification",,"ISO 2-character country/territory code"
-"iso3","Country identification",,"ISO 3-character country/territory code"
-"c_cdr","Estimates",,"Case detection rate (all forms), percent"
-"c_cdr_hi","Estimates",,"Case detection rate (all forms), percent, high bound"
-"c_cdr_lo","Estimates",,"Case detection rate (all forms), percent, low bound"
-"e_inc_100k","Estimates",,"Estimated incidence (all forms) per 100 000 population"
-"e_inc_100k_hi","Estimates",,"Estimated incidence (all forms) per 100 000 population, high bound"
-"e_inc_100k_lo","Estimates",,"Estimated incidence (all forms) per 100 000 population, low bound"
-"e_inc_num","Estimates",,"Estimated number of incident cases (all forms)"
-"e_inc_num_hi","Estimates",,"Estimated number of incident cases (all forms), high bound"
-"e_inc_num_lo","Estimates",,"Estimated number of incident cases (all forms), low bound"
-"e_inc_tbhiv_100k","Estimates",,"Estimated incidence of TB cases who are HIV-positive per 100 000 population"
-"e_inc_tbhiv_100k_hi","Estimates",,"Estimated incidence of TB cases who are HIV-positive per 100 000 population, high bound"
-"e_inc_tbhiv_100k_lo","Estimates",,"Estimated incidence of TB cases who are HIV-positive per 100 000 population, low bound"
-"e_inc_tbhiv_num","Estimates",,"Estimated incidence of TB cases who are HIV-positive"
-"e_inc_tbhiv_num_hi","Estimates",,"Estimated incidence of TB cases who are HIV-positive, high bound"
-"e_inc_tbhiv_num_lo","Estimates",,"Estimated incidence of TB cases who are HIV-positive, low bound"
-"e_mdr_num","Estimates",,"Estimated number of MDR-TB cases among all notified pulmonary TB cases"
-"e_mdr_num_hi","Estimates",,"Estimated number of MDR-TB cases among all notified pulmonary TB cases: high bound"
-"e_mdr_num_lo","Estimates",,"Estimated number of MDR-TB cases among all notified pulmonary TB cases: low bound"
-"e_mort_exc_tbhiv_100k","Estimates",,"Estimated mortality of TB cases (all forms, excluding HIV) per 100 000 population"
-"e_mort_exc_tbhiv_100k_hi","Estimates",,"Estimated mortality of TB cases (all forms, excluding HIV), per 100 000 population, high bound"
-"e_mort_exc_tbhiv_100k_lo","Estimates",,"Estimated mortality of TB cases (all forms, excluding HIV), per 100 000 population, low bound"
-"e_mort_exc_tbhiv_num","Estimates",,"Estimated number of deaths from TB (all forms, excluding HIV)"
-"e_mort_exc_tbhiv_num_hi","Estimates",,"Estimated number of deaths from TB (all forms, excluding HIV), high bound"
-"e_mort_exc_tbhiv_num_lo","Estimates",,"Estimated number of deaths from TB (all forms, excluding HIV), low bound"
-"e_new_mdr_num","Estimates",,"Estimated number of MDR-TB cases among notified new pulmonary TB cases"
-"e_new_mdr_num_hi","Estimates",,"Estimated number of MDR-TB cases among notified new pulmonary TB cases: high bound"
-"e_new_mdr_num_lo","Estimates",,"Estimated number of MDR-TB cases among notified new pulmonary TB cases: low bound"
-"e_new_mdr_pcnt","Estimates",,"Estimated percentage of new TB cases with MDR-TB"
-"e_new_mdr_pcnt_hi","Estimates",,"Estimated percentage of new TB cases with MDR-TB: high bound"
-"e_new_mdr_pcnt_lo","Estimates",,"Estimated percentage of new TB cases with MDR-TB: low bound"
-"e_pop_num","Estimates",,"Estimated total population number"
-"e_prev_100k","Estimates",,"Estimated prevalence of TB (all forms) per 100 000 population"
-"e_prev_100k_hi","Estimates",,"Estimated prevalence of TB (all forms) per 100 000 population, high bound"
-"e_prev_100k_lo","Estimates",,"Estimated prevalence of TB (all forms) per 100 000 population, low bound"
-"e_prev_num","Estimates",,"Estimated prevalence of TB (all forms)"
-"e_prev_num_hi","Estimates",,"Estimated prevalence of TB (all forms), high bound"
-"e_prev_num_lo","Estimates",,"Estimated prevalence of TB (all forms), low bound"
-"e_ret_mdr_num","Estimates",,"Estimated number of MDR-TB cases among notified previously treated pulmonary TB cases"
-"e_ret_mdr_num_hi","Estimates",,"Estimated number of MDR-TB cases among notified previously treated pulmonary TB cases: high bound"
-"e_ret_mdr_num_lo","Estimates",,"Estimated number of MDR-TB cases among notified previously treated pulmonary TB cases: low bound"
-"e_ret_mdr_pcnt","Estimates",,"Estimated percentage of previously treated TB cases with MDR-TB"
-"e_ret_mdr_pcnt_hi","Estimates",,"Estimated percentage of previously treated TB cases with MDR-TB: high bound"
-"e_ret_mdr_pcnt_lo","Estimates",,"Estimated percentage of previously treated TB cases with MDR-TB: low bound"
-"e_tbhiv_prct","Estimates",,"Estimated HIV in incident TB (percent)"
-"e_tbhiv_prct_hi","Estimates",,"Estimated HIV in incident TB (percent), high bound"
-"e_tbhiv_prct_lo","Estimates",,"Estimated HIV in incident TB (percent), low bound"
-"source_drs_coverage_new","Estimates",,"Indicates whether national or subnational data from drug resistance surveys or surveillance was used to estimate the proportion of new TB cases with MDR-TB"
-"source_drs_coverage_ret","Estimates",,"Indicates whether national or subnational data from drug resistance surveys or surveillance was used to estimate the proportion of previously treated TB cases with MDR-TB"
-"source_drs_year_new","Estimates",,"Year of drug resistance surveillance, survey or model used to estimate proportion of new TB cases with MDR-TB"
-"source_drs_year_ret","Estimates",,"Year of drug resistance surveillance, survey or model used to estimate proportion of previously treated TB cases with MDR-TB"
-"source_mdr_new","Estimates","DRS=drug resistance surveillance or survey; Model=statistical model","Method used to estimate proportion of new TB patients with MDR-TB"
-"source_mdr_ret","Estimates","DRS=drug resistance surveillance or survey; Model=statistical model","Method used to estimate proportion of previously-treated TB patients with MDR-TB"
-"source_mort","Estimates",,"Method to derive mortality data "
-"source_tbhiv","Estimates",,"Method to derive TBHIV data"
-"conf_mdr_tx","Notification",,"Number of laboratory-confirmed MDR-TB patients who started treatment for MDR-TB"
-"conf_xdr_tx","Notification",,"Number of laboratory-confirmed XDR-TB patients who started treatment for XDR-TB"
-"dst_rlt_new","Notification",,"Drug resistance surveillance: Among new TB patients with positive identification for M. Tuberculosis complex (confirmed by culture and/or line-probe assay): number of patients with available drug susceptibility testing results for isoniazid and rifampicin"
-"dst_rlt_ret","Notification",,"Drug resistance surveillance: Among patients previously treated for TB with positive identification for M. Tuberculosis complex (confirmed by culture and/or line-probe assay): number of patients with available drug susceptibility testing results for isoniazid and rifampicin"
-"dst_rlt_unk","Notification",,"Drug resistance surveillance: Among patients with unknown TB treatment history with positive identification for M. Tuberculosis complex (confirmed by culture and/or line-probe assay): number of patients with available drug susceptibility testing results for isoniazid and rifampicin"
-"hiv_art","Notification",,"HIV-positive TB patients started or continued on antiretroviral therapy (ART)"
-"hiv_cpt","Notification",,"HIV-positive TB patients started or continued on co-trimoxazole preventive therapy (CPT)"
-"hiv_ipt","Notification",,"People registered as HIV-positive given isoniazid prophylaxis (treatment of latent TB infection)"
-"hiv_reg","Notification",,"Total number of people registered as HIV-positive regardless of year of diagnosis. (Total number of adults and children enrolled in HIV care; includes everyone in the HIV care and/or ART register)"
-"hiv_reg_new","Notification",,"Number of adults and children newly enrolled in HIV care during the year."
-"hiv_tbscr","Notification",,"Number of adults and children enrolled in HIV care who had their TB status assessed and recorded during their last visit"
-"hivtest","Notification",,"TB patients (new and re-treatment) with an HIV test result recorded in the TB register"
-"hivtest_pos","Notification",,"TB patients (new and re-treatment) recorded as HIV-positive"
-"mdr","Notification",,"Number of laboratory-confirmed cases of multidrug-resistant TB (MDR-TB) identified among all TB patients (new, previously treated, or unknown treatment history)"
-"mdr_dst_rlt","Notification",,"Drug resistance surveillance: Total number of MDR-TB patients with drug susceptibility test results for any fluoroquinolone and any second-line injectable agent"
-"mdr_new","Notification",,"Drug resistance surveillance: Among new TB patients with available drug susceptibility testing results (variable dst_rlt_new): number of patients with resistance to isoniazid and rifampicin (MDR-TB)"
-"mdr_ret","Notification",,"Drug resistance surveillance: Among patients previously treated for TB with available drug susceptibility testing results (variable dst_rlt_ret): number of patients with resistance to isoniazid and rifampicin (MDR-TB)"
-"mdr_unk","Notification",,"Drug resistance surveillance: Among patients with unknown TB treatment history with available drug susceptibility testing results (variable dst_rlt_unk): number of patients with resistance to isoniazid and rifampicin (MDR-TB)"
-"new_bact_pos","Notification",,"New bacteriologically-positive TB cases"
-"new_ep","Notification",,"New extra-pulmonary cases"
-"new_ep_f014","Notification",,"New extrapulmonary cases: females aged 0-14 years"
-"new_ep_f04","Notification",,"New extrapulmonary cases: females aged 0-4 years"
-"new_ep_f1524","Notification",,"New extrapulmonary cases: females aged 15-24 years"
-"new_ep_f15plus","Notification",,"New extrapulmonary cases: females aged 15 years and over"
-"new_ep_f2534","Notification",,"New extrapulmonary cases: females aged 25-34 years"
-"new_ep_f3544","Notification",,"New extrapulmonary cases: females aged 35-44 years"
-"new_ep_f4554","Notification",,"New extrapulmonary cases: females aged 45-54 years"
-"new_ep_f514","Notification",,"New extrapulmonary cases: females aged 5-14 years"
-"new_ep_f5564","Notification",,"New extrapulmonary cases: females aged 55-64 years"
-"new_ep_f65","Notification",,"New extrapulmonary cases: females aged 65 years and over"
-"new_ep_fu","Notification",,"New extrapulmonary cases: females age unknown"
-"new_ep_m014","Notification",,"New extrapulmonary cases: males aged 0-14 years"
-"new_ep_m04","Notification",,"New extrapulmonary cases: males aged 0-4 years"
-"new_ep_m1524","Notification",,"New extrapulmonary cases: males aged 15-24 years"
-"new_ep_m15plus","Notification",,"New extrapulmonary cases: males aged 15 years and over"
-"new_ep_m2534","Notification",,"New extrapulmonary cases: males aged 25-34 years"
-"new_ep_m3544","Notification",,"New extrapulmonary cases: males aged 35-44 years"
-"new_ep_m4554","Notification",,"New extrapulmonary cases: males aged 45-54 years"
-"new_ep_m514","Notification",,"New extrapulmonary cases: males aged 5-14 years"
-"new_ep_m5564","Notification",,"New extrapulmonary cases: males aged 55-64 years"
-"new_ep_m65","Notification",,"New extrapulmonary cases: males aged 65 years and over"
-"new_ep_mu","Notification",,"New extrapulmonary cases: males age unknown"
-"new_ep_sexunk014","Notification",,"New extrapulmonary cases: sex unknown, aged 0-14 years"
-"new_ep_sexunk04","Notification",,"New extrapulmonary cases: sex unknown, aged 0-4 years"
-"new_ep_sexunk15plus","Notification",,"New extrapulmonary cases: sex unknown, aged 15 years and over"
-"new_ep_sexunk514","Notification",,"New extrapulmonary cases: sex unknown, aged 5-14 years"
-"new_ep_sexunkageunk","Notification",,"New extrapulmonary cases: sex unknown, age unknown"
-"new_foreign","Notification",,"New and re-treatment TB cases among foreign-born individuals"
-"new_labconf","Notification",,"New pulmonary laboratory-confirmed cases. Laboratory-confirmed includes all cases confirmed by smear and/or culture, or by any other laboratory methods"
-"new_oth","Notification",,"Other new cases"
-"new_sn","Notification",,"New pulmonary smear-negative cases"
-"new_sn_f014","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females aged 0-14 years"
-"new_sn_f04","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females aged 0-4 years"
-"new_sn_f1524","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females aged 15-24 years"
-"new_sn_f15plus","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females aged 15 years and over"
-"new_sn_f2534","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females aged 25-34 years"
-"new_sn_f3544","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females aged 35-44 years"
-"new_sn_f4554","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females aged 45-54 years"
-"new_sn_f514","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females aged 5-14 years"
-"new_sn_f5564","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females aged 55-64 years"
-"new_sn_f65","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females aged 65 years and over"
-"new_sn_fu","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: females age unknown"
-"new_sn_m014","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males aged 0-14 years"
-"new_sn_m04","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males aged 0-4 years"
-"new_sn_m1524","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males aged 15-24 years"
-"new_sn_m15plus","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males aged 15 years and above"
-"new_sn_m2534","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males aged 25-34 years"
-"new_sn_m3544","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males aged 35-44 years"
-"new_sn_m4554","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males aged 45-54 years"
-"new_sn_m514","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males aged 5-14 years"
-"new_sn_m5564","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males aged 55-64 years"
-"new_sn_m65","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males aged 65 years and over"
-"new_sn_mu","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: males age unknown"
-"new_sn_sexunk014","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: sex unknown, aged 0-14 years"
-"new_sn_sexunk04","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: sex unknown, aged 0-4 years"
-"new_sn_sexunk15plus","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: sex unknown, aged 15 years and over"
-"new_sn_sexunk514","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: sex unknown, aged 5-14 years"
-"new_sn_sexunkageunk","Notification",,"New pulmonary smear negative/smear unknown/smear not done cases: sex unknown, age unknown"
-"new_sp","Notification",,"New pulmonary smear-positive cases"
-"new_sp_f014","Notification",,"New pulmonary smear positive cases: females aged 0-14 years"
-"new_sp_f04","Notification",,"New pulmonary smear positive cases: females aged 0-4 years"
-"new_sp_f1524","Notification",,"New pulmonary smear positive cases: females aged 15-24 years"
-"new_sp_f2534","Notification",,"New pulmonary smear positive cases: females aged 25-34 years"
-"new_sp_f3544","Notification",,"New pulmonary smear positive cases: females aged 35-44 years"
-"new_sp_f4554","Notification",,"New pulmonary smear positive cases: females aged 45-54 years"
-"new_sp_f514","Notification",,"New pulmonary smear positive cases: females aged 5-14 years"
-"new_sp_f5564","Notification",,"New pulmonary smear positive cases: females aged 55-64 years"
-"new_sp_f65","Notification",,"New pulmonary smear positive cases: females aged 65 and over"
-"new_sp_fu","Notification",,"New pulmonary smear positive cases: females age unknown"
-"new_sp_m014","Notification",,"New pulmonary smear positive cases: males aged 0-14 years"
-"new_sp_m04","Notification",,"New pulmonary smear positive cases: males aged 0-4 years"
-"new_sp_m1524","Notification",,"New pulmonary smear positive cases: males aged 15-24 years"
-"new_sp_m2534","Notification",,"New pulmonary smear positive cases: males aged 25-34 years"
-"new_sp_m3544","Notification",,"New pulmonary smear positive cases: males aged 35-44 years"
-"new_sp_m4554","Notification",,"New pulmonary smear positive cases: males aged 45-54 years"
-"new_sp_m514","Notification",,"New pulmonary smear positive cases: males aged 5-14 years"
-"new_sp_m5564","Notification",,"New pulmonary smear positive cases: males aged 55-64 years"
-"new_sp_m65","Notification",,"New pulmonary smear positive cases: males aged 65 years and over"
-"new_sp_mu","Notification",,"New pulmonary smear positive cases: males age unknown"
-"new_sspct","Notification",,"People with signs and symptoms suggestive of pulmonary TB screened for TB"
-"new_su","Notification",,"New pulmonary smear unknown/not done cases"
-"new_tbdeaths","Notification",,"TB deaths registered by the vital registration system following the ICD-10 codes (or ICD-9) codes for TB"
-"newret_oth","Notification",,"Other cases not included in new and re-treatment case numbers"
-"ret_oth","Notification",,"Other re-treatment cases"
-"ret_rel","Notification",,"Relapse cases"
-"ret_tad","Notification",,"Treatment after default cases"
-"ret_taf","Notification",,"Treatment after failure cases"
-"tot_newrel","Notification",,"Total new and relapse cases"
-"unconf_mdr_tx","Notification",,"Number of MDR-TB (not laboratory-confirmed) patients who started treatment for MDR-TB"
-"xdr","Notification",,"Drug resistance surveillance: Among MDR-TB patients with drug susceptibility test results for any fluoroquinolone (FQ) and any second-line injectable agent (2LI) (variable mdr_dst_rlt): number with any resistance to both FQ and 2LI (i.e. XDR-TB)"
-"c_new_snep_tsr","Outcomes",,"Treatment success rate for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done cases, percent"
-"c_new_sp_tsr","Outcomes",,"Treatment success rate for new pulmonary smear-positive (and/or culture-positive) cases, percent"
-"c_ret_tsr","Outcomes",,"Treatment success rate for re-treatment cases, percent"
-"hiv_new_snep_cmplt","Outcomes",,"Outcomes for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done HIV-positive TB cases: completed"
-"hiv_new_snep_coh","Outcomes",,"Outcomes for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done HIV-positive TB cases: cohort size"
-"hiv_new_snep_def","Outcomes",,"Outcomes for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done HIV-positive TB cases: defaulted"
-"hiv_new_snep_died","Outcomes",,"Outcomes for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done HIV-positive TB cases: died"
-"hiv_new_snep_fail","Outcomes",,"Outcomes for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done HIV-positive TB cases: failed"
-"hiv_new_sp_cmplt","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) HIV-positive TB cases: completed"
-"hiv_new_sp_coh","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) HIV-positive TB cases: cohort size"
-"hiv_new_sp_cur","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) HIV-positive TB cases: cured"
-"hiv_new_sp_def","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) HIV-positive TB cases: defaulted"
-"hiv_new_sp_died","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) HIV-positive TB cases: died"
-"hiv_new_sp_fail","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) HIV-positive TB cases: failed"
-"hiv_ret_cmplt","Outcomes",,"Outcomes for re-treatment HIV-positive TB cases: completed"
-"hiv_ret_coh","Outcomes",,"Outcomes for re-treatment HIV-positive TB cases: cohort size"
-"hiv_ret_cur","Outcomes",,"Outcomes for re-treatment HIV-positive TB cases: cured"
-"hiv_ret_def","Outcomes",,"Outcomes for re-treatment HIV-positive TB cases: defaulted"
-"hiv_ret_died","Outcomes",,"Outcomes for re-treatment HIV-positive TB cases: died"
-"hiv_ret_fail","Outcomes",,"Outcomes for re-treatment HIV-positive TB cases: failed"
-"mdr_cmplt","Outcomes",,"Outcomes for MDR-TB cases: number completed treatment"
-"mdr_coh","Outcomes",,"Outcomes for MDR-TB cases: cohort size"
-"mdr_cur","Outcomes",,"Outcomes for MDR-TB cases: number cured"
-"mdr_def","Outcomes",,"Outcomes for MDR-TB cases: number whose treatment was interrupted (defaulted)"
-"mdr_died","Outcomes",,"Outcomes for MDR-TB cases: number died"
-"mdr_fail","Outcomes",,"Outcomes for MDR-TB cases: number whose treatment failed"
-"new_snep_cmplt","Outcomes",,"Outcomes for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done cases: completed"
-"new_snep_coh","Outcomes",,"Outcomes for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done cases: cohort size"
-"new_snep_def","Outcomes",,"Outcomes for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done cases: defauled"
-"new_snep_died","Outcomes",,"Outcomes for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done cases: died"
-"new_snep_fail","Outcomes",,"Outcomes for new pulmonary smear-negative/extrapulmonary/smear unknown/smear not done cases: failed"
-"new_sp_cmplt","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) cases: completed"
-"new_sp_coh","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) cases: cohort size"
-"new_sp_cur","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) cases: cured"
-"new_sp_def","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) cases: defaulted"
-"new_sp_died","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) cases: died"
-"new_sp_fail","Outcomes",,"Outcomes for new pulmonary smear-positive (and/or culture-positive) cases: failed"
-"pulm_tb_rep_meth","Outcomes",,"Method used to report treatment outcomes of pulmonary cases"
-"ret_cmplt","Outcomes",,"Outcomes for re-treatment cases: completed"
-"ret_coh","Outcomes",,"Outcomes for re-treatment cases: cohort size"
-"ret_cur","Outcomes",,"Outcomes for re-treatment cases: cured"
-"ret_def","Outcomes",,"Outcomes for re-treatment cases: defaulted"
-"ret_died","Outcomes",,"Outcomes for re-treatment cases: died"
-"ret_fail","Outcomes",,"Outcomes for re-treatment cases: failed"
-"xdr_cmplt","Outcomes",,"Outcomes for XDR-TB cases: number completed treatment"
-"xdr_coh","Outcomes",,"Outcomes for XDR-TB cases: cohort size"
-"xdr_cur","Outcomes",,"Outcomes for XDR-TB cases: number cured"
-"xdr_def","Outcomes",,"Outcomes for XDR-TB cases: number whose treatment was interrupted (defaulted)"
-"xdr_died","Outcomes",,"Outcomes for XDR-TB cases: number died"
-"xdr_fail","Outcomes",,"Outcomes for XDR-TB cases: number whose treatment failed"
-"caseb_err_nat","Strategy","0=No; 40=Yes; all patients; 41=Yes; MDR-TB patients only","Did the National Treatment Programme keep (or have access to) an electronic case-based database for TB patients on treatment at national level"
-"collab_private_lab","Strategy","0=No; 1=yes","Were any non-NTP laboratories in the private sector (including NGOs) collaborating with the NTP?"
-"collab_public_lab","Strategy","0=No; 1=yes","Were any non-NTP laboratories in the public sector collaborating with the NTP?"
-"dst_in_guide","Strategy","0=No; 1=yes","Is conventional Drug Susceptibility Testing (DST) (solid or liquid methods) included in TB control guidelines for diagnosis?"
-"dx_alg_tbhiv_in_guide","Strategy","0=No; 1=yes","Is an algorithm for the diagnosis of TB in HIV-positive people, which includes use of all investigations at the same time including CXR, culture (when available) and no use of an antibiotic trial included in TB control guidelines for diagnosis?"
-"eol_care","Strategy","0=No; 1=yes","Is there a component in the TB programme that provides palliative and end-of-life care to patients who have failed MDR-TB treatment or who have life-threatening sequelae of disease?"
-"free_dx","Strategy","10=Yes (all suspects);11=Yes (if TB is confirmed);12=Yes (for smear-positive TB);13=Yes (for certain income groups);14=Yes (other criteria);0=No","Is diagnosis provided through the TB National Treatment Programme free-of-charge?"
-"free_fld_ntp","Strategy","0=No; 1=yes;3=Don't know","Were TB drugs provided free-of-charge to all TB patients treated with first-line drugs under the National Treatment Programme?"
-"hcw_tb_infected","Strategy",,"Number of health-care workers who had TB"
-"hcw_tot","Strategy",,"Total number of health-care workers who were working in the country in the public and private sector"
-"lab_cul_eqa_f","Strategy",,"Number of culture laboratories for which External Quality Assessment (EQA) was carried out"
-"lab_cul_eqa_pass","Strategy",,"Number of culture laboratories which demonstrated acceptable performance"
-"lab_cul_f","Strategy",,"Number of laboratories providing TB diagnostic services using culture"
-"lab_dst_eqa_f","Strategy",,"Number of drug susceptibility testing laboratories for which External Quality Assessment (EQA) was carried out"
-"lab_dst_eqa_pass","Strategy",,"Number of drug susceptibility testing laboratories which demonstrated acceptable performance"
-"lab_dst_f","Strategy",,"Number of laboratories providing TB diagnostic services using drug susceptibility testing"
-"lab_lpa_eqa_f","Strategy",,"Number of Line Probe Assay (LPA) rifampicin laboratories for which External Quality Assessment (EQA) was carried out"
-"lab_lpa_eqa_pass","Strategy",,"Number of Line Probe Assay (LPA) rifampicin laboratories which demonstrated acceptable performance"
-"lab_lpa_f","Strategy",,"Number of laboratories providing TB diagnostic services using Line Probe Assay (LPA) rifampicin"
-"lab_sm_eqa_f","Strategy",,"Number of smear microscopy laboratories for which External Quality Assessment (EQA) was carried out"
-"lab_sm_eqa_pass","Strategy",,"Number of smear microscopy laboratories which demonstrated acceptable performance"
-"lab_sm_f","Strategy",,"Number of laboratories providing TB diagnostic services using smear microscopy"
-"lab_sm_led","Strategy",,"Number of laboratories providing TB diagnostic services using LED microscopes for smear microscopy"
-"lab_xpert","Strategy",,"Number of laboratories providing TB diagnostic services using xpert MTB/RIF"
-"lab_xpert_eqa","Strategy",,"Number of laboratories providing TB diagnostic services using xpert MTB/RIF for which External Quality Assessment (EQA) was carried out"
-"lc_rst_in_guide","Strategy","0=No; 1=yes","Is liquid culture and rapid speciation test for Mycobacterium Tuberculosis included in TB control guidelines for diagnosis?"
-"lpa_in_guide","Strategy","0=No; 1=yes","Is line-probe assay for detecting resistance to rifampicin and isonaizid included in TB control guidelines for diagnosis?"
-"nrl","Strategy","0=No; 1=yes","Was there a national reference laboratory or laboratories (NRL)?"
-"nrl_srl_link","Strategy","0=No; 1=yes","Has a formal link been established between the National Reference Laboratory and a partner Supranational Reference Laboratory?"
-"priv_new_dx","Strategy",,"Number of new cases of TB diagnosed according to National Treatment Programme (NTP) guidelines by private providers"
-"pub_new_dx","Strategy",,"Number of new cases of TB diagnosed according to National Treatment Programme (NTP) guidelines by non-NTP public providers"
-"r_rgmn_new_initcont","Strategy","0=No; 1=yes","Is the 6-month drug regimen with rifampicin throughout treatment (in the intensive phase and continuation phases) used for new TB patients?"
-"sldst_avail_incntry","Strategy","0=No; 1=yes","Was second-line drug susceptibility testing available within the country for TB National Treatment Programme patients?"
-"sldst_avail_outcntry","Strategy","0=No; 1=yes","Was second-line drug susceptibility testing available outside the country for TB National Treatment Programme patients?"
-"tbhiv_sentin_cil","Strategy",,"Lower limit (95% confidence interval) of prevalence (%) of HIV in TB patients estimated using sentinel sites"
-"tbhiv_sentin_ciu","Strategy",,"Upper limit (95% confidence interval) of prevalence (%) of HIV in TB patients estimated using sentinel sites"
-"tbhiv_sentin_prev","Strategy",,"Prevalence (%) of HIV in TB patients estimated using sentinel sites"
-"tbhiv_sentin_yr","Strategy",,"Year in which prevalence of HIV in TB patients was estimated using sentinel sites"
-"tbhiv_surv_cil","Strategy",,"Lower limit (95% confidence interval) of prevalence (%) of HIV in TB patients estimated using nationwide representative surveys"
-"tbhiv_surv_ciu","Strategy",,"Upper limit (95% confidence interval) of prevalence (%) of HIV in TB patients estimated using nationwide representative surveys"
-"tbhiv_surv_prev","Strategy",,"Prevalence (%) of HIV in TB patients estimated using nationwide representative
-surveys"
-"tbhiv_surv_yr","Strategy",,"Year in which prevalence of HIV in TB patients was estimated using nationwide representative surveys"
-"tbhiv_surveil","Strategy","0=No; 1=yes","Is there a national surveillance system to measure the prevalence of HIV in TB patients?"
-"xpert_in_guide_MDR","Strategy","0=No; 1=yes","Is WHO policy guidance on the inclusion of Xpert MTB/RIF assay in an algorithm for the diagnosis of drug-resistant TB among persons at risk incorporated into national guidelines?"
-"xpert_in_guide_TBHIV","Strategy","0=No; 1=yes","Is WHO policy guidance on the inclusion of Xpert MTB/RIF assay in an algorithm for the diagnosis of TB in persons at risk of HIV-associated TB incorporated into national guidelines?"
diff --git a/Chapter 13 - csv/csv_dictwriter.py b/Chapter 13 - csv/csv_dictwriter.py
deleted file mode 100644
index a5547fe..0000000
--- a/Chapter 13 - csv/csv_dictwriter.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import csv
-
-def csv_dict_writer(path, fieldnames, data):
- """
- Writes a CSV file using DictWriter
- """
- with open(path, "w", newline='') as out_file:
- writer = csv.DictWriter(out_file, delimiter=',', fieldnames=fieldnames)
- writer.writeheader()
- for row in data:
- writer.writerow(row)
-
-if __name__ == "__main__":
- data = ["first_name,last_name,city".split(","),
- "Tyrese,Hirthe,Strackeport".split(","),
- "Jules,Dicki,Lake Nickolasville".split(","),
- "Dedric,Medhurst,Stiedemannberg".split(",")
- ]
- my_list = []
- fieldnames = data[0]
- for values in data[1:]:
- inner_dict = dict(zip(fieldnames, values))
- my_list.append(inner_dict)
-
- path = "dict_output.csv"
- csv_dict_writer(path, fieldnames, my_list)
\ No newline at end of file
diff --git a/Chapter 13 - csv/csv_reader.py b/Chapter 13 - csv/csv_reader.py
deleted file mode 100644
index 1fa9813..0000000
--- a/Chapter 13 - csv/csv_reader.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import csv
-
-def csv_reader(file_obj):
- """
- Read a csv file
- """
- reader = csv.reader(file_obj)
- for row in reader:
- print(" ".join(row))
-
-
-if __name__ == "__main__":
- csv_path = "TB_data_dictionary_2014-02-26.csv"
- with open(csv_path, "r") as f_obj:
- csv_reader(f_obj)
\ No newline at end of file
diff --git a/Chapter 13 - csv/csv_reader2.py b/Chapter 13 - csv/csv_reader2.py
deleted file mode 100644
index 9883a1c..0000000
--- a/Chapter 13 - csv/csv_reader2.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import csv
-
-def csv_dict_reader(file_obj):
- """
- Read a CSV file using csv.DictReader
- """
- reader = csv.DictReader(file_obj, delimiter=',')
- for line in reader:
- print(line["first_name"]),
- print(line["last_name"])
-
-if __name__ == "__main__":
- with open("data.csv") as f_obj:
- csv_dict_reader(f_obj)
\ No newline at end of file
diff --git a/Chapter 13 - csv/csv_writer.py b/Chapter 13 - csv/csv_writer.py
deleted file mode 100644
index af0baa5..0000000
--- a/Chapter 13 - csv/csv_writer.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import csv
-
-def csv_writer(data, path):
- """
- Write data to a CSV file path
- """
- with open(path, "w", newline='') as csv_file:
- writer = csv.writer(csv_file, delimiter=',')
- for line in data:
- writer.writerow(line)
-
-if __name__ == "__main__":
- data = ["first_name,last_name,city".split(","),
- "Tyrese,Hirthe,Strackeport".split(","),
- "Jules,Dicki,Lake Nickolasville".split(","),
- "Dedric,Medhurst,Stiedemannberg".split(",")
- ]
- path = "output.csv"
- csv_writer(data, path)
\ No newline at end of file
diff --git a/Chapter 13 - csv/data.csv b/Chapter 13 - csv/data.csv
deleted file mode 100644
index 2c19a16..0000000
--- a/Chapter 13 - csv/data.csv
+++ /dev/null
@@ -1,4 +0,0 @@
-first_name,last_name,address,city,state,zip_code
-Tyrese,Hirthe,1404 Turner Ville,Strackeport,NY,19106-8813
-Jules,Dicki,2410 Estella Cape Suite 061,Lake Nickolasville,ME,00621-7435
-Dedric,Medhurst,6912 Dayna Shoal,Stiedemannberg,SC,43259-2273
\ No newline at end of file
diff --git a/Chapter 14 - configparser/create_config.py b/Chapter 14 - configparser/create_config.py
deleted file mode 100644
index b7f3551..0000000
--- a/Chapter 14 - configparser/create_config.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import configparser
-
-def createConfig(path):
- """
- Create a config file
- """
- config = configparser.ConfigParser()
- config.add_section("Settings")
- config.set("Settings", "font", "Courier")
- config.set("Settings", "font_size", "10")
- config.set("Settings", "font_style", "Normal")
- config.set("Settings", "font_info",
- "You are using %(font)s at %(font_size)s pt")
-
- with open(path, "w") as config_file:
- config.write(config_file)
-
-if __name__ == "__main__":
- path = "settings.ini"
- createConfig(path)
\ No newline at end of file
diff --git a/Chapter 14 - configparser/crud_config.py b/Chapter 14 - configparser/crud_config.py
deleted file mode 100644
index f9e2d39..0000000
--- a/Chapter 14 - configparser/crud_config.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import configparser
-import os
-
-from create_config import createConfig
-
-
-def crudConfig(path):
- """
- Create, read, update, delete config
- """
- if not os.path.exists(path):
- createConfig(path)
-
- stat = os.stat(path)
- if stat.st_size == 0:
- # File is zero bytes
- raise RuntimeError('Settings file is empty')
-
- config = configparser.ConfigParser()
- config.read(path)
-
- # read some values from the config
- font = config.get("Settings", "font")
- font_size = config.get("Settings", "font_size")
-
- # change a value in the config
- config.set("Settings", "font_size", "12")
-
- # delete a value from the config
- config.remove_option("Settings", "font_style")
-
- # write changes back to the config file
- with open(path, "w") as config_file:
- config.write(config_file)
-
-if __name__ == "__main__":
- path = "settings.ini"
- crudConfig(path)
\ No newline at end of file
diff --git a/Chapter 14 - configparser/crud_config_refactored.py b/Chapter 14 - configparser/crud_config_refactored.py
deleted file mode 100644
index 80ef4d5..0000000
--- a/Chapter 14 - configparser/crud_config_refactored.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import configparser
-import os
-
-def create_config(path):
- """
- Create a config file
- """
- config = configparser.ConfigParser()
- config.add_section("Settings")
- config.set("Settings", "font", "Courier")
- config.set("Settings", "font_size", "10")
- config.set("Settings", "font_style", "Normal")
- config.set("Settings", "font_info",
- "You are using %(font)s at %(font_size)s pt")
-
- with open(path, "w") as config_file:
- config.write(config_file)
-
-
-def get_config(path):
- """
- Returns the config object
- """
- if not os.path.exists(path):
- create_config(path)
-
- config = configparser.ConfigParser()
- config.read(path)
- return config
-
-
-def get_setting(path, section, setting):
- """
- Print out a setting
- """
- config = get_config(path)
- value = config.get(section, setting)
- msg = "{section} {setting} is {value}".format(
- section=section, setting=setting, value=value)
- print(msg)
- return value
-
-
-def update_setting(path, section, setting, value):
- """
- Update a setting
- """
- config = get_config(path)
- config.set(section, setting, value)
- with open(path, "w") as config_file:
- config.write(config_file)
-
-
-def delete_setting(path, section, setting):
- """
- Delete a setting
- """
- config = get_config(path)
- config.remove_option(section, setting)
- with open(path, "w") as config_file:
- config.write(config_file)
-
-if __name__ == "__main__":
- path = "settings.ini"
- font = get_setting(path, 'Settings', 'font')
- font_size = get_setting(path, 'Settings', 'font_size')
-
- update_setting(path, "Settings", "font_size", "12")
-
- delete_setting(path, "Settings", "font_style")
\ No newline at end of file
diff --git a/Chapter 14 - configparser/interpolation.py b/Chapter 14 - configparser/interpolation.py
deleted file mode 100644
index f767a7f..0000000
--- a/Chapter 14 - configparser/interpolation.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import configparser
-import os
-
-from create_config import createConfig
-
-
-def interpolationDemo(path):
- if not os.path.exists(path):
- createConfig(path)
-
- config = configparser.ConfigParser()
- config.read(path)
-
- print(config.get("Settings", "font_info"))
-
- print(config.get("Settings", "font_info",
- vars={"font": "Arial", "font_size": "100"}))
-
-if __name__ == "__main__":
- path = "settings.ini"
- interpolationDemo(path)
\ No newline at end of file
diff --git a/Chapter 15 - logging/exception_logger.py b/Chapter 15 - logging/exception_logger.py
deleted file mode 100644
index b1009f4..0000000
--- a/Chapter 15 - logging/exception_logger.py
+++ /dev/null
@@ -1,9 +0,0 @@
-import logging
-
-logging.basicConfig(filename="sample.log", level=logging.INFO)
-log = logging.getLogger("ex")
-
-try:
- raise RuntimeError
-except RuntimeError:
- log.exception("Error!")
\ No newline at end of file
diff --git a/Chapter 15 - logging/log_multiple_modules.py b/Chapter 15 - logging/log_multiple_modules.py
deleted file mode 100644
index eaa29d4..0000000
--- a/Chapter 15 - logging/log_multiple_modules.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import logging
-import otherMod
-
-def main():
- """
- The main entry point of the application
- """
- logging.basicConfig(filename="mySnake.log", level=logging.INFO)
- logging.info("Program started")
- result = otherMod.add(7, 8)
- logging.info("Done!")
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
diff --git a/Chapter 15 - logging/log_multiple_modules2.py b/Chapter 15 - logging/log_multiple_modules2.py
deleted file mode 100644
index ebe7b21..0000000
--- a/Chapter 15 - logging/log_multiple_modules2.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import logging
-import otherMod2
-
-def main():
- """
- The main entry point of the application
- """
- logger = logging.getLogger("exampleApp")
- logger.setLevel(logging.INFO)
-
- # create the logging file handler
- fh = logging.FileHandler("new_snake.log")
-
- formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
- fh.setFormatter(formatter)
-
- # add handler to logger object
- logger.addHandler(fh)
-
- logger.info("Program started")
- result = otherMod2.add(7, 8)
- logger.info("Done!")
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
diff --git a/Chapter 15 - logging/log_with_config.py b/Chapter 15 - logging/log_with_config.py
deleted file mode 100644
index 8228096..0000000
--- a/Chapter 15 - logging/log_with_config.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# log_with_config.py
-import logging
-import logging.config
-import otherMod2
-
-def main():
- """
- Based on http://docs.python.org/howto/logging.html#configuring-logging
- """
- logging.config.fileConfig('logging.conf')
- logger = logging.getLogger("exampleApp")
-
- logger.info("Program started")
- result = otherMod2.add(7, 8)
- logger.info("Done!")
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
diff --git a/Chapter 15 - logging/log_with_config2.py b/Chapter 15 - logging/log_with_config2.py
deleted file mode 100644
index 332cdcd..0000000
--- a/Chapter 15 - logging/log_with_config2.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# log_with_config2.py
-import logging
-import logging.config
-import otherMod2
-
-def main():
- """
- Based on http://docs.python.org/howto/logging.html#configuring-logging
- """
- dictLogConfig = {
- "version":1,
- "handlers":{
- "fileHandler":{
- "class":"logging.FileHandler",
- "formatter":"myFormatter",
- "filename":"config2.log"
- }
- },
- "loggers":{
- "exampleApp":{
- "handlers":["fileHandler"],
- "level":"INFO",
- }
- },
- "formatters":{
- "myFormatter":{
- "format":"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
- }
- }
- }
-
- logging.config.dictConfig(dictLogConfig)
-
- logger = logging.getLogger("exampleApp")
-
- logger.info("Program started")
- result = otherMod2.add(7, 8)
- logger.info("Done!")
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
diff --git a/Chapter 15 - logging/logging.conf b/Chapter 15 - logging/logging.conf
deleted file mode 100644
index a855fd0..0000000
--- a/Chapter 15 - logging/logging.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-[loggers]
-keys=root,exampleApp
-
-[handlers]
-keys=fileHandler, consoleHandler
-
-[formatters]
-keys=myFormatter
-
-[logger_root]
-level=CRITICAL
-handlers=consoleHandler
-
-[logger_exampleApp]
-level=INFO
-handlers=fileHandler
-qualname=exampleApp
-
-[handler_consoleHandler]
-class=StreamHandler
-level=DEBUG
-formatter=myFormatter
-args=(sys.stdout,)
-
-[handler_fileHandler]
-class=FileHandler
-formatter=myFormatter
-args=("config.log",)
-
-[formatter_myFormatter]
-format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
-datefmt=
\ No newline at end of file
diff --git a/Chapter 15 - logging/otherMod.py b/Chapter 15 - logging/otherMod.py
deleted file mode 100644
index 16fa316..0000000
--- a/Chapter 15 - logging/otherMod.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# otherMod.py
-import logging
-
-def add(x, y):
- """"""
- logging.info("added %s and %s to get %s" % (x, y, x+y))
- return x+y
\ No newline at end of file
diff --git a/Chapter 15 - logging/otherMod2.py b/Chapter 15 - logging/otherMod2.py
deleted file mode 100644
index 67a3f5f..0000000
--- a/Chapter 15 - logging/otherMod2.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# otherMod2.py
-import logging
-
-module_logger = logging.getLogger("exampleApp.otherMod2")
-
-def add(x, y):
- """"""
- logger = logging.getLogger("exampleApp.otherMod2.add")
- logger.info("added %s and %s to get %s" % (x, y, x+y))
- return x+y
\ No newline at end of file
diff --git a/Chapter 15 - logging/simple_logger.py b/Chapter 15 - logging/simple_logger.py
deleted file mode 100644
index 47ce3af..0000000
--- a/Chapter 15 - logging/simple_logger.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import logging
-
-# add filemode="w" to overwrite
-logging.basicConfig(filename="sample.log", level=logging.INFO)
-
-logging.debug("This is a debug message")
-logging.info("Informational message")
-logging.error("An error has happened!")
\ No newline at end of file
diff --git a/Chapter 16 - os/readme.txt b/Chapter 16 - os/readme.txt
deleted file mode 100644
index 6fb69d5..0000000
--- a/Chapter 16 - os/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-This chapter was skipped because it just demonstrates different ways of importing modules. The examples in chapter 16 should be practiced in IDLE or a Python editor of your choice.
\ No newline at end of file
diff --git a/Chapter 17 - smtplib and email/email.ini b/Chapter 17 - smtplib and email/email.ini
deleted file mode 100644
index 3fdee9e..0000000
--- a/Chapter 17 - smtplib and email/email.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[smtp]
-server = some.server.com
-from_addr = python@mydomain.com
\ No newline at end of file
diff --git a/Chapter 17 - smtplib and email/send_email.py b/Chapter 17 - smtplib and email/send_email.py
deleted file mode 100644
index d2d1dcd..0000000
--- a/Chapter 17 - smtplib and email/send_email.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import smtplib
-
-HOST = "mySMTP.server.com"
-SUBJECT = "Test email from Python"
-TO = "mike@someAddress.org"
-FROM = "python@mydomain.com"
-text = "Python 3.4 rules them all!"
-
-BODY = "\r\n".join((
- "From: %s" % FROM,
- "To: %s" % TO,
- "Subject: %s" % SUBJECT ,
- "",
- text
- ))
-
-server = smtplib.SMTP(HOST)
-server.sendmail(FROM, [TO], BODY)
-server.quit()
\ No newline at end of file
diff --git a/Chapter 17 - smtplib and email/send_email_attachment.py b/Chapter 17 - smtplib and email/send_email_attachment.py
deleted file mode 100644
index 773033b..0000000
--- a/Chapter 17 - smtplib and email/send_email_attachment.py
+++ /dev/null
@@ -1,76 +0,0 @@
-import os
-import smtplib
-import sys
-
-from configparser import ConfigParser
-from email import encoders
-from email.mime.text import MIMEText
-from email.mime.base import MIMEBase
-from email.mime.multipart import MIMEMultipart
-from email.utils import formatdate
-
-#----------------------------------------------------------------------
-def send_email_with_attachment(subject, body_text, to_emails,
- cc_emails, bcc_emails, file_to_attach):
- """
- Send an email with an attachment
- """
- base_path = os.path.dirname(os.path.abspath(__file__))
- config_path = os.path.join(base_path, "email.ini")
- header = 'Content-Disposition', 'attachment; filename="%s"' % file_to_attach
-
- # get the config
- if os.path.exists(config_path):
- cfg = ConfigParser()
- cfg.read(config_path)
- else:
- print("Config not found! Exiting!")
- sys.exit(1)
-
- # extract server and from_addr from config
- host = cfg.get("smtp", "server")
- from_addr = cfg.get("smtp", "from_addr")
-
- # create the message
- msg = MIMEMultipart()
- msg["From"] = from_addr
- msg["Subject"] = subject
- msg["Date"] = formatdate(localtime=True)
- if body_text:
- msg.attach( MIMEText(body_text) )
-
- msg["To"] = ', '.join(to_emails)
- msg["cc"] = ', '.join(cc_emails)
-
- attachment = MIMEBase('application', "octet-stream")
- try:
- with open(file_to_attach, "rb") as fh:
- data = fh.read()
- attachment.set_payload( data )
- encoders.encode_base64(attachment)
- attachment.add_header(*header)
- msg.attach(attachment)
- except IOError:
- msg = "Error opening attachment file %s" % file_to_attach
- print(msg)
- sys.exit(1)
-
- emails = to_emails + cc_emails
-
- server = smtplib.SMTP(host)
- server.sendmail(from_addr, emails, msg.as_string())
- server.quit()
-
-if __name__ == "__main__":
- emails = ["mike@someAddress.org", "nedry@jp.net"]
- cc_emails = ["someone@gmail.com"]
- bcc_emails = ["anonymous@circe.org"]
-
- subject = "Test email with attachment from Python"
- body_text = "This email contains an attachment!"
- path = "/path/to/some/file"
- send_email_with_attachment(subject, body_text, emails,
- cc_emails, bcc_emails, path)
-
-
-
diff --git a/Chapter 17 - smtplib and email/send_email_function.py b/Chapter 17 - smtplib and email/send_email_function.py
deleted file mode 100644
index 670683a..0000000
--- a/Chapter 17 - smtplib and email/send_email_function.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import smtplib
-
-def send_email(host, subject, to_addr, from_addr, body_text):
- """
- Send an email
- """
- BODY = "\r\n".join((
- "From: %s" % from_addr,
- "To: %s" % to_addr,
- "Subject: %s" % subject ,
- "",
- body_text
- ))
- server = smtplib.SMTP(host)
- server.sendmail(from_addr, [to_addr], BODY)
- server.quit()
-
-if __name__ == "__main__":
- host = "mySMTP.server.com"
- subject = "Test email from Python"
- to_addr = "mike@someAddress.org"
- from_addr = "python@mydomain.com"
- body_text = "Python rules them all!"
- send_email(host, subject, to_addr, from_addr, body_text)
\ No newline at end of file
diff --git a/Chapter 17 - smtplib and email/send_multiple_emails.py b/Chapter 17 - smtplib and email/send_multiple_emails.py
deleted file mode 100644
index a603a9f..0000000
--- a/Chapter 17 - smtplib and email/send_multiple_emails.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import os
-import smtplib
-import sys
-
-from configparser import ConfigParser
-
-def send_email(subject, body_text, emails):
- """
- Send an email
- """
- base_path = os.path.dirname(os.path.abspath(__file__))
- config_path = os.path.join(base_path, "email.ini")
-
- if os.path.exists(config_path):
- cfg = ConfigParser()
- cfg.read(config_path)
- else:
- print("Config not found! Exiting!")
- sys.exit(1)
-
- host = cfg.get("smtp", "server")
- from_addr = cfg.get("smtp", "from_addr")
-
- BODY = "\r\n".join((
- "From: %s" % from_addr,
- "To: %s" % ', '.join(emails),
- "Subject: %s" % subject ,
- "",
- body_text
- ))
- server = smtplib.SMTP(host)
- server.sendmail(from_addr, emails, BODY)
- server.quit()
-
-if __name__ == "__main__":
- emails = ["mike@someAddress.org", "someone@gmail.com"]
- subject = "Test email from Python"
- body_text = "Python rules them all!"
- send_email(subject, body_text, emails)
\ No newline at end of file
diff --git a/Chapter 17 - smtplib and email/send_to_cc_bcc.py b/Chapter 17 - smtplib and email/send_to_cc_bcc.py
deleted file mode 100644
index 99e29b1..0000000
--- a/Chapter 17 - smtplib and email/send_to_cc_bcc.py
+++ /dev/null
@@ -1,45 +0,0 @@
-import os
-import smtplib
-import sys
-
-from configparser import ConfigParser
-
-def send_email(subject, body_text, to_emails, cc_emails, bcc_emails):
- """
- Send an email
- """
- base_path = os.path.dirname(os.path.abspath(__file__))
- config_path = os.path.join(base_path, "email.ini")
-
- if os.path.exists(config_path):
- cfg = ConfigParser()
- cfg.read(config_path)
- else:
- print("Config not found! Exiting!")
- sys.exit(1)
-
- host = cfg.get("smtp", "server")
- from_addr = cfg.get("smtp", "from_addr")
-
- BODY = "\r\n".join((
- "From: %s" % from_addr,
- "To: %s" % ', '.join(to_emails),
- "CC: %s" % ', '.join(cc_emails),
- "BCC: %s" % ', '.join(bcc_emails),
- "Subject: %s" % subject ,
- "",
- body_text
- ))
- emails = to_emails + cc_emails + bcc_emails
-
- server = smtplib.SMTP(host)
- server.sendmail(from_addr, emails, BODY)
- server.quit()
-
-if __name__ == "__main__":
- emails = ["mike@somewhere.org"]
- cc_emails = ["someone@gmail.com"]
- bcc_emails = ["schmuck@newtel.net"]
- subject = "Test email from Python"
- body_text = "Python rules them all!"
- send_email(subject, body_text, emails, cc_emails, bcc_emails)
\ No newline at end of file
diff --git a/Chapter 17 - smtplib and email/smtp_config.py b/Chapter 17 - smtplib and email/smtp_config.py
deleted file mode 100644
index d0f40be..0000000
--- a/Chapter 17 - smtplib and email/smtp_config.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import os
-import smtplib
-import sys
-
-from configparser import ConfigParser
-
-def send_email(subject, to_addr, body_text):
- """
- Send an email
- """
- base_path = os.path.dirname(os.path.abspath(__file__))
- config_path = os.path.join(base_path, "email.ini")
-
- if os.path.exists(config_path):
- cfg = ConfigParser()
- cfg.read(config_path)
- else:
- print("Config not found! Exiting!")
- sys.exit(1)
-
- host = cfg.get("smtp", "server")
- from_addr = cfg.get("smtp", "from_addr")
- BODY = "\r\n".join((
- "From: %s" % from_addr,
- "To: %s" % to_addr,
- "Subject: %s" % subject ,
- "",
- body_text
- ))
- server = smtplib.SMTP(host)
- server.sendmail(from_addr, [to_addr], BODY)
- server.quit()
-
-if __name__ == "__main__":
- subject = "Test email from Python"
- to_addr = "mike@someAddress.org"
- body_text = "Python rules them all!"
- send_email(subject, to_addr, body_text)
\ No newline at end of file
diff --git a/Chapter 18 - sqlite/basic_queries.py b/Chapter 18 - sqlite/basic_queries.py
deleted file mode 100644
index f793530..0000000
--- a/Chapter 18 - sqlite/basic_queries.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import sqlite3
-
-conn = sqlite3.connect("mydatabase.db")
-#conn.row_factory = sqlite3.Row
-cursor = conn.cursor()
-
-sql = "SELECT * FROM albums WHERE artist=?"
-cursor.execute(sql, [("Red")])
-print cursor.fetchall() # or use fetchone()
-
-print "\nHere's a listing of all the records in the table:\n"
-for row in cursor.execute("SELECT rowid, * FROM albums ORDER BY artist"):
- print row
-
-print "\nResults from a LIKE query:\n"
-sql = """
-SELECT * FROM albums
-WHERE title LIKE 'The%'"""
-cursor.execute(sql)
-print cursor.fetchall()
\ No newline at end of file
diff --git a/Chapter 18 - sqlite/create_database.py b/Chapter 18 - sqlite/create_database.py
deleted file mode 100644
index 33883be..0000000
--- a/Chapter 18 - sqlite/create_database.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import sqlite3
-
-conn = sqlite3.connect("mydatabase.db") # or use :memory: to put it in RAM
-
-cursor = conn.cursor()
-
-# create a table
-cursor.execute("""CREATE TABLE albums
- (title text, artist text, release_date text,
- publisher text, media_type text)
- """)
-
-# insert some data
-cursor.execute("""INSERT INTO albums
- VALUES ('Glow', 'Andy Hunter', '7/24/2012',
- 'Xplore Records', 'MP3')"""
- )
-
-# save data to database
-conn.commit()
-
-# insert multiple records using the more secure "?" method
-albums = [('Exodus', 'Andy Hunter', '7/9/2002', 'Sparrow Records', 'CD'),
- ('Until We Have Faces', 'Red', '2/1/2011', 'Essential Records', 'CD'),
- ('The End is Where We Begin', 'Thousand Foot Krutch', '4/17/2012', 'TFKmusic', 'CD'),
- ('The Good Life', 'Trip Lee', '4/10/2012', 'Reach Records', 'CD')]
-cursor.executemany("INSERT INTO albums VALUES (?,?,?,?,?)", albums)
-conn.commit()
\ No newline at end of file
diff --git a/Chapter 18 - sqlite/delete_record.py b/Chapter 18 - sqlite/delete_record.py
deleted file mode 100644
index cd63978..0000000
--- a/Chapter 18 - sqlite/delete_record.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import sqlite3
-
-conn = sqlite3.connect("mydatabase.db")
-cursor = conn.cursor()
-
-sql = """
-DELETE FROM albums
-WHERE artist = 'John Doe'
-"""
-cursor.execute(sql)
-conn.commit()
\ No newline at end of file
diff --git a/Chapter 18 - sqlite/update_database.py b/Chapter 18 - sqlite/update_database.py
deleted file mode 100644
index e368efe..0000000
--- a/Chapter 18 - sqlite/update_database.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import sqlite3
-
-conn = sqlite3.connect("mydatabase.db")
-cursor = conn.cursor()
-
-sql = """
-UPDATE albums
-SET artist = 'John Doe'
-WHERE artist = 'Andy Hunter'
-"""
-
-cursor.execute(sql)
-conn.commit()
\ No newline at end of file
diff --git a/Chapter 19 - subprocess/communicate_example.py b/Chapter 19 - subprocess/communicate_example.py
deleted file mode 100644
index bd8a90a..0000000
--- a/Chapter 19 - subprocess/communicate_example.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import subprocess
-
-args = ["ping", "www.yahoo.com"]
-process = subprocess.Popen(args, stdout=subprocess.PIPE)
-
-data = process.communicate()
-for line in data:
- print(line)
\ No newline at end of file
diff --git a/Chapter 19 - subprocess/readme.txt b/Chapter 19 - subprocess/readme.txt
deleted file mode 100644
index 4b1a328..0000000
--- a/Chapter 19 - subprocess/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-Most of the examples in this chapter should be run in IDLE so you can better understand the subprocess module
\ No newline at end of file
diff --git a/Chapter 2 - Strings/creating_strings.py b/Chapter 2 - Strings/creating_strings.py
deleted file mode 100644
index ef49c69..0000000
--- a/Chapter 2 - Strings/creating_strings.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# The following shows different methods of creating a string
-my_string = "Welcome to Python!"
-another_string = 'The bright red fox jumped the fence.'
-a_long_string = '''This is a
-multi-line string. It covers more than
-one line'''
-
-# this set of strings shows how to mix single and double-quotes
-my_string = "I'm a Python programmer!"
-otherString = 'The word "python" usually refers to a snake'
-tripleString = """Here's another way to embed "quotes" in a string"""
-
-# cast an integer to a string using Python's str() class
-my_number = 123
-my_string = str(my_number)
\ No newline at end of file
diff --git a/Chapter 2 - Strings/string_concatenation.py b/Chapter 2 - Strings/string_concatenation.py
deleted file mode 100644
index b080618..0000000
--- a/Chapter 2 - Strings/string_concatenation.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# the following demonstrates how to join two strings
-string_one = "My dog ate "
-string_two = "my homework!"
-string_three = string_one + string_two
\ No newline at end of file
diff --git a/Chapter 2 - Strings/string_methods.py b/Chapter 2 - Strings/string_methods.py
deleted file mode 100644
index 4eced9f..0000000
--- a/Chapter 2 - Strings/string_methods.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# string methods
-my_string = "This is a string!"
-my_string.upper() # or print(my_string.upper())
-"This is a string!".upper()
-
-# get a list of string methods
-dir(my_string)
-
-# get help
-help(my_string.capitalize)
diff --git a/Chapter 2 - Strings/string_slicing.py b/Chapter 2 - Strings/string_slicing.py
deleted file mode 100644
index 9ef51df..0000000
--- a/Chapter 2 - Strings/string_slicing.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# string slicing
-my_string = "I like Python!"
-my_string[0:1]
-my_string[:1]
-my_string[0:12]
-my_string[0:13]
-my_string[0:14]
-my_string[0:-5]
-my_string[:]
-my_string[2:]
-
-# string indexing
-print(my_string[0]) # prints the first character of the string
\ No newline at end of file
diff --git a/Chapter 2 - Strings/string_substitution.py b/Chapter 2 - Strings/string_substitution.py
deleted file mode 100644
index 5c47187..0000000
--- a/Chapter 2 - Strings/string_substitution.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# string substitution
-
-# the old way
-my_string = "I like %s" % "Python"
-my_string
-
-var = "cookies"
-newString = "I like %s" % var
-newString
-
-
-another_string = "I like %s and %s" % ("Python", var)
-another_string
-
-# this will cause a TypeError
-another_string = "I like %s and %s" % "Python"
-
-# string formatting
-my_string = "%i + %i = %i" % (1,2,3)
-my_string
-
-float_string = "%f" % (1.23)
-float_string
-
-float_string2 = "%.2f" % (1.23)
-float_string2
-
-float_string3 = "%.2f" % (1.237)
-float_string3
-
-# passing bad data raises a TypeError
-int_float_err = "%i + %f" % ("1", "2.00")
-
-# this is bad too
-int_float_err = "%i + %f" % (1, "2.00")
-
-# ---------------------------
-# new style of string substitution / formatting
-print("%(lang)s is fun!" % {"lang":"Python"})
-print("%(value)s %(value)s %(value)s !" % {"value":"SPAM"})
-
-# this one won't work!
-print("%(x)i + %(y)i = %(z)i" % {"x":1, "y":2})
-
-# this is a fix of the previous example
-print("%(x)i + %(y)i = %(z)i" % {"x":1, "y":2, "z":3})
-
-# messing with the order of substitution
-"Python is as simple as {0}, {1}, {2}".format("a", "b", "c")
-"Python is as simple as {1}, {0}, {2}".format("a", "b", "c")
-
-# creating the dict and then doing the substitution
-xy = {"x":0, "y":10}
-print("Graph a point at where x={x} and y={y}".format(**xy))
\ No newline at end of file
diff --git a/Chapter 20 - sys/call_exit.py b/Chapter 20 - sys/call_exit.py
deleted file mode 100644
index ef1a4d4..0000000
--- a/Chapter 20 - sys/call_exit.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# call_exit.py
-import subprocess
-
-code = subprocess.call(["python.exe", "exit.py"])
-print(code)
\ No newline at end of file
diff --git a/Chapter 20 - sys/exit.py b/Chapter 20 - sys/exit.py
deleted file mode 100644
index 40be86f..0000000
--- a/Chapter 20 - sys/exit.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import sys
-
-sys.exit(0)
\ No newline at end of file
diff --git a/Chapter 20 - sys/readme.txt b/Chapter 20 - sys/readme.txt
deleted file mode 100644
index 0887469..0000000
--- a/Chapter 20 - sys/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-Most of the examples in this chapter should be run in IDLE so you can better understand the sys module
\ No newline at end of file
diff --git a/Chapter 20 - sys/sysargv.py b/Chapter 20 - sys/sysargv.py
deleted file mode 100644
index 4d8e493..0000000
--- a/Chapter 20 - sys/sysargv.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# sysargv.py
-import sys
-
-print(sys.argv)
\ No newline at end of file
diff --git a/Chapter 21 - threading/downloader_2x.py b/Chapter 21 - threading/downloader_2x.py
deleted file mode 100644
index 6b19c4b..0000000
--- a/Chapter 21 - threading/downloader_2x.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Python 2 version
-import os
-import urllib2
-
-from threading import Thread
-
-class DownloadThread(Thread):
- """
- A threading example that can download a file
- """
-
- def __init__(self, url, name):
- """Initialize the thread"""
- Thread.__init__(self)
- self.name = name
- self.url = url
-
- def run(self):
- """Run the thread"""
- handle = urllib2.urlopen(self.url)
- fname = os.path.basename(self.url)
- with open(fname, "wb") as f_handler:
- while True:
- chunk = handle.read(1024)
- if not chunk:
- break
- f_handler.write(chunk)
- msg = "%s has finished downloading %s!" % (self.name,
- self.url)
- print(msg)
-
-def main(urls):
- """
- Run the program
- """
- for item, url in enumerate(urls):
- name = "Thread %s" % (item+1)
- thread = DownloadThread(url, name)
- thread.start()
-
-if __name__ == "__main__":
- urls = ["http://www.irs.gov/pub/irs-pdf/f1040.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040a.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040ez.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040es.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040sb.pdf"]
- main(urls)
\ No newline at end of file
diff --git a/Chapter 21 - threading/downloader_3x.py b/Chapter 21 - threading/downloader_3x.py
deleted file mode 100644
index 6a0c9c1..0000000
--- a/Chapter 21 - threading/downloader_3x.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Python 3 version
-import os
-import urllib.request
-
-from threading import Thread
-
-class DownloadThread(Thread):
- """
- A threading example that can download a file
- """
-
- def __init__(self, url, name):
- """Initialize the thread"""
- Thread.__init__(self)
- self.name = name
- self.url = url
-
- def run(self):
- """Run the thread"""
- handle = urllib.request.urlopen(self.url)
- fname = os.path.basename(self.url)
- with open(fname, "wb") as f_handler:
- while True:
- chunk = handle.read(1024)
- if not chunk:
- break
- f_handler.write(chunk)
- msg = "%s has finished downloading %s!" % (self.name,
- self.url)
- print(msg)
-
-def main(urls):
- """
- Run the program
- """
- for item, url in enumerate(urls):
- name = "Thread %s" % (item+1)
- thread = DownloadThread(url, name)
- thread.start()
-
-if __name__ == "__main__":
- urls = ["http://www.irs.gov/pub/irs-pdf/f1040.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040a.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040ez.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040es.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040sb.pdf"]
- main(urls)
\ No newline at end of file
diff --git a/Chapter 21 - threading/downloader_queues.py b/Chapter 21 - threading/downloader_queues.py
deleted file mode 100644
index d07552c..0000000
--- a/Chapter 21 - threading/downloader_queues.py
+++ /dev/null
@@ -1,62 +0,0 @@
-import os
-import threading
-import urllib.request
-
-from queue import Queue
-
-class Downloader(threading.Thread):
- """Threaded File Downloader"""
-
- def __init__(self, queue):
- """Initialize the thread"""
- threading.Thread.__init__(self)
- self.queue = queue
-
- def run(self):
- """Run the thread"""
- while True:
- # gets the url from the queue
- url = self.queue.get()
-
- # download the file
- self.download_file(url)
-
- # send a signal to the queue that the job is done
- self.queue.task_done()
-
- def download_file(self, url):
- """Download the file"""
- handle = urllib.request.urlopen(url)
- fname = os.path.basename(url)
- with open(fname, "wb") as f:
- while True:
- chunk = handle.read(1024)
- if not chunk: break
- f.write(chunk)
-
-def main(urls):
- """
- Run the program
- """
- queue = Queue()
-
- # create a thread pool and give them a queue
- for i in range(5):
- t = Downloader(queue)
- t.setDaemon(True)
- t.start()
-
- # give the queue some data
- for url in urls:
- queue.put(url)
-
- # wait for the queue to finish
- queue.join()
-
-if __name__ == "__main__":
- urls = ["http://www.irs.gov/pub/irs-pdf/f1040.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040a.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040ez.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040es.pdf",
- "http://www.irs.gov/pub/irs-pdf/f1040sb.pdf"]
- main(urls)
\ No newline at end of file
diff --git a/Chapter 21 - threading/simple_threads.py b/Chapter 21 - threading/simple_threads.py
deleted file mode 100644
index 4836f82..0000000
--- a/Chapter 21 - threading/simple_threads.py
+++ /dev/null
@@ -1,32 +0,0 @@
-import random
-import time
-
-from threading import Thread
-
-class MyThread(Thread):
- """
- A threading example
- """
- def __init__(self, name):
- """Initialize the thread"""
- Thread.__init__(self)
- self.name = name
-
- def run(self):
- """Run the thread"""
- amount = random.randint(3, 15)
- time.sleep(amount)
- msg = "%s is running" % self.name
- print(msg)
-
-def create_threads():
- """
- Create a group of threads
- """
- for i in range(5):
- name = "Thread #%s" % (i+1)
- my_thread = MyThread(name)
- my_thread.start()
-
-if __name__ == "__main__":
- create_threads()
\ No newline at end of file
diff --git a/Chapter 22 - time/readme.txt b/Chapter 22 - time/readme.txt
deleted file mode 100644
index ba449fa..0000000
--- a/Chapter 22 - time/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-Most of the examples in this chapter should be run in IDLE so you can better understand the datetime and time modules
\ No newline at end of file
diff --git a/Chapter 23 - xml/appt.xml b/Chapter 23 - xml/appt.xml
deleted file mode 100644
index d2dd55a..0000000
--- a/Chapter 23 - xml/appt.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- 1181251680
- 040000008200E000
- 1181572063
-
-
- 1800
- Bring pizza home
-
-
\ No newline at end of file
diff --git a/Chapter 23 - xml/create_with_elementtree.py b/Chapter 23 - xml/create_with_elementtree.py
deleted file mode 100644
index 184f2ee..0000000
--- a/Chapter 23 - xml/create_with_elementtree.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import xml.etree.ElementTree as xml
-
-def createXML(filename):
- """
- Create an example XML file
- """
- root = xml.Element("zAppointments")
- appt = xml.Element("appointment")
- root.append(appt)
-
- # add appointment children
- begin = xml.SubElement(appt, "begin")
- begin.text = "1181251680"
-
- uid = xml.SubElement(appt, "uid")
- uid.text = "040000008200E000"
-
- alarmTime = xml.SubElement(appt, "alarmTime")
- alarmTime.text = "1181572063"
-
- state = xml.SubElement(appt, "state")
-
- location = xml.SubElement(appt, "location")
-
- duration = xml.SubElement(appt, "duration")
- duration.text = "1800"
-
- subject = xml.SubElement(appt, "subject")
-
- tree = xml.ElementTree(root)
- with open(filename, "w") as fh:
- tree.write(fh)
-
-if __name__ == "__main__":
- createXML("appt.xml")
-
\ No newline at end of file
diff --git a/Chapter 23 - xml/edit_with_elementtree.py b/Chapter 23 - xml/edit_with_elementtree.py
deleted file mode 100644
index c200124..0000000
--- a/Chapter 23 - xml/edit_with_elementtree.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import time
-import xml.etree.cElementTree as ET
-
-def editXML(filename):
- """
- Edit an example XML file
- """
- tree = ET.ElementTree(file=filename)
- root = tree.getroot()
-
- for begin_time in root.iter("begin"):
- begin_time.text = time.ctime(int(begin_time.text))
-
- tree = ET.ElementTree(root)
- with open("updated.xml", "w") as f:
- tree.write(f)
-
-if __name__ == "__main__":
- editXML("original_appt.xml")
\ No newline at end of file
diff --git a/Chapter 23 - xml/example.xml b/Chapter 23 - xml/example.xml
deleted file mode 100644
index 5737624..0000000
--- a/Chapter 23 - xml/example.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
- Gambardella, Matthew
- XML Developer's Guide
- Computer
- 44.95
- 2000-10-01
- An in-depth look at creating applications
- with XML.
-
-
- Ralls, Kim
- Midnight Rain
- Fantasy
- 5.95
- 2000-12-16
- A former architect battles corporate zombies,
- an evil sorceress, and her own childhood to become queen
- of the world.
-
-
- Corets, Eva
- Maeve Ascendant
- Fantasy
- 5.95
- 2000-11-17
- After the collapse of a nanotechnology
- society in England, the young survivors lay the
- foundation for a new society.
-
-
\ No newline at end of file
diff --git a/Chapter 23 - xml/minidom_parse.py b/Chapter 23 - xml/minidom_parse.py
deleted file mode 100644
index 4fd862d..0000000
--- a/Chapter 23 - xml/minidom_parse.py
+++ /dev/null
@@ -1,76 +0,0 @@
-import xml.dom.minidom
-import urllib.request
-
-class ApptParser(object):
-
- def __init__(self, url, flag='url'):
- self.list = []
- self.appt_list = []
- self.flag = flag
- self.rem_value = 0
- xml = self.getXml(url)
- self.handleXml(xml)
-
- def getXml(self, url):
- try:
- print(url)
- f = urllib.request.urlopen(url)
- except:
- f = url
-
- doc = xml.dom.minidom.parse(f)
- node = doc.documentElement
- if node.nodeType == xml.dom.Node.ELEMENT_NODE:
- print('Element name: %s' % node.nodeName)
- for (name, value) in node.attributes.items():
- print(' Attr -- Name: %s Value: %s' % (name, value))
-
- return node
-
- def handleXml(self, xml):
- rem = xml.getElementsByTagName('zAppointments')
- appointments = xml.getElementsByTagName("appointment")
- self.handleAppts(appointments)
-
- def getElement(self, element):
- return self.getText(element.childNodes)
-
- def handleAppts(self, appts):
- for appt in appts:
- self.handleAppt(appt)
- self.list = []
-
- def handleAppt(self, appt):
- begin = self.getElement(appt.getElementsByTagName("begin")[0])
- duration = self.getElement(appt.getElementsByTagName("duration")[0])
- subject = self.getElement(appt.getElementsByTagName("subject")[0])
- location = self.getElement(appt.getElementsByTagName("location")[0])
- uid = self.getElement(appt.getElementsByTagName("uid")[0])
-
- self.list.append(begin)
- self.list.append(duration)
- self.list.append(subject)
- self.list.append(location)
- self.list.append(uid)
- if self.flag == 'file':
-
- try:
- state = self.getElement(appt.getElementsByTagName("state")[0])
- self.list.append(state)
- alarm = self.getElement(appt.getElementsByTagName("alarmTime")[0])
- self.list.append(alarm)
- except Exception as e:
- print(e)
-
- self.appt_list.append(self.list)
-
- def getText(self, nodelist):
- rc = ""
- for node in nodelist:
- if node.nodeType == node.TEXT_NODE:
- rc = rc + node.data
- return rc
-
-if __name__ == "__main__":
- appt = ApptParser("appt.xml")
- print(appt.appt_list)
\ No newline at end of file
diff --git a/Chapter 23 - xml/minidom_parse2.py b/Chapter 23 - xml/minidom_parse2.py
deleted file mode 100644
index d51bb73..0000000
--- a/Chapter 23 - xml/minidom_parse2.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import xml.dom.minidom as minidom
-
-def getTitles(xml):
- """
- Print out all titles found in xml
- """
- doc = minidom.parse(xml)
- node = doc.documentElement
- books = doc.getElementsByTagName("book")
-
- titles = []
- for book in books:
- titleObj = book.getElementsByTagName("title")[0]
- titles.append(titleObj)
-
- for title in titles:
- nodes = title.childNodes
-
- for node in nodes:
- if node.nodeType == node.TEXT_NODE:
- print(node.data)
-
-if __name__ == "__main__":
- document = 'example.xml'
- getTitles(document)
\ No newline at end of file
diff --git a/Chapter 23 - xml/parse_with_elementtree.py b/Chapter 23 - xml/parse_with_elementtree.py
deleted file mode 100644
index b0cf086..0000000
--- a/Chapter 23 - xml/parse_with_elementtree.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import xml.etree.cElementTree as ET
-
-def parseXML(xml_file):
- """
- Parse XML with ElementTree
- """
- tree = ET.ElementTree(file=xml_file)
- print(tree.getroot())
- root = tree.getroot()
- print("tag=%s, attrib=%s" % (root.tag, root.attrib))
-
- for child in root:
- print(child.tag, child.attrib)
- if child.tag == "appointment":
- for step_child in child:
- print(step_child.tag)
-
- # iterate over the entire tree
- print("-" * 40)
- print("Iterating using a tree iterator")
- print("-" * 40)
- iter_ = tree.getiterator()
- for elem in iter_:
- print(elem.tag)
-
- # get the information via the children!
- print("-" * 40)
- print("Iterating using getchildren()")
- print("-" * 40)
- appointments = root.getchildren()
- for appointment in appointments:
- appt_children = appointment.getchildren()
- for appt_child in appt_children:
- print("%s=%s" % (appt_child.tag, appt_child.text))
-
-if __name__ == "__main__":
- parseXML("appt.xml")
\ No newline at end of file
diff --git a/Chapter 24 - pdb/debug_test.py b/Chapter 24 - pdb/debug_test.py
deleted file mode 100644
index 67ca6e8..0000000
--- a/Chapter 24 - pdb/debug_test.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# debug_test.py
-
-def doubler(a):
- """"""
- result = a*2
- print(result)
- return result
-
-def main():
- """"""
- for i in range(1,10):
- doubler(i)
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
diff --git a/Chapter 25 - decorators/add_property.py b/Chapter 25 - decorators/add_property.py
deleted file mode 100644
index 756305d..0000000
--- a/Chapter 25 - decorators/add_property.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from decimal import Decimal
-
-class Fees(object):
- """"""
-
- def __init__(self):
- """Constructor"""
- self._fee = None
-
- def get_fee(self):
- """
- Return the current fee
- """
- return self._fee
-
- def set_fee(self, value):
- """
- Set the fee
- """
- if isinstance(value, str):
- self._fee = Decimal(value)
- elif isinstance(value, Decimal):
- self._fee = value
- fee = property(get_fee, set_fee)
\ No newline at end of file
diff --git a/Chapter 25 - decorators/add_property_setter.py b/Chapter 25 - decorators/add_property_setter.py
deleted file mode 100644
index c55c38a..0000000
--- a/Chapter 25 - decorators/add_property_setter.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from decimal import Decimal
-
-class Fees(object):
- """"""
-
- def __init__(self):
- """Constructor"""
- self._fee = None
-
- @property
- def fee(self):
- """
- The fee property - the getter
- """
- return self._fee
-
- @fee.setter
- def fee(self, value):
- """
- The setter of the fee property
- """
- if isinstance(value, str):
- self._fee = Decimal(value)
- elif isinstance(value, Decimal):
- self._fee = value
-
-if __name__ == "__main__":
- f = Fees()
\ No newline at end of file
diff --git a/Chapter 25 - decorators/builtin_decorators.py b/Chapter 25 - decorators/builtin_decorators.py
deleted file mode 100644
index 380d7cd..0000000
--- a/Chapter 25 - decorators/builtin_decorators.py
+++ /dev/null
@@ -1,36 +0,0 @@
-class DecoratorTest(object):
- """
- Test regular method vs @classmethod vs @staticmethod
- """
-
- def __init__(self):
- """Constructor"""
- pass
-
- def doubler(self, x):
- """"""
- print("running doubler")
- return x*2
-
- @classmethod
- def class_tripler(klass, x):
- """"""
- print("running tripler: %s" % klass)
- return x*3
-
- @staticmethod
- def static_quad(x):
- """"""
- print("running quad")
- return x*4
-
-if __name__ == "__main__":
- decor = DecoratorTest()
- print(decor.doubler(5))
- print(decor.class_tripler(3))
- print(DecoratorTest.class_tripler(3))
- print(DecoratorTest.static_quad(2))
- print(decor.static_quad(3))
- print(decor.doubler)
- print(decor.class_tripler)
- print(decor.static_quad)
\ No newline at end of file
diff --git a/Chapter 25 - decorators/logging_decorator.py b/Chapter 25 - decorators/logging_decorator.py
deleted file mode 100644
index 8ef2527..0000000
--- a/Chapter 25 - decorators/logging_decorator.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import logging
-
-def log(func):
- """
- Log what function is called
- """
- def wrap_log(*args, **kwargs):
- name = func.__name__
- logger = logging.getLogger(name)
- logger.setLevel(logging.INFO)
-
- # add file handler
- fh = logging.FileHandler("%s.log" % name)
- fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
- formatter = logging.Formatter(fmt)
- fh.setFormatter(formatter)
- logger.addHandler(fh)
-
- logger.info("Running function: %s" % name)
- result = func(*args, **kwargs)
- logger.info("Result: %s" % result)
- return func
- return wrap_log
-
-@log
-def double_function(a):
- """
- Double the input parameter
- """
- return a*2
-
-if __name__ == "__main__":
- value = double_function(2)
\ No newline at end of file
diff --git a/Chapter 25 - decorators/properties.py b/Chapter 25 - decorators/properties.py
deleted file mode 100644
index b35679e..0000000
--- a/Chapter 25 - decorators/properties.py
+++ /dev/null
@@ -1,21 +0,0 @@
-class Person(object):
- """"""
-
- def __init__(self, first_name, last_name):
- """Constructor"""
- self.first_name = first_name
- self.last_name = last_name
-
- @property
- def full_name(self):
- """
- Return the full name
- """
- return "%s %s" % (self.first_name, self.last_name)
-
-if __name__ == "__main__":
- person = Person("Mike", "Driscoll")
- print(person.full_name)
- print(person.first_name)
- person.first_name = "Dan"
- print(person.full_name)
\ No newline at end of file
diff --git a/Chapter 25 - decorators/property_setters_getters.py b/Chapter 25 - decorators/property_setters_getters.py
deleted file mode 100644
index 0188328..0000000
--- a/Chapter 25 - decorators/property_setters_getters.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from decimal import Decimal
-
-class Fees(object):
- """"""
-
- def __init__(self):
- """Constructor"""
- self._fee = None
-
- def get_fee(self):
- """
- Return the current fee
- """
- return self._fee
-
- def set_fee(self, value):
- """
- Set the fee
- """
- if isinstance(value, str):
- self._fee = Decimal(value)
- elif isinstance(value, Decimal):
- self._fee = value
-
-if __name__ == "__main__":
- f = Fees()
- f.set_fee("1")
- print( f.get_fee() )
\ No newline at end of file
diff --git a/Chapter 25 - decorators/simple_decorator.py b/Chapter 25 - decorators/simple_decorator.py
deleted file mode 100644
index d2ef72b..0000000
--- a/Chapter 25 - decorators/simple_decorator.py
+++ /dev/null
@@ -1,21 +0,0 @@
-def another_function(func):
- """
- A function that accepts another function
- """
-
- def other_func():
- val = "The result of %s is %s" % (func(),
- eval(func())
- )
- return val
- return other_func
-
-def a_function():
- """A pretty useless function"""
- return "1+1"
-
-if __name__ == "__main__":
- value = a_function()
- print(value)
- decorator = another_function(a_function)
- print(decorator())
\ No newline at end of file
diff --git a/Chapter 25 - decorators/simple_decorator2.py b/Chapter 25 - decorators/simple_decorator2.py
deleted file mode 100644
index 940f64c..0000000
--- a/Chapter 25 - decorators/simple_decorator2.py
+++ /dev/null
@@ -1,20 +0,0 @@
-def another_function(func):
- """
- A function that accepts another function
- """
-
- def other_func():
- val = "The result of %s is %s" % (func(),
- eval(func())
- )
- return val
- return other_func
-
-@another_function
-def a_function():
- """A pretty useless function"""
- return "1+1"
-
-if __name__ == "__main__":
- value = a_function()
- print(value)
\ No newline at end of file
diff --git a/Chapter 25 - decorators/simple_function.py b/Chapter 25 - decorators/simple_function.py
deleted file mode 100644
index bbd1dda..0000000
--- a/Chapter 25 - decorators/simple_function.py
+++ /dev/null
@@ -1,7 +0,0 @@
-def a_function():
- """A pretty useless function"""
- return "1+1"
-
-if __name__ == "__main__":
- value = a_function()
- print(value)
\ No newline at end of file
diff --git a/Chapter 26 - lambda/simple_lambda.py b/Chapter 26 - lambda/simple_lambda.py
deleted file mode 100644
index 9b4ac1c..0000000
--- a/Chapter 26 - lambda/simple_lambda.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import math
-
-def sqroot(x):
- """
- Finds the square root of the number passed in
- """
- return math.sqrt(x)
-
-if __name__ == "__main__":
- square_rt = lambda x: math.sqrt(x)
- print( sqroot(49) )
\ No newline at end of file
diff --git a/Chapter 26 - lambda/tkinter_lambda.py b/Chapter 26 - lambda/tkinter_lambda.py
deleted file mode 100644
index 208c922..0000000
--- a/Chapter 26 - lambda/tkinter_lambda.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import Tkinter as tk
-
-class App:
- """"""
-
- def __init__(self, parent):
- """Constructor"""
- frame = tk.Frame(parent)
- frame.pack()
-
- btn22 = tk.Button(frame, text="22", command=lambda: self.printNum(22))
- btn22.pack(side=tk.LEFT)
- btn44 = tk.Button(frame, text="44", command=lambda: self.printNum(44))
- btn44.pack(side=tk.LEFT)
- quitBtn = tk.Button(frame, text="QUIT", fg="red", command=frame.quit)
- quitBtn.pack(side=tk.LEFT)
-
- def printNum(self, num):
- """"""
- print("You pressed the %s button" % num)
-
-if __name__ == "__main__":
- root = tk.Tk()
- app = App(root)
- root.mainloop()
\ No newline at end of file
diff --git a/Chapter 27 - profiling/ptest.py b/Chapter 27 - profiling/ptest.py
deleted file mode 100644
index 924453f..0000000
--- a/Chapter 27 - profiling/ptest.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import time
-
-def fast():
- """"""
- print("I run fast!")
-
-def slow():
- """"""
- time.sleep(3)
- print("I run slow!")
-
-def medium():
- """"""
- time.sleep(0.5)
- print("I run a little slowly...")
-
-def main():
- """"""
- fast()
- slow()
- medium()
-
-if __name__ == '__main__':
- main()
\ No newline at end of file
diff --git a/Chapter 28 - testing/dtest1.py b/Chapter 28 - testing/dtest1.py
deleted file mode 100644
index 0bb3dbb..0000000
--- a/Chapter 28 - testing/dtest1.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# dtest1.py
-
-def double(a):
- """
- >>> double(4)
- 8
- >>> double(9)
- 18
- """
- return a*2
\ No newline at end of file
diff --git a/Chapter 28 - testing/dtest2.py b/Chapter 28 - testing/dtest2.py
deleted file mode 100644
index 88e363e..0000000
--- a/Chapter 28 - testing/dtest2.py
+++ /dev/null
@@ -1,12 +0,0 @@
-def double(a):
- """
- >>> double(4)
- 8
- >>> double(9)
- 18
- """
- return a*2
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod(verbose=True)
\ No newline at end of file
diff --git a/Chapter 28 - testing/first_test_bowling.py b/Chapter 28 - testing/first_test_bowling.py
deleted file mode 100644
index c68a8d7..0000000
--- a/Chapter 28 - testing/first_test_bowling.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import unittest
-
-class TestBowling(unittest.TestCase):
- """"""
- def test_all_ones(self):
- """Constructor"""
- game = Game()
- game.roll(11, 1)
- self.assertEqual(game.score, 11)
-
-class Game:
- """"""
-
- def __init__(self):
- """Constructor"""
- self.score = 0
-
- def roll(self, numOfRolls, pins):
- """"""
- for roll in numOfRolls:
- self.score += pins
-
-if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
diff --git a/Chapter 28 - testing/first_test_bowling2.py b/Chapter 28 - testing/first_test_bowling2.py
deleted file mode 100644
index b44cd4f..0000000
--- a/Chapter 28 - testing/first_test_bowling2.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import unittest
-
-class TestBowling(unittest.TestCase):
- """"""
- def test_all_ones(self):
- """Constructor"""
- game = Game()
- game.roll(11, 1)
- self.assertEqual(game.score, 11)
-
-class Game:
- """"""
-
- def __init__(self):
- """Constructor"""
- self.score = 0
-
- def roll(self, numOfRolls, pins):
- """"""
- for roll in range(numOfRolls):
- self.score += pins
-
-if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
diff --git a/Chapter 28 - testing/game_v2.py b/Chapter 28 - testing/game_v2.py
deleted file mode 100644
index f091d36..0000000
--- a/Chapter 28 - testing/game_v2.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# game_v2.py
-
-class Game:
- """"""
- def __init__(self):
- """Constructor"""
- self.score = 0
- self.pins = [0 for i in range(11)]
-
- def roll(self, numOfRolls, pins):
- """"""
- x = 0
- for pin in pins:
- self.pins[x] = pin
- x += 1
- x = 0
- spare_begin = 0
- spare_end = 2
- for roll in range(numOfRolls):
- spare = sum(self.pins[spare_begin:spare_end])
- if self.pins[x] == 10:
- self.score = self.pins[x] + self.pins[x+1] + self.pins[x+2]
- elif spare == 10:
- self.score = spare + self.pins[x+2]
- x += 1
- else:
- self.score += self.pins[x]
- x += 1
- if x == 11:
- break
- spare_begin += 2
- spare_end += 2
- print(self.score)
\ No newline at end of file
diff --git a/Chapter 28 - testing/second_test_bowling.py b/Chapter 28 - testing/second_test_bowling.py
deleted file mode 100644
index 3e0f159..0000000
--- a/Chapter 28 - testing/second_test_bowling.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from game import Game
-import unittest
-
-class TestBowling(unittest.TestCase):
- """"""
-
- def test_all_ones(self):
- """Constructor"""
- game = Game()
- pins = [1 for i in range(11)]
-
- game.roll(11, pins)
- self.assertEqual(game.score, 11)
-
- def test_strike(self):
- """
- A strike is 10 + the value of the next two rolls. So in this case
- the first frame will be 10+5+4 or 19 and the second will be
- 5+4. The total score would be 19+9 or 28.
- """
- game = Game()
- game.roll(11, [10, 5, 4])
- self.assertEqual(game.score, 28)
-
-if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
diff --git a/Chapter 28 - testing/second_test_bowling2.py b/Chapter 28 - testing/second_test_bowling2.py
deleted file mode 100644
index 5e1eb7e..0000000
--- a/Chapter 28 - testing/second_test_bowling2.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from game import Game
-import unittest
-
-class TestBowling(unittest.TestCase):
- """"""
-
- def test_all_ones(self):
- """Constructor"""
- game = Game()
- pins = [1 for i in range(11)]
-
- game.roll(11, pins)
- self.assertEqual(game.score, 11)
-
- def test_strike(self):
- """
- A strike is 10 + the value of the next two rolls. So in this case
- the first frame will be 10+5+4 or 19 and the second will be
- 5+4. The total score would be 19+9 or 28.
- """
- game = Game()
- game.roll(11, [10, 5, 4])
- self.assertEqual(game.score, 28)
-
-class Game:
- """"""
-
- def __init__(self):
- """Constructor"""
- self.score = 0
- self.pins = [0 for i in range(11)]
-
- def roll(self, numOfRolls, pins):
- """"""
- x = 0
- for pin in pins:
- self.pins[x] = pin
- x += 1
- x = 0
- for roll in range(numOfRolls):
- if self.pins[x] == 10:
- self.score = self.pins[x] + self.pins[x+1] + self.pins[x+2]
- else:
- self.score += self.pins[x]
- x += 1
- print(self.score)
-
-if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
diff --git a/Chapter 28 - testing/third_test_bowling.py b/Chapter 28 - testing/third_test_bowling.py
deleted file mode 100644
index 4691556..0000000
--- a/Chapter 28 - testing/third_test_bowling.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from game_v2 import Game
-import unittest
-
-class TestBowling(unittest.TestCase):
- """"""
-
- def setUp(self):
- """"""
- self.game = Game()
-
- def test_all_ones(self):
- """
- If you don't get a strike or a spare, then you just add up the
- face value of the frame. In this case, each frame is worth
- one point, so the total is eleven.
- """
- pins = [1 for i in range(11)]
- self.game.roll(11, pins)
- self.assertEqual(self.game.score, 11)
-
- def test_spare(self):
- """
- A spare is worth 10, plus the value of your next roll. So in this
- case, the first frame will be 5+5+5 or 15 and the second will be
- 5+4 or 9. The total is 15+9, which equals 24,
- """
- self.game.roll(11, [5, 5, 5, 4])
- self.assertEqual(self.game.score, 24)
-
- def test_strike(self):
- """
- A strike is 10 + the value of the next two rolls. So in this case
- the first frame will be 10+5+4 or 19 and the second will be
- 5+4. The total score would be 19+9 or 28.
- """
- self.game.roll(11, [10, 5, 4])
- self.assertEqual(self.game.score, 28)
-
-if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
diff --git a/Chapter 29 - installing modules/readme.txt b/Chapter 29 - installing modules/readme.txt
deleted file mode 100644
index 33682f3..0000000
--- a/Chapter 29 - installing modules/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-The exercises in this chapter do not have corresponding code examples and are meant to be done via your console or terminal.
\ No newline at end of file
diff --git a/Chapter 3 - Lists Dicts Tuples/dict_examples.py b/Chapter 3 - Lists Dicts Tuples/dict_examples.py
deleted file mode 100644
index a3c7ff4..0000000
--- a/Chapter 3 - Lists Dicts Tuples/dict_examples.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# there are two ways to create a Python dictionary (dict)
-my_dict = {}
-another_dict = dict()
-
-# here's an example with the dict containing data
-my_other_dict = {"one":1, "two":2, "three":3}
-
-# access values in a dict
-my_other_dict["one"]
-my_dict = {"name":"Mike", "address":"123 Happy Way"}
-my_dict["name"]
-
-# check if a dict has a particular key
-"name" in my_dict # returns True
-"state" in my_dict # returns False
-
-# get a view of the keys in a dict
-my_dict.keys()
\ No newline at end of file
diff --git a/Chapter 3 - Lists Dicts Tuples/list_examples.py b/Chapter 3 - Lists Dicts Tuples/list_examples.py
deleted file mode 100644
index c226f41..0000000
--- a/Chapter 3 - Lists Dicts Tuples/list_examples.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# two ways to create an empty list
-my_list = []
-my_list = list()
-
-# examples of lists
-my_list = [1, 2, 3]
-my_list2 = ["a", "b", "c"]
-my_list3 = ["a", 1, "Python", 5]
-
-# create a nested list
-my_nested_list = [my_list, my_list2]
-
-# combine / extend a list
-combo_list = []
-one_list = [4, 5]
-combo_list.extend(one_list)
-
-# or just concatenate the lists together
-my_list = [1, 2, 3]
-my_list2 = ["a", "b", "c"]
-combo_list = my_list + my_list2
-
-# sort a list
-alpha_list = [34, 23, 67, 100, 88, 2]
-alpha_list.sort()
-alpha_list
-
-# finding a logic error
-alpha_list = [34, 23, 67, 100, 88, 2]
-sorted_list = alpha_list.sort()
-# the sort method returns a None object as lists sort in-place
-print(sorted_list)
\ No newline at end of file
diff --git a/Chapter 3 - Lists Dicts Tuples/tuple_examples.py b/Chapter 3 - Lists Dicts Tuples/tuple_examples.py
deleted file mode 100644
index 7ba2279..0000000
--- a/Chapter 3 - Lists Dicts Tuples/tuple_examples.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# a few tuple examples
-my_tuple = (1, 2, 3, 4, 5)
-my_tuple[0:3] # tuple slicing
-another_tuple = tuple() # creating an empty tuple
-
-# turn a list into a tuple via casting
-abc = tuple([1, 2, 3])
\ No newline at end of file
diff --git a/Chapter 30 - configobj/config.ini b/Chapter 30 - configobj/config.ini
deleted file mode 100644
index 522488d..0000000
--- a/Chapter 30 - configobj/config.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-product = Sony PS3
-accessories = controller, eye, memory stick
-# This is a comment that will be ignored
-retail_price = $400
\ No newline at end of file
diff --git a/Chapter 30 - configobj/configobj_example.py b/Chapter 30 - configobj/configobj_example.py
deleted file mode 100644
index 5e32d88..0000000
--- a/Chapter 30 - configobj/configobj_example.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import configobj
-
-def createConfig(path):
- config = configobj.ConfigObj()
- config.filename = path
- config["Sony"] = {}
- config["Sony"]["product"] = "Sony PS3"
- config["Sony"]["accessories"] = ['controller', 'eye', 'memory stick']
- config["Sony"]["retail price"] = "$400"
- config.write()
-
-if __name__ == "__main__":
- createConfig("config.ini")
\ No newline at end of file
diff --git a/Chapter 30 - configobj/configspec_example.py b/Chapter 30 - configobj/configspec_example.py
deleted file mode 100644
index 887187e..0000000
--- a/Chapter 30 - configobj/configspec_example.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import configobj, validate
-
-cfg = """
-bmp_select_transparent = boolean(default=False)
-canvas_border = integer(min=10, max=35, default=15)
-colour1 = list(min=3, max=3, default=list('280', '0', '0'))
-colour2 = list(min=3, max=3, default=list('255', '255', '0'))
-colour3 = list(min=3, max=3, default=list('0', '255', '0'))
-colour4 = list(min=3, max=3, default=list('255', '0', '0'))
-colour5 = list(min=3, max=3, default=list('0', '0', '255'))
-colour6 = list(min=3, max=3, default=list('160', '32', '240'))
-colour7 = list(min=3, max=3, default=list('0', '255', '255'))
-colour8 = list(min=3, max=3, default=list('255', '165', '0'))
-colour9 = list(min=3, max=3, default=list('211', '211', '211'))
-convert_quality = option('highest', 'high', 'normal', default='normal')
-default_font = string
-default_width = integer(min=1, max=12000, default=640)
-default_height = integer(min=1, max=12000, default=480)
-imagemagick_path = string
-handle_size = integer(min=3, max=15, default=6)
-language = option('English', 'English (United Kingdom)', 'Russian', 'Hindi', default='English')
-print_title = boolean(default=True)
-statusbar = boolean(default=True)
-toolbar = boolean(default=True)
-toolbox = option('icon', 'text', default='icon')
-undo_sheets = integer(min=5, max=50, default=10)
-"""
-
-def createConfig(path):
- """
- Create a config file using a configspec
- and validate it against a Validator object
- """
- spec = cfg.split("\n")
- config = configobj.ConfigObj(path, configspec=spec)
- validator = validate.Validator()
- config.validate(validator, copy=True)
- config.filename = path
- config.write()
-
-if __name__ == "__main__":
- createConfig("config.ini")
\ No newline at end of file
diff --git a/Chapter 31 - lxml/create_xml_with_objectify.py b/Chapter 31 - lxml/create_xml_with_objectify.py
deleted file mode 100644
index 2693dc4..0000000
--- a/Chapter 31 - lxml/create_xml_with_objectify.py
+++ /dev/null
@@ -1,65 +0,0 @@
-from lxml import etree, objectify
-
-def create_appt(data):
- """
- Create an appointment XML element
- """
- appt = objectify.Element("appointment")
- appt.begin = data["begin"]
- appt.uid = data["uid"]
- appt.alarmTime = data["alarmTime"]
- appt.state = data["state"]
- appt.location = data["location"]
- appt.duration = data["duration"]
- appt.subject = data["subject"]
- return appt
-
-def create_xml():
- """
- Create an XML file
- """
- xml = '''
-
-
- '''
-
- root = objectify.fromstring(xml)
- root.set("reminder", "15")
-
- appt = create_appt({"begin":1181251680,
- "uid":"040000008200E000",
- "alarmTime":1181572063,
- "state":"",
- "location":"",
- "duration":1800,
- "subject":"Bring pizza home"}
- )
- root.append(appt)
-
- uid = "604f4792-eb89-478b-a14f-dd34d3cc6c21-1234360800"
- appt = create_appt({"begin":1234360800,
- "uid":uid,
- "alarmTime":1181572063,
- "state":"dismissed",
- "location":"",
- "duration":1800,
- "subject":"Check MS Office website for updates"}
- )
- root.append(appt)
-
- # remove lxml annotation
- objectify.deannotate(root)
- etree.cleanup_namespaces(root)
-
- # create the xml string
- obj_xml = etree.tostring(root,
- pretty_print=True,
- xml_declaration=True)
- try:
- with open("example.xml", "wb") as xml_writer:
- xml_writer.write(obj_xml)
- except IOError:
- pass
-
-if __name__ == "__main__":
- create_xml()
\ No newline at end of file
diff --git a/Chapter 31 - lxml/example.xml b/Chapter 31 - lxml/example.xml
deleted file mode 100644
index 0ba8878..0000000
--- a/Chapter 31 - lxml/example.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- 1181251680
- 040000008200E000
- 1181572063
-
-
- 1800
- Bring pizza home
-
-
- 1181253977
- sdlkjlkadhdakhdfd
- 1181588888
- TX
- Dallas
- 1800
- Bring pizza home
-
-
\ No newline at end of file
diff --git a/Chapter 31 - lxml/example2.xml b/Chapter 31 - lxml/example2.xml
deleted file mode 100644
index bbcb205..0000000
--- a/Chapter 31 - lxml/example2.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
- Gambardella, Matthew
- XML Developer's Guide
- Computer
- 44.95
- 2000-10-01
- An in-depth look at creating applications
- with XML.
-
-
- Ralls, Kim
- Midnight Rain
- Fantasy
- 5.95
- 2000-12-16
- A former architect battles corporate zombies,
- an evil sorceress, and her own childhood to become queen
- of the world.
-
-
- Corets, Eva
- Maeve Ascendant
- Fantasy
- 5.95
- 2000-11-17
- After the collapse of a nanotechnology
- society in England, the young survivors lay the
- foundation for a new society.
-
-
\ No newline at end of file
diff --git a/Chapter 31 - lxml/parse_book_example.py b/Chapter 31 - lxml/parse_book_example.py
deleted file mode 100644
index cb46bef..0000000
--- a/Chapter 31 - lxml/parse_book_example.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from lxml import etree
-from StringIO import StringIO
-
-def parseBookXML(xmlFile):
-
- f = open(xmlFile)
- xml = f.read()
- f.close()
-
- tree = etree.parse(StringIO(xml))
- print(tree.docinfo.doctype)
- context = etree.iterparse(StringIO(xml))
- book_dict = {}
- books = []
- for action, elem in context:
- if not elem.text:
- text = "None"
- else:
- text = elem.text
- print(elem.tag + " => " + text)
- book_dict[elem.tag] = text
- if elem.tag == "book":
- books.append(book_dict)
- book_dict = {}
- return books
-
-if __name__ == "__main__":
- parseBookXML("example2.xml")
\ No newline at end of file
diff --git a/Chapter 31 - lxml/parse_book_example_refactored.py b/Chapter 31 - lxml/parse_book_example_refactored.py
deleted file mode 100644
index 271adb3..0000000
--- a/Chapter 31 - lxml/parse_book_example_refactored.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from lxml import etree
-
-def parseBookXML(xmlFile):
- """"""
- context = etree.iterparse(xmlFile)
- book_dict = {}
- books = []
- for action, elem in context:
- if not elem.text:
- text = "None"
- else:
- text = elem.text
- print(elem.tag + " => " + text)
- book_dict[elem.tag] = text
- if elem.tag == "book":
- books.append(book_dict)
- book_dict = {}
- return books
-
-if __name__ == "__main__":
- parseBookXML("example3.xml")
\ No newline at end of file
diff --git a/Chapter 31 - lxml/parse_with_objectify.py b/Chapter 31 - lxml/parse_with_objectify.py
deleted file mode 100644
index 6d07dbd..0000000
--- a/Chapter 31 - lxml/parse_with_objectify.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from lxml import etree, objectify
-
-def parseXML(xmlFile):
- """Parse the XML file"""
- with open(xmlFile) as f:
- xml = f.read()
-
- root = objectify.fromstring(xml)
-
- # returns attributes in element node as dict
- attrib = root.attrib
-
- # how to extract element data
- begin = root.appointment.begin
- uid = root.appointment.uid
-
- # loop over elements and print their tags and text
- for e in root.appointment.iterchildren():
- print("%s => %s" % (e.tag, e.text))
-
- # how to change an element's text
- root.appointment.begin = "something else"
- print(root.appointment.begin)
-
- # how to add a new element
- root.appointment.new_element = "new data"
-
- # remove the py:pytype stuff
- objectify.deannotate(root)
- etree.cleanup_namespaces(root)
- obj_xml = etree.tostring(root, pretty_print=True)
- print(obj_xml)
-
- # save your xml
- with open("new.xml", "w") as f:
- f.write(obj_xml)
-
-if __name__ == "__main__":
- f = r'path\to\sample.xml'
- parseXML(f)
\ No newline at end of file
diff --git a/Chapter 31 - lxml/simple_parser.py b/Chapter 31 - lxml/simple_parser.py
deleted file mode 100644
index 1904b15..0000000
--- a/Chapter 31 - lxml/simple_parser.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from lxml import etree
-from StringIO import StringIO
-
-def parseXML(xmlFile):
- """
- Parse the xml
- """
- f = open(xmlFile)
- xml = f.read()
- f.close()
-
- tree = etree.parse(StringIO(xml))
- context = etree.iterparse(StringIO(xml))
- for action, elem in context:
- if not elem.text:
- text = "None"
- else:
- text = elem.text
- print(elem.tag + " => " + text)
-
-if __name__ == "__main__":
- parseXML("example.xml")
\ No newline at end of file
diff --git a/Chapter 32 - code analysis/crummy_code.py b/Chapter 32 - code analysis/crummy_code.py
deleted file mode 100644
index 22f1223..0000000
--- a/Chapter 32 - code analysis/crummy_code.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import sys
-
-class CarClass:
- """"""
-
- def __init__(self, color, make, model, year):
- """Constructor"""
- self.color = color
- self.make = make
- self.model = model
- self.year = year
-
- if "Windows" in platform.platform():
- print("You're using Windows!")
-
- self.weight = self.getWeight(1, 2, 3)
-
- def getWeight(this):
- """"""
- return "2000 lbs"
\ No newline at end of file
diff --git a/Chapter 32 - code analysis/crummy_code_fixed.py b/Chapter 32 - code analysis/crummy_code_fixed.py
deleted file mode 100644
index b3cf6fb..0000000
--- a/Chapter 32 - code analysis/crummy_code_fixed.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# crummy_code_fixed.py
-import platform
-
-class CarClass:
- """"""
- def __init__(self, color, make, model, year):
- """Constructor"""
- self.color = color
- self.make = make
- self.model = model
- self.year = year
-
- if "Windows" in platform.platform():
- print("You're using Windows!")
-
- self.weight = self.get_weight(3)
-
- def get_weight(self, this):
- """"""
- return "2000 lbs"
\ No newline at end of file
diff --git a/Chapter 33 - requests/submit_form_requests.py b/Chapter 33 - requests/submit_form_requests.py
deleted file mode 100644
index 793ba22..0000000
--- a/Chapter 33 - requests/submit_form_requests.py
+++ /dev/null
@@ -1,7 +0,0 @@
-import requests
-
-url = 'https://duckduckgo.com/html/'
-payload = {'q':'python'}
-r = requests.get(url, params=payload)
-with open("requests_results.html", "wb") as f:
- f.write(r.content)
\ No newline at end of file
diff --git a/Chapter 33 - requests/submit_form_urllib.py b/Chapter 33 - requests/submit_form_urllib.py
deleted file mode 100644
index 339043a..0000000
--- a/Chapter 33 - requests/submit_form_urllib.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import urllib.request
-import urllib.parse
-import webbrowser
-
-data = urllib.parse.urlencode({'q': 'Python'})
-url = 'http://duckduckgo.com/html/'
-full_url = url + '?' + data
-response = urllib.request.urlopen(full_url)
-with open("results.html", "wb") as f:
- f.write(response.read())
-
-webbrowser.open("results.html")
\ No newline at end of file
diff --git a/Chapter 34 - SQLAlchemy/add_data.py b/Chapter 34 - SQLAlchemy/add_data.py
deleted file mode 100644
index e6ec996..0000000
--- a/Chapter 34 - SQLAlchemy/add_data.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# add_data.py
-import datetime
-from sqlalchemy import create_engine
-from sqlalchemy.orm import sessionmaker
-from table_def import Album, Artist
-
-engine = create_engine('sqlite:///mymusic.db', echo=True)
-
-# create a Session
-Session = sessionmaker(bind=engine)
-session = Session()
-
-# Create an artist
-new_artist = Artist(name="Newsboys")
-new_artist.albums = [Album(title="Read All About It",
- release_date=datetime.date(1988,12,1),
- publisher="Refuge", media_type="CD")]
-
-# add more albums
-more_albums = [Album(title="Hell Is for Wimps",
- release_date=datetime.date(1990,7,31),
- publisher="Star Song", media_type="CD"),
- Album(title="Love Liberty Disco",
- release_date=datetime.date(1999,11,16),
- publisher="Sparrow", media_type="CD"),
- Album(title="Thrive",
- release_date=datetime.date(2002,3,26),
- publisher="Sparrow", media_type="CD")]
-new_artist.albums.extend(more_albums)
-
-# Add the record to the session object
-session.add(new_artist)
-
-# commit the record the database
-session.commit()
-
-# Add several artists
-session.add_all([
- Artist(name="MXPX"),
- Artist(name="Kutless"),
- Artist(name="Thousand Foot Krutch")
-])
-session.commit()
\ No newline at end of file
diff --git a/Chapter 34 - SQLAlchemy/deleting_data.py b/Chapter 34 - SQLAlchemy/deleting_data.py
deleted file mode 100644
index 7558e0d..0000000
--- a/Chapter 34 - SQLAlchemy/deleting_data.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# deleting_data.py
-from sqlalchemy import create_engine
-from sqlalchemy.orm import sessionmaker
-from table_def import Album, Artist
-
-engine = create_engine('sqlite:///mymusic.db', echo=True)
-
-# create a Session
-Session = sessionmaker(bind=engine)
-session = Session()
-
-res = session.query(Artist).filter(Artist.name=="MXPX").first()
-
-session.delete(res)
-session.commit()
\ No newline at end of file
diff --git a/Chapter 34 - SQLAlchemy/modify_data.py b/Chapter 34 - SQLAlchemy/modify_data.py
deleted file mode 100644
index 5dd439e..0000000
--- a/Chapter 34 - SQLAlchemy/modify_data.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# modify_data.py
-from sqlalchemy import create_engine
-from sqlalchemy.orm import sessionmaker
-from table_def import Album, Artist
-
-engine = create_engine('sqlite:///mymusic.db', echo=True)
-
-# create a Session
-Session = sessionmaker(bind=engine)
-session = Session()
-
-# querying for a record in the Artist table
-res = session.query(Artist).filter(Artist.name=="Kutless").first()
-print(res.name)
-
-# changing the name
-res.name = "Beach Boys"
-session.commit()
-
-# editing Album data
-artist, album = session.query(Artist, Album).filter(
- Artist.id==Album.artist_id).filter(Album.title=="Thrive").first()
-album.title = "Step Up to the Microphone"
-session.commit()
\ No newline at end of file
diff --git a/Chapter 34 - SQLAlchemy/queries.py b/Chapter 34 - SQLAlchemy/queries.py
deleted file mode 100644
index b633875..0000000
--- a/Chapter 34 - SQLAlchemy/queries.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# queries.py
-from sqlalchemy import create_engine
-from sqlalchemy.orm import sessionmaker
-from table_def import Album, Artist
-
-engine = create_engine('sqlite:///mymusic.db', echo=True)
-
-# create a Session
-Session = sessionmaker(bind=engine)
-session = Session()
-
-# how to do a SELECT * (i.e. all)
-res = session.query(Artist).all()
-for artist in res:
- print(artist.name)
-
-# how to SELECT the first result
-res = session.query(Artist).filter(Artist.name=="Newsboys").first()
-
-# how to sort the results (ORDER_BY)
-res = session.query(Album).order_by(Album.title).all()
-for album in res:
- print(album.title)
-
-# how to do a JOINed query
-qry = session.query(Artist, Album)
-qry = qry.filter(Artist.id==Album.artist_id)
-artist, album = qry.filter(Album.title=="Step Up to the Microphone").first()
-
-# how to use LIKE in a query
-res = session.query(Album).filter(Album.publisher.like("S%a%")).all()
-for item in res:
- print(item.publisher)
\ No newline at end of file
diff --git a/Chapter 34 - SQLAlchemy/table_def.py b/Chapter 34 - SQLAlchemy/table_def.py
deleted file mode 100644
index 719b0df..0000000
--- a/Chapter 34 - SQLAlchemy/table_def.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# table_def.py
-from sqlalchemy import create_engine, ForeignKey
-from sqlalchemy import Column, Date, Integer, String
-from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import relationship, backref
-
-engine = create_engine('sqlite:///mymusic.db', echo=True)
-Base = declarative_base()
-
-class Artist(Base):
- """"""
- __tablename__ = "artists"
-
- id = Column(Integer, primary_key=True)
- name = Column(String)
-
- class Album(Base):
- """"""
- __tablename__ = "albums"
-
- id = Column(Integer, primary_key=True)
- title = Column(String)
- release_date = Column(Date)
- publisher = Column(String)
- media_type = Column(String)
-
- artist_id = Column(Integer, ForeignKey("artists.id"))
- artist = relationship("Artist", backref=backref("albums", order_by=id))
-
-# create tables
-Base.metadata.create_all(engine)
\ No newline at end of file
diff --git a/Chapter 35 - virtualenv/readme.txt b/Chapter 35 - virtualenv/readme.txt
deleted file mode 100644
index 20f3899..0000000
--- a/Chapter 35 - virtualenv/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-This chapter is meant to be done in a terminal or console.
\ No newline at end of file
diff --git a/Chapter 36 - creating modules and packages/arithmetic2.py b/Chapter 36 - creating modules and packages/arithmetic2.py
deleted file mode 100644
index a77010c..0000000
--- a/Chapter 36 - creating modules and packages/arithmetic2.py
+++ /dev/null
@@ -1,28 +0,0 @@
-def add(x, y):
- return x + y
-
-def division(x, y):
- return x / y
-
-def multiply(x, y):
- return x * y
-
-def subtract(x, y):
- return x - y
-
-if __name__ == "__main__":
- import sys
- print(sys.argv)
- v = sys.argv[1].lower()
- valOne = int(sys.argv[2])
- valTwo = int(sys.argv[3])
- if v == "a":
- print(add(valOne, valTwo))
- elif v == "d":
- print(division(valOne, valTwo))
- elif v == "m":
- print(multiply(valOne, valTwo))
- elif v == "s":
- print(subtract(valOne, valTwo))
- else:
- pass
\ No newline at end of file
diff --git a/Chapter 36 - creating modules and packages/modify_path.py b/Chapter 36 - creating modules and packages/modify_path.py
deleted file mode 100644
index a51d621..0000000
--- a/Chapter 36 - creating modules and packages/modify_path.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import sys
-
-# modify this path to match your environment
-sys.path.append('C:\Users\mdriscoll\Documents')
-
-import mymath
-
-print(mymath.add(4,5))
-print(mymath.division(4, 2))
-print(mymath.multiply(10, 5))
-print(mymath.squareroot(48))
\ No newline at end of file
diff --git a/Chapter 36 - creating modules and packages/mymath/__init__.py b/Chapter 36 - creating modules and packages/mymath/__init__.py
deleted file mode 100644
index 81646bb..0000000
--- a/Chapter 36 - creating modules and packages/mymath/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# outer __init__.py
-from . add import add
-from . divide import division
-from . multiply import multiply
-from . subtract import subtract
-from .adv.sqrt import squareroot
\ No newline at end of file
diff --git a/Chapter 36 - creating modules and packages/mymath/adv/sqrt.py b/Chapter 36 - creating modules and packages/mymath/adv/sqrt.py
deleted file mode 100644
index 263e5b3..0000000
--- a/Chapter 36 - creating modules and packages/mymath/adv/sqrt.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# sqrt.py
-import math
-
-def squareroot(n):
- return math.sqrt(n)
\ No newline at end of file
diff --git a/Chapter 36 - creating modules and packages/mymath/divide.py b/Chapter 36 - creating modules and packages/mymath/divide.py
deleted file mode 100644
index ba34cf0..0000000
--- a/Chapter 36 - creating modules and packages/mymath/divide.py
+++ /dev/null
@@ -1,2 +0,0 @@
-def division(x, y):
- return x / y
\ No newline at end of file
diff --git a/Chapter 36 - creating modules and packages/setup.py b/Chapter 36 - creating modules and packages/setup.py
deleted file mode 100644
index a514839..0000000
--- a/Chapter 36 - creating modules and packages/setup.py
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env python
-from setuptools import setup
-
-# This setup is suitable for "python setup.py develop".
-setup(name='mymath',
- version='0.1',
- description='A silly math package',
- author='Mike Driscoll',
- author_email='mike@mymath.org',
- url='http://www.mymath.org/',
- packages=['mymath', 'mymath.adv'],
- )
\ No newline at end of file
diff --git a/Chapter 37 - add your code to pypi/.pypirc b/Chapter 37 - add your code to pypi/.pypirc
deleted file mode 100644
index 645ef74..0000000
--- a/Chapter 37 - add your code to pypi/.pypirc
+++ /dev/null
@@ -1,14 +0,0 @@
-[distutils]
-index-servers=
- pypi
- test
-
-[test]
-repository = https://testpypi.python.org/pypi
-username = richard
-password =
-
-[pypi]
-repository = http://pypi.python.org/pypi
-username = richard
-password =
\ No newline at end of file
diff --git a/Chapter 37 - add your code to pypi/setup.py b/Chapter 37 - add your code to pypi/setup.py
deleted file mode 100644
index 22b6855..0000000
--- a/Chapter 37 - add your code to pypi/setup.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from distutils.core import setup
-
-setup(name='mymath',
- version='0.1',
- packages=['mymath', 'mymath.adv'],
- )
\ No newline at end of file
diff --git a/Chapter 37 - add your code to pypi/setup2.py b/Chapter 37 - add your code to pypi/setup2.py
deleted file mode 100644
index 1137346..0000000
--- a/Chapter 37 - add your code to pypi/setup2.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from distutils.core import setup
-
-setup(name='mymath',
- version='0.1',
- description='A silly math package',
- author='Mike Driscoll',
- author_email='mike@mymath.org',
- url='http://www.mymath.org/',
- packages=['mymath', 'mymath.adv'],
- )
\ No newline at end of file
diff --git a/Chapter 38 - Python eggs/setup.py b/Chapter 38 - Python eggs/setup.py
deleted file mode 100644
index bc88077..0000000
--- a/Chapter 38 - Python eggs/setup.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from setuptools import setup, find_packages
-
-setup(
- name = "mymath",
- version = "0.1",
- packages = find_packages()
- )
\ No newline at end of file
diff --git a/Chapter 39 - Python wheels/readme.txt b/Chapter 39 - Python wheels/readme.txt
deleted file mode 100644
index 20f3899..0000000
--- a/Chapter 39 - Python wheels/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-This chapter is meant to be done in a terminal or console.
\ No newline at end of file
diff --git a/Chapter 4 - Conditionals/conditionals.py b/Chapter 4 - Conditionals/conditionals.py
deleted file mode 100644
index b39d867..0000000
--- a/Chapter 4 - Conditionals/conditionals.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# a simple if statement
-if 2 > 1:
- print("This is a True statement!")
-
-# another simple if statement
-var1 = 1
-var2 = 3
-if var1 > var2:
- print("This is also True")
\ No newline at end of file
diff --git a/Chapter 40 - py2exe/advanced_setup.py b/Chapter 40 - py2exe/advanced_setup.py
deleted file mode 100644
index 7bbce7f..0000000
--- a/Chapter 40 - py2exe/advanced_setup.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from distutils.core import setup
-import py2exe
-
-includes = []
-excludes = ['_gtkagg', '_tkagg', 'bsddb', 'curses', 'email', 'pywin.debugger',
- 'pywin.debugger.dbgcon', 'pywin.dialogs', 'tcl',
- 'Tkconstants', 'Tkinter']
-packages = []
-dll_excludes = ['libgdk-win32-2.0-0.dll', 'libgobject-2.0-0.dll', 'tcl84.dll',
- 'tk84.dll']
-
-setup(
- options = {"py2exe": {"compressed": 2,
- "optimize": 2,
- "includes": includes,
- "excludes": excludes,
- "packages": packages,
- "dll_excludes": dll_excludes,
- "bundle_files": 3,
- "dist_dir": "dist",
- "xref": False,
- "skip_archive": False,
- "ascii": False,
- "custom_boot_script": '',
- }
- },
- windows=['sampleApp.py']
- )
\ No newline at end of file
diff --git a/Chapter 40 - py2exe/sampleApp.py b/Chapter 40 - py2exe/sampleApp.py
deleted file mode 100644
index 494cd42..0000000
--- a/Chapter 40 - py2exe/sampleApp.py
+++ /dev/null
@@ -1,56 +0,0 @@
-import wx
-
-class DemoPanel(wx.Panel):
- """"""
- def __init__(self, parent):
- """Constructor"""
- wx.Panel.__init__(self, parent)
-
- labels = ["Name", "Address", "City", "State", "Zip",
- "Phone", "Email", "Notes"]
-
- mainSizer = wx.BoxSizer(wx.VERTICAL)
- lbl = wx.StaticText(self, label="Please enter your information here:")
- lbl.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD))
- mainSizer.Add(lbl, 0, wx.ALL, 5)
- for lbl in labels:
- sizer = self.buildControls(lbl)
- mainSizer.Add(sizer, 1, wx.EXPAND)
- self.SetSizer(mainSizer)
- mainSizer.Layout()
-
- def buildControls(self, label):
- """
- Put the widgets together
- """
- sizer = wx.BoxSizer(wx.HORIZONTAL)
- size = (80,40)
- font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
- lbl = wx.StaticText(self, label=label, size=size)
- lbl.SetFont(font)
- sizer.Add(lbl, 0, wx.ALL|wx.CENTER, 5)
- if label != "Notes":
- txt = wx.TextCtrl(self, name=label)
- else:
- txt = wx.TextCtrl(self, style=wx.TE_MULTILINE, name=label)
- sizer.Add(txt, 1, wx.ALL, 5)
- return sizer
-
-class DemoFrame(wx.Frame):
- """
- Frame that holds all other widgets
- """
-
- def __init__(self):
- """Constructor"""
- wx.Frame.__init__(self, None, wx.ID_ANY,
- "Py2Exe Tutorial",
- size=(600,400)
- )
- panel = DemoPanel(self)
- self.Show()
-
-if __name__ == "__main__":
- app = wx.App(False)
- frame = DemoFrame()
- app.MainLoop()
\ No newline at end of file
diff --git a/Chapter 40 - py2exe/setup.py b/Chapter 40 - py2exe/setup.py
deleted file mode 100644
index 301f2a8..0000000
--- a/Chapter 40 - py2exe/setup.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from distutils.core import setup
-import py2exe
-
-setup(windows=['sampleApp.py'])
\ No newline at end of file
diff --git a/Chapter 41 - bbfreeze/bb_setup.py b/Chapter 41 - bbfreeze/bb_setup.py
deleted file mode 100644
index cd416e5..0000000
--- a/Chapter 41 - bbfreeze/bb_setup.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# bb_setup.py
-from bbfreeze import Freezer
-
-f = Freezer(distdir="bb-binary")
-f.addScript("sampleApp.py")
-f()
\ No newline at end of file
diff --git a/Chapter 41 - bbfreeze/bb_setup2.py b/Chapter 41 - bbfreeze/bb_setup2.py
deleted file mode 100644
index 0a64a7c..0000000
--- a/Chapter 41 - bbfreeze/bb_setup2.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# bb_setup2.py
-from bbfreeze import Freezer
-
-includes = []
-excludes = ['_gtkagg', '_tkagg', 'bsddb', 'curses', 'email', 'pywin.debugger',
- 'pywin.debugger.dbgcon', 'pywin.dialogs', 'tcl',
- 'Tkconstants', 'Tkinter']
-
-bbFreeze_Class = Freezer('dist', includes=includes, excludes=excludes)
-
-bbFreeze_Class.addScript("sampleApp.py", gui_only=True)
-
-bbFreeze_Class.use_compression = 0
-bbFreeze_Class.include_py = True
-bbFreeze_Class()
\ No newline at end of file
diff --git a/Chapter 41 - bbfreeze/config_1.py b/Chapter 41 - bbfreeze/config_1.py
deleted file mode 100644
index a3bc2e6..0000000
--- a/Chapter 41 - bbfreeze/config_1.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# config_1.py
-import configobj
-
-def createConfig(configFile):
- """
- Create the configuration file
- """
- config = configobj.ConfigObj()
- inifile = configFile
- config.filename = inifile
- config['server'] = "http://www.google.com"
- config['username'] = "mike"
- config['password'] = "dingbat"
- config['update interval'] = 2
- config.write()
-
-def getConfig(configFile):
- """
- Open the config file and return a configobj
- """
- return configobj.ConfigObj(configFile)
-
-def createConfig2(path):
- """
- Create a config file
- """
- config = configobj.ConfigObj()
- config.filename = path
- config["Sony"] = {}
- config["Sony"]["product"] = "Sony PS3"
- config["Sony"]["accessories"] = ['controller', 'eye', 'memory stick']
- config["Sony"]["retail price"] = "$400"
- config.write()
-
-if __name__ == "__main__":
- createConfig2("sampleConfig2.ini")
\ No newline at end of file
diff --git a/Chapter 41 - bbfreeze/sampleApp.py b/Chapter 41 - bbfreeze/sampleApp.py
deleted file mode 100644
index 494cd42..0000000
--- a/Chapter 41 - bbfreeze/sampleApp.py
+++ /dev/null
@@ -1,56 +0,0 @@
-import wx
-
-class DemoPanel(wx.Panel):
- """"""
- def __init__(self, parent):
- """Constructor"""
- wx.Panel.__init__(self, parent)
-
- labels = ["Name", "Address", "City", "State", "Zip",
- "Phone", "Email", "Notes"]
-
- mainSizer = wx.BoxSizer(wx.VERTICAL)
- lbl = wx.StaticText(self, label="Please enter your information here:")
- lbl.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD))
- mainSizer.Add(lbl, 0, wx.ALL, 5)
- for lbl in labels:
- sizer = self.buildControls(lbl)
- mainSizer.Add(sizer, 1, wx.EXPAND)
- self.SetSizer(mainSizer)
- mainSizer.Layout()
-
- def buildControls(self, label):
- """
- Put the widgets together
- """
- sizer = wx.BoxSizer(wx.HORIZONTAL)
- size = (80,40)
- font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
- lbl = wx.StaticText(self, label=label, size=size)
- lbl.SetFont(font)
- sizer.Add(lbl, 0, wx.ALL|wx.CENTER, 5)
- if label != "Notes":
- txt = wx.TextCtrl(self, name=label)
- else:
- txt = wx.TextCtrl(self, style=wx.TE_MULTILINE, name=label)
- sizer.Add(txt, 1, wx.ALL, 5)
- return sizer
-
-class DemoFrame(wx.Frame):
- """
- Frame that holds all other widgets
- """
-
- def __init__(self):
- """Constructor"""
- wx.Frame.__init__(self, None, wx.ID_ANY,
- "Py2Exe Tutorial",
- size=(600,400)
- )
- panel = DemoPanel(self)
- self.Show()
-
-if __name__ == "__main__":
- app = wx.App(False)
- frame = DemoFrame()
- app.MainLoop()
\ No newline at end of file
diff --git a/Chapter 42 - cx_Freeze/config_1.py b/Chapter 42 - cx_Freeze/config_1.py
deleted file mode 100644
index a3bc2e6..0000000
--- a/Chapter 42 - cx_Freeze/config_1.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# config_1.py
-import configobj
-
-def createConfig(configFile):
- """
- Create the configuration file
- """
- config = configobj.ConfigObj()
- inifile = configFile
- config.filename = inifile
- config['server'] = "http://www.google.com"
- config['username'] = "mike"
- config['password'] = "dingbat"
- config['update interval'] = 2
- config.write()
-
-def getConfig(configFile):
- """
- Open the config file and return a configobj
- """
- return configobj.ConfigObj(configFile)
-
-def createConfig2(path):
- """
- Create a config file
- """
- config = configobj.ConfigObj()
- config.filename = path
- config["Sony"] = {}
- config["Sony"]["product"] = "Sony PS3"
- config["Sony"]["accessories"] = ['controller', 'eye', 'memory stick']
- config["Sony"]["retail price"] = "$400"
- config.write()
-
-if __name__ == "__main__":
- createConfig2("sampleConfig2.ini")
\ No newline at end of file
diff --git a/Chapter 42 - cx_Freeze/sampleApp.py b/Chapter 42 - cx_Freeze/sampleApp.py
deleted file mode 100644
index 494cd42..0000000
--- a/Chapter 42 - cx_Freeze/sampleApp.py
+++ /dev/null
@@ -1,56 +0,0 @@
-import wx
-
-class DemoPanel(wx.Panel):
- """"""
- def __init__(self, parent):
- """Constructor"""
- wx.Panel.__init__(self, parent)
-
- labels = ["Name", "Address", "City", "State", "Zip",
- "Phone", "Email", "Notes"]
-
- mainSizer = wx.BoxSizer(wx.VERTICAL)
- lbl = wx.StaticText(self, label="Please enter your information here:")
- lbl.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD))
- mainSizer.Add(lbl, 0, wx.ALL, 5)
- for lbl in labels:
- sizer = self.buildControls(lbl)
- mainSizer.Add(sizer, 1, wx.EXPAND)
- self.SetSizer(mainSizer)
- mainSizer.Layout()
-
- def buildControls(self, label):
- """
- Put the widgets together
- """
- sizer = wx.BoxSizer(wx.HORIZONTAL)
- size = (80,40)
- font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
- lbl = wx.StaticText(self, label=label, size=size)
- lbl.SetFont(font)
- sizer.Add(lbl, 0, wx.ALL|wx.CENTER, 5)
- if label != "Notes":
- txt = wx.TextCtrl(self, name=label)
- else:
- txt = wx.TextCtrl(self, style=wx.TE_MULTILINE, name=label)
- sizer.Add(txt, 1, wx.ALL, 5)
- return sizer
-
-class DemoFrame(wx.Frame):
- """
- Frame that holds all other widgets
- """
-
- def __init__(self):
- """Constructor"""
- wx.Frame.__init__(self, None, wx.ID_ANY,
- "Py2Exe Tutorial",
- size=(600,400)
- )
- panel = DemoPanel(self)
- self.Show()
-
-if __name__ == "__main__":
- app = wx.App(False)
- frame = DemoFrame()
- app.MainLoop()
\ No newline at end of file
diff --git a/Chapter 42 - cx_Freeze/setup.py b/Chapter 42 - cx_Freeze/setup.py
deleted file mode 100644
index 57c6d69..0000000
--- a/Chapter 42 - cx_Freeze/setup.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# setup.py
-from cx_Freeze import setup, Executable
-
-setup(
- name = "wxSampleApp",
- version = "0.1",
- description = "An example wxPython script",
- executables = [Executable("sampleApp.py")]
-)
\ No newline at end of file
diff --git a/Chapter 42 - cx_Freeze/setup2.py b/Chapter 42 - cx_Freeze/setup2.py
deleted file mode 100644
index 4e954bc..0000000
--- a/Chapter 42 - cx_Freeze/setup2.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from cx_Freeze import setup, Executable
-
-exe = Executable(
- script="sampleApp.py",
- base="Win32GUI",
-)
-
-setup(
- name = "wxSampleApp",
- version = "0.1",
- description = "An example wxPython script",
- executables = [exe]
-)
\ No newline at end of file
diff --git a/Chapter 43 - PyInstaller/config_1.py b/Chapter 43 - PyInstaller/config_1.py
deleted file mode 100644
index a3bc2e6..0000000
--- a/Chapter 43 - PyInstaller/config_1.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# config_1.py
-import configobj
-
-def createConfig(configFile):
- """
- Create the configuration file
- """
- config = configobj.ConfigObj()
- inifile = configFile
- config.filename = inifile
- config['server'] = "http://www.google.com"
- config['username'] = "mike"
- config['password'] = "dingbat"
- config['update interval'] = 2
- config.write()
-
-def getConfig(configFile):
- """
- Open the config file and return a configobj
- """
- return configobj.ConfigObj(configFile)
-
-def createConfig2(path):
- """
- Create a config file
- """
- config = configobj.ConfigObj()
- config.filename = path
- config["Sony"] = {}
- config["Sony"]["product"] = "Sony PS3"
- config["Sony"]["accessories"] = ['controller', 'eye', 'memory stick']
- config["Sony"]["retail price"] = "$400"
- config.write()
-
-if __name__ == "__main__":
- createConfig2("sampleConfig2.ini")
\ No newline at end of file
diff --git a/Chapter 43 - PyInstaller/sampleApp.py b/Chapter 43 - PyInstaller/sampleApp.py
deleted file mode 100644
index 494cd42..0000000
--- a/Chapter 43 - PyInstaller/sampleApp.py
+++ /dev/null
@@ -1,56 +0,0 @@
-import wx
-
-class DemoPanel(wx.Panel):
- """"""
- def __init__(self, parent):
- """Constructor"""
- wx.Panel.__init__(self, parent)
-
- labels = ["Name", "Address", "City", "State", "Zip",
- "Phone", "Email", "Notes"]
-
- mainSizer = wx.BoxSizer(wx.VERTICAL)
- lbl = wx.StaticText(self, label="Please enter your information here:")
- lbl.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD))
- mainSizer.Add(lbl, 0, wx.ALL, 5)
- for lbl in labels:
- sizer = self.buildControls(lbl)
- mainSizer.Add(sizer, 1, wx.EXPAND)
- self.SetSizer(mainSizer)
- mainSizer.Layout()
-
- def buildControls(self, label):
- """
- Put the widgets together
- """
- sizer = wx.BoxSizer(wx.HORIZONTAL)
- size = (80,40)
- font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
- lbl = wx.StaticText(self, label=label, size=size)
- lbl.SetFont(font)
- sizer.Add(lbl, 0, wx.ALL|wx.CENTER, 5)
- if label != "Notes":
- txt = wx.TextCtrl(self, name=label)
- else:
- txt = wx.TextCtrl(self, style=wx.TE_MULTILINE, name=label)
- sizer.Add(txt, 1, wx.ALL, 5)
- return sizer
-
-class DemoFrame(wx.Frame):
- """
- Frame that holds all other widgets
- """
-
- def __init__(self):
- """Constructor"""
- wx.Frame.__init__(self, None, wx.ID_ANY,
- "Py2Exe Tutorial",
- size=(600,400)
- )
- panel = DemoPanel(self)
- self.Show()
-
-if __name__ == "__main__":
- app = wx.App(False)
- frame = DemoFrame()
- app.MainLoop()
\ No newline at end of file
diff --git a/Chapter 44 - Creating an installer/sampleApp.py b/Chapter 44 - Creating an installer/sampleApp.py
deleted file mode 100644
index 494cd42..0000000
--- a/Chapter 44 - Creating an installer/sampleApp.py
+++ /dev/null
@@ -1,56 +0,0 @@
-import wx
-
-class DemoPanel(wx.Panel):
- """"""
- def __init__(self, parent):
- """Constructor"""
- wx.Panel.__init__(self, parent)
-
- labels = ["Name", "Address", "City", "State", "Zip",
- "Phone", "Email", "Notes"]
-
- mainSizer = wx.BoxSizer(wx.VERTICAL)
- lbl = wx.StaticText(self, label="Please enter your information here:")
- lbl.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD))
- mainSizer.Add(lbl, 0, wx.ALL, 5)
- for lbl in labels:
- sizer = self.buildControls(lbl)
- mainSizer.Add(sizer, 1, wx.EXPAND)
- self.SetSizer(mainSizer)
- mainSizer.Layout()
-
- def buildControls(self, label):
- """
- Put the widgets together
- """
- sizer = wx.BoxSizer(wx.HORIZONTAL)
- size = (80,40)
- font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
- lbl = wx.StaticText(self, label=label, size=size)
- lbl.SetFont(font)
- sizer.Add(lbl, 0, wx.ALL|wx.CENTER, 5)
- if label != "Notes":
- txt = wx.TextCtrl(self, name=label)
- else:
- txt = wx.TextCtrl(self, style=wx.TE_MULTILINE, name=label)
- sizer.Add(txt, 1, wx.ALL, 5)
- return sizer
-
-class DemoFrame(wx.Frame):
- """
- Frame that holds all other widgets
- """
-
- def __init__(self):
- """Constructor"""
- wx.Frame.__init__(self, None, wx.ID_ANY,
- "Py2Exe Tutorial",
- size=(600,400)
- )
- panel = DemoPanel(self)
- self.Show()
-
-if __name__ == "__main__":
- app = wx.App(False)
- frame = DemoFrame()
- app.MainLoop()
\ No newline at end of file
diff --git a/Chapter 5 - Loops/for_loops.py b/Chapter 5 - Loops/for_loops.py
deleted file mode 100644
index 71fc156..0000000
--- a/Chapter 5 - Loops/for_loops.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# a basic for loop
-for number in range(5):
- print(number)
-
-# you can also write the above like this
-for number in [0, 1, 2, 3, 4]:
- print(number)
-
-# this is how to loop over the keys in a dict
-a_dict = {"one":1, "two":2, "three":3}
-for key in a_dict:
- print(key)
-
-# sort the keys before looping over them
-a_dict = {1:"one", 2:"two", 3:"three"}
-keys = a_dict.keys()
-sorted(keys)
-for key in keys:
- print(key)
-
-# Let's use a conditional to print out only even numbers
-for number in range(10):
- if number % 2 == 0:
- print(number)
-
-# using the else statement
-my_list = [1, 2, 3, 4, 5]
-for i in my_list:
- if i == 3:
- print("Item found!")
- break
- print(i)
-else:
- print("Item not found!")
\ No newline at end of file
diff --git a/Chapter 5 - Loops/while_loops.py b/Chapter 5 - Loops/while_loops.py
deleted file mode 100644
index e2d21d5..0000000
--- a/Chapter 5 - Loops/while_loops.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# a simple while loop
-i = 0
-while i < 10:
- print(i)
- i = i + 1
-
-# this is how to break out of a loop
-while i < 10:
- print(i)
- if i == 5:
- break
- i += 1
-
-# an example of break and continue
-i = 0
-while i < 10:
- if i == 3:
- i += 1
- continue
-
- print(i)
-
- if i == 5:
- break
- i += 1
\ No newline at end of file
diff --git a/Chapter 6 - Comprehensions/comprehensions.py b/Chapter 6 - Comprehensions/comprehensions.py
deleted file mode 100644
index e05a5c3..0000000
--- a/Chapter 6 - Comprehensions/comprehensions.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# a simple list comprehension
-x = [i for i in range(5)]
-
-# turn a list of strings into a list of ints
-x = ['1', '2', '3', '4', '5']
-y = [int(i) for i in x]
-
-# strip off all the leading or ending white space
-myStrings = [s.strip() for s in myStringList]
-
-# how to turn a list of lists into one list (flattening)
-vec = [[1,2,3], [4,5,6], [7,8,9]]
-flat_vec = [num for elem in vec for num in elem]
-
-# a simple dict comprehension
-print( {i: str(i) for i in range(5)} )
-
-# swapping keys and values with a dict comprehension
-my_dict = {1:"dog", 2:"cat", 3:"hamster"}
-print( {value:key for key, value in my_dict.items()} )
-
-# turn a list into a set using a set comprehension
-my_list = [1, 2, 2, 3, 4, 5, 5, 7, 8]
-my_set = {x for x in my_list}
\ No newline at end of file
diff --git a/Chapter 7 - Exceptions/exceptions.py b/Chapter 7 - Exceptions/exceptions.py
deleted file mode 100644
index ba8e8c3..0000000
--- a/Chapter 7 - Exceptions/exceptions.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# raise a ZeroDivisionError exception
-try:
- 1 / 0
-except ZeroDivisionError:
- print("You cannot divide by zero!")
-
-# this is known as a "bare except"
-try:
- 1 / 0
-except:
- print("You cannot divide by zero!")
-
-# let's raise a KeyError
-my_dict = {"a":1, "b":2, "c":3}
-try:
- value = my_dict["d"]
-except KeyError:
- print("That key does not exist!")
-
-# now let's raise an IndexError
-my_list = [1, 2, 3, 4, 5]
-try:
- my_list[6]
-except IndexError:
- print("That index is not in the list!")
-
-# the following shows how to catch multiple exceptions
-my_dict = {"a":1, "b":2, "c":3}
-try:
- value = my_dict["d"]
-except IndexError:
- print("This index does not exist!")
-except KeyError:
- print("This key is not in the dictionary!")
-except:
- print("Some other error occurred!")
-
-# here's a shorter method of catching multiple exceptions
-try:
- value = my_dict["d"]
-except (IndexError, KeyError):
- print("An IndexError or KeyError occurred!")
-
-# here is an example of the "finally" statement
-# note: the statement following finally always runs
-my_dict = {"a":1, "b":2, "c":3}
-try:
- value = my_dict["d"]
-except KeyError:
- print("A KeyError occurred!")
-finally:
- print("The finally statement has executed!")
-
-# here we learn how to use the "else" statement
-# note: else only runs when no errors occur
-my_dict = {"a":1, "b":2, "c":3}
-try:
- value = my_dict["a"]
-except KeyError:
- print("A KeyError occurred!")
-else:
- print("No error occurred!")
-
-# this last example demonstrates both else and finally
-my_dict = {"a":1, "b":2, "c":3}
-try:
- value = my_dict["a"]
-except KeyError:
- print("A KeyError occurred!")
-else:
- print("No error occurred!")
-finally:
- print("The finally statement ran!")
\ No newline at end of file
diff --git a/Chapter 8 - Working with Files/catching_errors.py b/Chapter 8 - Working with Files/catching_errors.py
deleted file mode 100644
index b59d424..0000000
--- a/Chapter 8 - Working with Files/catching_errors.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# catching errors the old school way
-try:
- file_handler = open("test.txt")
- for line in file_handler:
- print(line)
-except IOError:
- print("An IOError has occurred!")
-finally:
- file_handler.close()
-
-# catching errors when using the with operator
-try:
- with open("test.txt") as file_handler:
- for line in file_handler:
- print(line)
-except IOError:
- print("An IOError has occurred!"
\ No newline at end of file
diff --git a/Chapter 8 - Working with Files/file_io.py b/Chapter 8 - Working with Files/file_io.py
deleted file mode 100644
index 4a0ac24..0000000
--- a/Chapter 8 - Working with Files/file_io.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# open a file that is in the same folder as this script
-handle = open("test.txt")
-
-# open a file by specifying its path
-handle = open(r"C:\Users\mike\py101book\data\test.txt", "r")
-
-# open the file in read-only binary mode
-handle = open("test.pdf", "rb")
\ No newline at end of file
diff --git a/Chapter 8 - Working with Files/open_and_close.py b/Chapter 8 - Working with Files/open_and_close.py
deleted file mode 100644
index 947b113..0000000
--- a/Chapter 8 - Working with Files/open_and_close.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# open a file in read-only mode
-handle = open("test.txt", "r")
-# read the data
-data = handle.read()
-# print it out
-print(data)
-# close the file
-handle.close()
\ No newline at end of file
diff --git a/Chapter 8 - Working with Files/open_and_close2.py b/Chapter 8 - Working with Files/open_and_close2.py
deleted file mode 100644
index ebb8872..0000000
--- a/Chapter 8 - Working with Files/open_and_close2.py
+++ /dev/null
@@ -1,4 +0,0 @@
-handle = open("test.txt", "r")
-data = handle.readline() # read just one line
-print(data)
-handle.close()
\ No newline at end of file
diff --git a/Chapter 8 - Working with Files/open_and_close3.py b/Chapter 8 - Working with Files/open_and_close3.py
deleted file mode 100644
index 90b7a15..0000000
--- a/Chapter 8 - Working with Files/open_and_close3.py
+++ /dev/null
@@ -1,4 +0,0 @@
-handle = open("test.txt", "r")
-data = handle.readlines() # read ALL the lines!
-print(data)
-handle.close()
\ No newline at end of file
diff --git a/Chapter 8 - Working with Files/open_with.py b/Chapter 8 - Working with Files/open_with.py
deleted file mode 100644
index 2ea04a7..0000000
--- a/Chapter 8 - Working with Files/open_with.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# open and read the file using the with operator
-with open("test.txt") as file_handler:
- for line in file_handler:
- print(line)
\ No newline at end of file
diff --git a/Chapter 8 - Working with Files/read_in_chunks.py b/Chapter 8 - Working with Files/read_in_chunks.py
deleted file mode 100644
index ee61380..0000000
--- a/Chapter 8 - Working with Files/read_in_chunks.py
+++ /dev/null
@@ -1,6 +0,0 @@
-handle = open("test.txt", "r")
-while True:
- data = handle.read(1024)
- print(data)
- if not data:
- break
\ No newline at end of file
diff --git a/Chapter 8 - Working with Files/read_line_by_line.py b/Chapter 8 - Working with Files/read_line_by_line.py
deleted file mode 100644
index 9e3a79b..0000000
--- a/Chapter 8 - Working with Files/read_line_by_line.py
+++ /dev/null
@@ -1,4 +0,0 @@
-handle = open("test.txt", "r")
-for line in handle:
- print(line)
-handle.close()
\ No newline at end of file
diff --git a/Chapter 8 - Working with Files/test.txt b/Chapter 8 - Working with Files/test.txt
deleted file mode 100644
index 6641cea..0000000
--- a/Chapter 8 - Working with Files/test.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a test file
-line 2
-line 3
-this line intentionally left blank
\ No newline at end of file
diff --git a/Chapter 8 - Working with Files/write_file.py b/Chapter 8 - Working with Files/write_file.py
deleted file mode 100644
index f410841..0000000
--- a/Chapter 8 - Working with Files/write_file.py
+++ /dev/null
@@ -1,3 +0,0 @@
-handle = open("output.txt", "w")
-handle.write("This is a test!")
-handle.close()
\ No newline at end of file
diff --git a/Chapter 9 - Imports/readme.txt b/Chapter 9 - Imports/readme.txt
deleted file mode 100644
index 10768ea..0000000
--- a/Chapter 9 - Imports/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-This chapter was skipped because it just demonstrates different ways of importing modules. The examples in chapter 9 should be practiced in IDLE or a Python editor of your choice.
\ No newline at end of file
diff --git a/README.md b/README.md
index fb0d14a..cdc0491 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,14 @@
-# Python 101 Book Code
+# Python 101, 2nd Edition Book Code
-Code examples from the book, [Python 101](https://leanpub.com/python_101) by Michael Driscoll.
+
+
+Code examples from the book, [Python 101](https://leanpub.com/py101) 2nd Edition by Michael Driscoll.
+
+You can get early access to the book on [Leanpub](https://leanpub.com/py101) as well as all updates as they come out. The book will be finished by **September 2020**.
+
+The first dozen or so chapters will have [Jupyter Notebooks](https://jupyter.org/) rather than simple code examples. You can run the examples in your browser by using this link: [](https://mybinder.org/v2/gh/driscollis/python101code/master). Then navigate to each chapter and open the Jupyter Notebook.
+
+Alternatively, you can download the code (or clone it with Git) and use Jupyter on your own machine. Once you have gotten the code / notebooks from this repo, you will need to [install Jupyter](https://jupyter.org/install). Once installed, you should open up a terminal (or cmd.exe on Windows) and navigate to the folder where your save the code to. Then run `jupyter notebook` in your terminal.
+
+If you are looking for the code for **Python 101**, 1st Edition, they can be found [here](https://github.com/driscollis/Python-101-Community-Edition)
-You can get the book on [Leanpub](https://leanpub.com/python_101) or read it for free at [www.Python101.org](www.Python101.org)
diff --git a/Chapter 36 - creating modules and packages/arithmetic.py b/appendix_b_git/arithmetic.py
similarity index 67%
rename from Chapter 36 - creating modules and packages/arithmetic.py
rename to appendix_b_git/arithmetic.py
index 8ca2008..f49c8db 100644
--- a/Chapter 36 - creating modules and packages/arithmetic.py
+++ b/appendix_b_git/arithmetic.py
@@ -1,11 +1,13 @@
+# arithmetic.py
+
def add(x, y):
return x + y
-def division(x, y):
+def divide(x, y):
return x / y
def multiply(x, y):
return x * y
def subtract(x, y):
- return x - y
\ No newline at end of file
+ return x - y
diff --git a/chapter04_strings/Chapter 4 - Working with Strings.ipynb b/chapter04_strings/Chapter 4 - Working with Strings.ipynb
new file mode 100644
index 0000000..1931c7c
--- /dev/null
+++ b/chapter04_strings/Chapter 4 - Working with Strings.ipynb
@@ -0,0 +1,1210 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 4 - Working with Strings\n",
+ "\n",
+ "You will be using strings very often when you program. A string is a series of letters surrounded by single, double or triple quotes. Python 3 defines string as a \"Text Sequence Type\". You can cast other types to a string using the built-in `str()` function."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Creating Strings\n",
+ "\n",
+ "Here are some examples of creating strings:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "name = 'Mike'\n",
+ "first_name = 'Mike'\n",
+ "last_name = \"Driscoll\"\n",
+ "triple = \"\"\"multi-line\n",
+ "string\"\"\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When you use triple quotes, you may use three double quotes at the beginning and end of the string or three single quotes. Also, note that using triple quotes allows you to create multi-line strings. Any whitespace within the string will also be included.\n",
+ "\n",
+ "Here is an example of converting an integer to a string:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'5'"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "number = 5\n",
+ "str(number)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In Python, backslashes can be used to create escape sequences. Here are a couple of examples:\n",
+ "\n",
+ "* `\\b` - backspace\n",
+ "* `\\n` - line feed\n",
+ "* `\\r` - ASCII carriage return\n",
+ "* `\\t` - tab\n",
+ "\n",
+ "There are several others that you can learn about if you read Python's documentation."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also use backslashes to escape quotes:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "\"This string has a single quote, ', in the middle\""
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'This string has a single quote, \\', in the middle'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## String Methods\n",
+ "\n",
+ "In Python, everything is an object. You will learn how useful this can be in chapter 18 when you learn about introspection. For now, just know that strings have methods (or functions) that you can call on them.\n",
+ "\n",
+ "Here are three examples:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Mike'"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "name = 'mike'\n",
+ "name.capitalize()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'MIKE'"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "name.upper()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'mike'"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'MIke'.lower()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To get a full listing of the methods and attributes that you can access, you can use Python's built-in `dir()` function:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "dir(name)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's do a little exercise where you will learn how to parse out the 2nd word in a string.\n",
+ "\n",
+ "To start, here's a string:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "my_string = 'This is a string of words'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now to get the parts of a string, you can call `.split()`, like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['This', 'is', 'a', 'string', 'of', 'words']"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_string.split()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The result is a `list` of strings. Now normally you would assign this result to a variable, but for demonstration purposes, you can skip that part.\n",
+ "\n",
+ "Instead, since you now know that the result is a string, you can use list slicing to get the second element:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'is'"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'This is a string of words'.split()[1]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Remember, in Python, lists elements start at 0 (zero), so when you tell it you want element 1 (one), that is the second element in the list."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## String Formatting\n",
+ "\n",
+ "String formatting or string substitution is where you have a string that you would like to insert into another string. This is especially useful when you need to do a template, like a form letter. But you will use string substitution a lot for debugging output, printing to standard out and much more.\n",
+ "\n",
+ "Python has three different ways to accomplish string formatting:\n",
+ "\n",
+ "* Using the % Method\n",
+ "* Using `.format()`\n",
+ "* Using formatted string literals (f-strings)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Formatting Strings Using %s (printf-style)\n",
+ "\n",
+ "Using the `%` method is Python's oldest method of string formatting. It is sometimes referred to as \"printf-style string formatting\". If you have used C or C++ in the past, then you may already be familiar with this type of string substitution. For brevity, you will learn the basics of using `%` here.\n",
+ "\n",
+ "The most common use of using the `%` sign is when you would use `%s`, which means convert any Python object to a string using `str()`.\n",
+ "\n",
+ "Here is an example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "My name is Mike\n"
+ ]
+ }
+ ],
+ "source": [
+ "name = 'Mike'\n",
+ "print('My name is %s' % name)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this code, you take the variable `name` and insert it into another string using the special `%s` syntax. To make it work, you need to use `%` outside of the string followed by the string or variable that you want to insert.\n",
+ "\n",
+ "Here is a second example that shows that you can pass in an `int` into a string and have it automatically converted for you:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "You must be at least 18 to continue\n"
+ ]
+ }
+ ],
+ "source": [
+ "age = 18\n",
+ "print('You must be at least %s to continue' % age)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also do string formatting with multiple variables. In fact, there are two ways to do this.\n",
+ "\n",
+ "Here's the first one:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hello Mike. You must be at least 18 to continue!\n"
+ ]
+ }
+ ],
+ "source": [
+ "name = 'Mike'\n",
+ "age = 18\n",
+ "print('Hello %s. You must be at least %i to continue!' % (name, age))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this example, you create two variables and use `%s` and `%i`. The `%i` indicates that you are going to pass an integer. To pass in multiple items, you use the percent sign followed by a tuple of the items to insert.\n",
+ "\n",
+ "You can make this clearer by using names, like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hello Mike. You must be at least 18 to continue!\n"
+ ]
+ }
+ ],
+ "source": [
+ "print('Hello %(name)s. You must be at least %(age)i to continue!' % {'name': name, 'age': age})"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When the argument on the right side of the `%` sign is a dictionary (or another mapping type), then the formats in the string must refer to the parenthesized key in the dictionary. In other words, if you see `%(name)s`, then the dictionary to the right of the `%` must have a `name` key.\n",
+ "\n",
+ "If you do not include all the keys that are required, you will receive an error:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "KeyError",
+ "evalue": "'name'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Hello %(name)s. You must be at least %(age)i to continue!'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m'age'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mage\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mKeyError\u001b[0m: 'name'"
+ ]
+ }
+ ],
+ "source": [
+ "print('Hello %(name)s. You must be at least %(age)i to continue!' % {'age': age})"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "For more information about using the printf-style string formatting, you should see the following link:\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Formatting Strings Using .format()\n",
+ "\n",
+ "Python strings have supported the `.format()` method for a long time. While this book will focus on using f-strings, you will find that `.format()` is still quite popular.\n",
+ "\n",
+ "For full details on how formatting works, see the following:\n",
+ "\n",
+ "\n",
+ "\n",
+ "Let's take a look at a few short examples to see how `.format()` works."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hello Mike. You must be at least 18 to continue!\n"
+ ]
+ }
+ ],
+ "source": [
+ "name = 'Mike'\n",
+ "age = 18\n",
+ "print('Hello {}. You must be at least {} to continue!'.format(name, age))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This example uses positional arguments. Python looks for two instances of `{}` and will insert the variables accordingly. If you do not pass in enough arguments, you will receive an error like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "IndexError",
+ "evalue": "tuple index out of range",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Hello {}. You must be at least {} to continue!'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mage\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mIndexError\u001b[0m: tuple index out of range"
+ ]
+ }
+ ],
+ "source": [
+ "print('Hello {}. You must be at least {} to continue!'.format(age))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This error indicates that you do not have enough items inside the `.format()` call.\n",
+ "\n",
+ "You can also use named arguments in a similar way to the previous section:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hello Mike. You must be at least 18 to continue!\n"
+ ]
+ }
+ ],
+ "source": [
+ "name = 'Mike'\n",
+ "age = 18\n",
+ "print('Hello {name}. You must be at least {age} to continue!'.format(name=name, age=age))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also use repeat a variable multiple times in the string using `.format()`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hello Mike. Why do they call you Mike?\n"
+ ]
+ }
+ ],
+ "source": [
+ "name = 'Mike'\n",
+ "print('Hello {name}. Why do they call you {name}?'.format(name=name))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here you refer to `{name}` twice in the string and you are able to replace both of them using `.format()`.\n",
+ "\n",
+ "If you want, you can also interpolate values using numbers:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hello 18. You must be at least Mike to continue!\n"
+ ]
+ }
+ ],
+ "source": [
+ "print('Hello {1}. You must be at least {0} to continue!'.format(name, age))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Because most things in Python start at 0 (zero), in this example you ended up passing the `age` to `{1}` and the `name` to `{0}`.\n",
+ "\n",
+ "A common coding style when working with `.format()` is to create a formatted string and save it to a variable to be used later:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Hello Mike. You must be at least 18 to continue!'"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "name = 'Mike'\n",
+ "age = 18\n",
+ "greetings = 'Hello {name}. You must be at least {age} to continue!'\n",
+ "greetings.format(name=name, age=age)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This allows you to reuse `greetings` and pass in updated values for `name` and `age` later on in your program.\n",
+ "\n",
+ "You can also specify the string width and alignment:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'left aligned '"
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'{:<20}'.format('left aligned')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "' right aligned'"
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'{:>20}'.format('right aligned')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "' centered '"
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'{:^20}'.format('centered')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Left aligned is the default. The colon (`:`) tells Python that you are going to apply some kind of formatting. In the first example, you are specifying that the string be left aligned and 20 characters wide. The second example is also 20 characters wide, but it is right aligned. Finally the `^` tells Python to center the string within the 20 character string."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If you want to pass in a variable like in the previous examples, here is how you would do that:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "' centered '"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'{name:^20}'.format(name='centered')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note that the `name` must come before the `:` inside of the `{}`.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Formatting Strings with f-strings\n",
+ "\n",
+ "Formatted string literals or f-strings are strings that have an \"f\" at the beginning and curly braces inside of them that contain expressions, much like the ones you saw in the previous section. These expressions tell the f-string about any special processing that needs to be done to the inserted string, such as justification, float precision, etc.\n",
+ "\n",
+ "The f-string was added in Python 3.6. You can read more about it and how it works by checking out PEP 498 here:\n",
+ "\n",
+ "\n",
+ "\n",
+ "The expressions that are contained inside of f-strings are evaluated at runtime. This makes it impossible to use an f-string as a docstring to a function, method or class if it contains an expression. The reason being that docstrings are defined at function definition time.\n",
+ "\n",
+ "Let's go ahead and look at a simple example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Hello Mike. You are 18 years old'"
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "name = 'Mike'\n",
+ "age = 18\n",
+ "f'Hello {name}. You are {age} years old'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here you create the f-string by putting an \"f\" right before the single, double or triple quote that begins your string. Then inside of the string, you use the curly braces, `{}`, to insert variables into your string.\n",
+ "\n",
+ "However, your curly braces must enclose something. If you create an f-string with empty braces, you will get an error:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "SyntaxError",
+ "evalue": "f-string: empty expression not allowed (, line 1)",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m f'Hello {}. You are {} years old'\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m f-string: empty expression not allowed\n"
+ ]
+ }
+ ],
+ "source": [
+ "f'Hello {}. You are {} years old'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The f-string can do things that neither `%s` nor `.format()` can do though. Because of the fact that f-strings are evaluated at runtime, you can put any valid Python expression inside of them.\n",
+ "\n",
+ "For example, you could increase the `age` variable:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'22'"
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "age = 20\n",
+ "f'{age+2}'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Or call a method or function:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'mike'"
+ ]
+ },
+ "execution_count": 32,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "name = 'Mike'\n",
+ "f'{name.lower()}'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also access dictionary values directly inside of an f-string:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Hello Tom. You are 40 years old'"
+ ]
+ },
+ "execution_count": 33,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'name': 'Tom', 'age': 40}\n",
+ "f'Hello {sample_dict[\"name\"]}. You are {sample_dict[\"age\"]} years old'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "However, backslashes are not allowed in f-string expressions:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "SyntaxError",
+ "evalue": "f-string expression part cannot include a backslash (, line 1)",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m print(f'My name is {name\\n}')\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m f-string expression part cannot include a backslash\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(f'My name is {name\\n}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "But you can use backslashes outside of the expression in an f-string:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "My name is Mike\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "name = 'Mike'\n",
+ "print(f'My name is {name}\\n')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "One other thing that you can't do is add a comment inside of an expression in an f-string:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "SyntaxError",
+ "evalue": "f-string expression part cannot include '#' (, line 1)",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m f'My name is {name # name of person}'\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m f-string expression part cannot include '#'\n"
+ ]
+ }
+ ],
+ "source": [
+ "f'My name is {name # name of person}'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In Python 3.8, f-strings added support for `=`, which will expand the text of the expression to include the text of the expression plus the equal sign and then the evaluated expression. That sounds kind of complicated, so let's look at an example:\n",
+ "\n",
+ "```python\n",
+ ">>> username = 'jdoe'\n",
+ ">>> f'Your {username=}'\n",
+ "\"Your username='jdoe'\"\n",
+ "```\n",
+ "\n",
+ "This example demonstrates that the text inside of the expression, `username=` is added to the output followed by the actual value of `username` in quotes.\n",
+ "\n",
+ "f-strings are very powerful and extremely useful. They will simplify your code quite a bit if you use them wisely. You should definitely give them a try."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## String Concatenation\n",
+ "\n",
+ "Strings also allow concatenation, which is a fancy word for joining two strings into one.\n",
+ "\n",
+ "To concatenate strings together, you can use the `+` sign:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'My name isMike'"
+ ]
+ },
+ "execution_count": 38,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "first_string = 'My name is'\n",
+ "second_string = 'Mike'\n",
+ "first_string + second_string"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Oops! It looks like the strings merged in a weird way because you forgot to add a space to the end of the `first_string`. You can change it like this:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'My name is Mike'"
+ ]
+ },
+ "execution_count": 39,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "first_string = 'My name is '\n",
+ "second_string = 'Mike'\n",
+ "first_string + second_string"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Another way to merge strings is to use the `.join()` method. The `.join()` method accepts an iterable, such as a list, of strings and joins them together."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'My name is Mike'"
+ ]
+ },
+ "execution_count": 40,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "first_string = 'My name is '\n",
+ "second_string = 'Mike'\n",
+ "''.join([first_string, second_string])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This will make the strings join right next to each other. You could put something inside of the string that you are joining though:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'My name is ***Mike'"
+ ]
+ },
+ "execution_count": 41,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'***'.join([first_string, second_string])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this case, it will join the first string to `***` plus the second string.\n",
+ "\n",
+ "More often than not, you can use an f-string rather than concatenation or `.join()` and the code will be easier to follow."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## String Slicing\n",
+ "\n",
+ "Slicing in strings works in much the same way that it does for Python lists. Let's take the string \"Mike\". The letter \"M\" is at position zero and the letter \"e\" is at position 3.\n",
+ "\n",
+ "If you want to grab characters 0-3, you would use this syntax: `my_string[0:4]`\n",
+ "\n",
+ "What that means is that you want the substring starting at position zero up to but not including position 4.\n",
+ "\n",
+ "Here are a few examples:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'this'"
+ ]
+ },
+ "execution_count": 42,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'this is a string'[0:4]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'this'"
+ ]
+ },
+ "execution_count": 44,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'this is a string'[:4]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'ring'"
+ ]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'this is a string'[-4:]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The first example grabs the first four letters from the string and returns them. If you want to, you can drop the zero as that is the default and use `[:4]` instead, which is what example two does.\n",
+ "\n",
+ "You can also use negative position values. So `[-4:]` means that you want to start at the end of the string and get the last four letters of the string.\n",
+ "\n",
+ "You should play around with slicing on your own and see what other slices you can come up with."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter05_numeric_types/Chapter 5 - Numeric Types.ipynb b/chapter05_numeric_types/Chapter 5 - Numeric Types.ipynb
new file mode 100644
index 0000000..13c3fd4
--- /dev/null
+++ b/chapter05_numeric_types/Chapter 5 - Numeric Types.ipynb
@@ -0,0 +1,259 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 5 - Numeric Types"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Python is a little different than some languages in that it basically only has three built-in numeric types. A built-in data type means that you don't have to do anything to use them other than typing out their name.\n",
+ "\n",
+ "The built-in numeric types are:\n",
+ "\n",
+ "* `int`\n",
+ "* `float`\n",
+ "* `complex`"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Integers\n",
+ "\n",
+ "You can create an integer in two ways in Python. The most common way is to assign an integer to a variable:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "my_integer = 3"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The other way to create an integer is to use the `int` function, like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "my_integer = int(3)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Floats\n",
+ "\n",
+ "A `float` in Python refers to a number that has a decimal point in it. For example, 2.0 is a `float` while 2 is an `int`."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can create a `float` in Python like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "my_float = 2.0"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also create a float like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "my_float = float(2.0)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Complex Numbers\n",
+ "\n",
+ "A complex number has a *real* and an *imaginary* part, which are each a floating-point number. To get each of these parts, let's say you have a variable named `comp`. You can use `comp.real` and `comp.imag` to extract the real and imaginary parts, respectively, from the number."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's look at a quick example using Python's interpreter:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```python\n",
+ ">>> comp = 1 + 2j\n",
+ ">>> type(comp)\n",
+ "\n",
+ ">>> comp.real\n",
+ "1.0\n",
+ ">>> comp.imag\n",
+ "2.0\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also use the `complex()` built-in function to create a complex number:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(10+12j)"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "complex(10, 12)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Numeric Operations\n",
+ "\n",
+ "All the numeric types, with the exception of `complex`, support a set of numeric operations.\n",
+ "\n",
+ "Here is a listing of the operations that you can do:\n",
+ "\n",
+ "|Operation |Result |\n",
+ "|-----------------|--------------------------------------------|\n",
+ "|a + b |The sum of a and b |\n",
+ "|a - b |The difference of a and b |\n",
+ "|a * b |The product of a and b |\n",
+ "|a / b |The quotient of a and b |\n",
+ "|a // b |The floored quotient of a and b |\n",
+ "|a % b |The remainder of `a / b` |\n",
+ "|-a |`a` negated (convert to negative) |\n",
+ "|abs(a) |absolute value of `a` |\n",
+ "|int(a) |`a` converted to integer |\n",
+ "|float(x) |`a` converted to a floating-point number |\n",
+ "|complex(re, im) |A complex number with real and imaginary |\n",
+ "|c.conjugate() |The conjugate of the complex number `c` |\n",
+ "|divmod(a, b) |The pair: (a // b, a % b) |\n",
+ "|pow(x, b) |`a` to the power of `b` |\n",
+ "|a ** b |`a` to the power of `b` |"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "See also [https://docs.python.org/3/library/stdtypes.html](https://docs.python.org/3/library/stdtypes.html)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Augmented Assignment\n",
+ "\n",
+ "Python supports doing some types of arithmetic using a concept called **Augmented Assignment**. This idea was first proposed in PEP 203:\n",
+ "\n",
+ "* "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The syntax allows you to do various arithmetic operations using the following operators:\n",
+ "\n",
+ "`+= -= *= /= %= **= <<= >>= &= ^= |=`\n",
+ "\n",
+ "This syntax is a shortcut for doing common arithmetic in Python. With it you can replace the following code:\n",
+ "\n",
+ "```python\n",
+ ">>> x = 1\n",
+ ">>> x = x + 2\n",
+ ">>> x\n",
+ "3\n",
+ "```\n",
+ "\n",
+ "with this:\n",
+ "\n",
+ "```python\n",
+ ">>> x = 1\n",
+ ">>> x += 2\n",
+ ">>> x\n",
+ "3\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter06_lists/Chapter 6 - Learning About Lists.ipynb b/chapter06_lists/Chapter 6 - Learning About Lists.ipynb
new file mode 100644
index 0000000..dbee46c
--- /dev/null
+++ b/chapter06_lists/Chapter 6 - Learning About Lists.ipynb
@@ -0,0 +1,814 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 6 - Learning About Lists"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Creating Lists\n",
+ "\n",
+ "There are several ways to create a `list`. You may construct a list in any of the following ways:\n",
+ "\n",
+ "* Using a pair of square brackets with nothing inside creates an empty list: `[]`\n",
+ "* Using square brackets with comma-separated items: `[1, 2, 3]`\n",
+ "* Using a list comprehension (see Chapter 13 for more information): [x for x in iterable]\n",
+ "* Using the `list()` function: `list(iterable)`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[1, 2, 3]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Or use the `list()` function to create a list:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "list_of_strings = list('abc')\n",
+ "print(list_of_strings)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The last example to look at is how to create empty lists:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "empty_list = []\n",
+ "another_empty_list = list()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## List Methods\n",
+ "\n",
+ "A Python `list` has several methods that you can call. Here is a listing of the methods you can use with a `list`:\n",
+ "\n",
+ "* `append()`\n",
+ "* `clear()`\n",
+ "* `copy()`\n",
+ "* `count()`\n",
+ "* `extend()`\n",
+ "* `index()`\n",
+ "* `insert()`\n",
+ "* `pop()`\n",
+ "* `remove()`\n",
+ "* `reverse()`\n",
+ "* `sort()`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "my_list = list('abcc')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list.count('c')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list.index('c')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list.index('a')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "['c', 'c', 'b', 'a']\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = list('abcc')\n",
+ "my_list.reverse()\n",
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Adding to a List\n",
+ "\n",
+ "There are three `list` methods that you can use to add to a list. They are as follows:\n",
+ "\n",
+ "* `append()`\n",
+ "* `extend()`\n",
+ "* `insert()`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "['a', 'b', 'c', 'c']\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = list('abcc')\n",
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "['a', 'b', 'c', 'c', 1]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list.append(1)\n",
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "5"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(my_list)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "['first', 'a', 'b', 'c', 'c', 1]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list.insert(0, 'first')\n",
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "There are two other ways to add items to a `list`. You can add an iterable to a `list` using `extend()`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[1, 2, 3, 4, 5, 6]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "other_list = [4, 5, 6]\n",
+ "my_list.extend(other_list)\n",
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also combine lists using concatenation:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[1, 2, 3, 4, 5, 6]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "other_list = [4, 5, 6]\n",
+ "my_list += other_list\n",
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Accessing and Changing List Elements"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To access an item in a `list`, you need to use square braces and pass in the index of the item that you wish to access. In the example above, you access the first and third elements."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "my_list[0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Lists also support accessing items in reverse by using negative values:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list[-1]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If you try to use an index that does not exist in the `list`, you will get an `IndexError`:\n",
+ "\n",
+ "```python\n",
+ ">>> my_list[-5]\n",
+ "Traceback (most recent call last):\n",
+ " Python Shell, prompt 41, line 1\n",
+ "builtins.IndexError: list index out of range\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Deleting From a List"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Deleting items from a `list` is pretty straight-forward. There are 4 primary methods of removing items from a list:\n",
+ "\n",
+ "* `clear()`\n",
+ "* `pop()`\n",
+ "* `remove()`\n",
+ "* `del`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "my_list.clear()\n",
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If you would rather remove individual items, then you should check out `pop()` or `remove()`. Let's start with `pop()`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "my_list.pop()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[1, 2]\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`remove()` will delete the first instance of the passed in item"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[1, 3]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "my_list.remove(2)\n",
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Sorting a List"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Lists in Python can be sorted. You can use the built-in `sort()` method to sort a `list` in-place or you can use Python's `sorted()` function."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[1, 2, 4, 9, 10, 23]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [4, 10, 2, 1, 23, 9]\n",
+ "my_list.sort()\n",
+ "print(my_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "A common misconception with Python is that if you call `sort()`, you can assign the result to a variable, like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "None\n"
+ ]
+ }
+ ],
+ "source": [
+ "sorted_list = my_list.sort()\n",
+ "print(sorted_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "However, when you do that, you will see that `sort()` doesn't actually return a sorted list. It always returns `None`.\n",
+ "\n",
+ "Fortunately you can use Python's built-in `sorted()` method for this too:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[1, 2, 4, 9, 10, 23]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [4, 10, 2, 1, 23, 9]\n",
+ "sorted_list = sorted(my_list)\n",
+ "print(sorted_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also sort in reverse using `sorted()`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[23, 10, 9, 4, 2, 1]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [4, 10, 2, 1, 23, 9]\n",
+ "sorted_list = sorted(my_list, reverse=True)\n",
+ "print(sorted_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## List Slicing"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Python lists support the idea of slicing. Slicing a list is done by using square brackets and entering a start and stop value. For example, if you had `my_list[1:3]`, you would be saying that you want to create a new list with the element starting at index one through 3 but not including index 3."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[10, 2]"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list = [4, 10, 2, 1, 23, 9]\n",
+ "my_list[1:3]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[23, 9]"
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list[-2:]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[4, 10, 2]"
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list[:3]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Copying a List\n",
+ "\n",
+ "Occasionally you will want to copy a `list`. One simple way to copy your `list` is to use the `copy` method:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[1, 2, 3]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "new_list = my_list.copy()\n",
+ "print(new_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also copy a list by using this funny syntax:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[1, 2, 3]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "new_list = my_list[:]\n",
+ "print(new_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You could also use Python's `list()` function to copy a list:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[1, 2, 3]\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "new_list = list(my_list)\n",
+ "print(new_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "No matter which method you choose though, whether it by `[:]`, `copy()` or `list()`, all three will do a shallow copy. If you run into weird issues where changing one list affects the copied list, then you should use `deepcopy` method from the `copy` module instead. You will learn about importing modules in chapter 16."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter07_tuples/Chapter 7 - Learning About Tuples.ipynb b/chapter07_tuples/Chapter 7 - Learning About Tuples.ipynb
new file mode 100644
index 0000000..fb5bcac
--- /dev/null
+++ b/chapter07_tuples/Chapter 7 - Learning About Tuples.ipynb
@@ -0,0 +1,327 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 7 - Learning About Tuples\n",
+ "\n",
+ "Tuples are another sequence type in Python. Tuples consist of a number of values that are separated by commas. A tuple is immutable whereas a list is not. Immutable means that the tuple has a fixed value and cannot change. You cannot add, delete or modify items in a tuple. Immutable objects are useful when you need a constant hash value. The most popular example is the key to a Python dictionary, which you will learn about in **chapter 7**."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Creating Tuples\n",
+ "\n",
+ "You can create tuples in several different ways. Let's take a look:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "tuple"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a_tuple = (4, 5)\n",
+ "type(a_tuple)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also cast a `list` into a `tuple` using the `tuple()` function:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "tuple"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a_tuple = tuple(['1', '2', '3'])\n",
+ "type(a_tuple)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Working With Tuples\n",
+ "\n",
+ "Tuples actually don't have a lot of ways to work with them due to the fact that they are immutable. If you were you run `dir(tuple())`, you would find that tuples have only two methods:\n",
+ "\n",
+ "* `count()`\n",
+ "* `index()`\n",
+ "\n",
+ "You can use `count()` to find out how many elements match the value that you pass in:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a_tuple = (1, 2, 3, 3)\n",
+ "a_tuple.count(3)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can use `index()` to find the first index of a value:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a_tuple = (1, 2, 3, 3)\n",
+ "a_tuple[2]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's try to modify an element in your `tuple`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "TypeError",
+ "evalue": "'tuple' object does not support item assignment",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma_tuple\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m8\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
+ ]
+ }
+ ],
+ "source": [
+ "a_tuple[0] = 8"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Concatenating Tuples\n",
+ "\n",
+ "Tuples can be concatenated together. However, when you do that, you will end up creating a new tuple:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "4437658264"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a_tuple = (1, 2, 3, 3)\n",
+ "id(a_tuple)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "4434750920"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a_tuple = a_tuple + (6, 7)\n",
+ "id(a_tuple)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Special Case Tuples\n",
+ "\n",
+ "There are two special-case tuples. A `tuple` with zero items and a `tuple` with one item. The reason they are special cases is that the syntax to create them is a little different."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To create an empty tuple, you can do one of the following:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "empty = tuple()\n",
+ "len(empty)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "also_empty = ()\n",
+ "len(also_empty)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now let's create a `tuple` with a single element:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "single = 2, # <-- Note the comma on the end\n",
+ "len(single)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter08_dictionaries/Chapter 8 - Learning About Dictionaries.ipynb b/chapter08_dictionaries/Chapter 8 - Learning About Dictionaries.ipynb
new file mode 100644
index 0000000..3a01e9d
--- /dev/null
+++ b/chapter08_dictionaries/Chapter 8 - Learning About Dictionaries.ipynb
@@ -0,0 +1,735 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 8 - Learning About Dictionaries\n",
+ "\n",
+ "Dictionaries are another fundamental data type in Python. A dictionary is a key, value pair. Some programming languages refer to them as hash tables. They are described as a *mapping* object that maps hashable values to arbitrary objects.\n",
+ "\n",
+ "A dictionary's keys must be immutable, that is, unable to change. Starting in Python 3.7, dictionaries are ordered. What that means is that when you add a new key, value pair to a dictionary, it remembers what order they were added. Prior to Python 3.7, this was not the case and you could not rely on insertion order."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Creating Dictionaries\n",
+ "\n",
+ "You can create a dictionary in a couple of different ways. The most common method is by placing a comma-separated list `key: value` pairs within curly braces.\n",
+ "\n",
+ "Let's look at an example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also use Python's built-in `dict()` function to create a dictionary. `dict()` will accept a series of keyword arguments (i.e. 1='one', 2='two', etc), a list of tuples or another dictionary.\n",
+ "\n",
+ "Here are a couple of examples:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'one': 1, 'two': 2, 'three': 3}\n"
+ ]
+ }
+ ],
+ "source": [
+ "numbers = dict(one=1, two=2, three=3)\n",
+ "print(numbers)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoes@gmail.com'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "info_list = [('first_name', 'James'), ('last_name', 'Doe'), ('email', 'jdoes@gmail.com')]\n",
+ "info_dict = dict(info_list)\n",
+ "print(info_dict)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The first example uses `dict()` on a series of keyword arguments. You will learn more about these when you learn about functions. You can think of keyword arguments as a series of keywords with the equals sign between them and their value.\n",
+ "\n",
+ "The second example shows you how to create a list that has 3 tuples inside of it. Then you pass that list to `dict()` to convert it to a dictionary."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Accessing Dictionaries\n",
+ "\n",
+ "Dictionaries claim to fame is that they are very fast. You can access any value in a dictionary via the key. If the key is not found, you will receive a `KeyError`.\n",
+ "\n",
+ "Let's take a look at how to use a dictionary:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'James'"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "sample_dict['first_name']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now let's try to get a key that doesn't exist:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "KeyError",
+ "evalue": "'address'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0msample_dict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'address'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mKeyError\u001b[0m: 'address'"
+ ]
+ }
+ ],
+ "source": [
+ "sample_dict['address']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Well that didn't work! You asked the dictionary to give you a value that wasn't in the dictionary!\n",
+ "\n",
+ "You can use Python's `in` keyword to ask if a key is in the dictionary:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'address' in sample_dict"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'first_name' in sample_dict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also check to see if a key is **not** in a dictionary by using Python's `not` keyword:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'first_name' not in sample_dict"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'address' not in sample_dict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Dictionary Methods\n",
+ "\n",
+ "As with most Python data types, dictionaries have special methods you can use. Let's check out some of the dictionarie's methods!\n",
+ "\n",
+ "### d.get(key[, default])\n",
+ "\n",
+ "You can use the `get()` method to get a value. `get()` requires you to specify a key to look for. It optionally allows you to return a default if the key is not found. The default is `None`. Let's take a look:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "None\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(sample_dict.get('address'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Not Found\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(sample_dict.get('address', 'Not Found'))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### d.clear()\n",
+ "\n",
+ "The `clear()` method can be used to remove all the items from the dictionary."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{}"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "sample_dict.clear()\n",
+ "sample_dict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### d.copy()\n",
+ "\n",
+ "If you need to create a shallow copy of the dictionary, then the `copy()` method is for you:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "copied_dict = sample_dict.copy()\n",
+ "copied_dict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If your dictionary has objects or dictionaries inside of it, then you may end up running into logic errors due to this method as changing one dictionary can affect the copy. In those case, you should use Python's `copy` module, which has a `deepcopy` function that will create a completely separate copy for you."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### d.items()\n",
+ "\n",
+ "The `items()` method will return a new view of the dictionary's items:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dict_items([('first_name', 'James'), ('last_name', 'Doe'), ('email', 'jdoe@gmail.com')])"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "sample_dict.items()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### d.keys()\n",
+ "\n",
+ "If you need to get a view of the keys that are in a dictionary, then `keys()` is the method for you. As a view object, it will provide you with a dynamic view of the dictionary's keys. You can iterate over a view and also check membership view the `in` keyword:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dict_keys(['first_name', 'last_name', 'email'])"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "sample_dict.keys()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### d.values()\n",
+ "\n",
+ "The `values()` method also returns a view object, but in this case it is a dynamic view of the dictionary's values:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dict_values(['James', 'Doe', 'jdoe@gmail.com'])"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "sample_dict.values()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### d.pop(key[, default])\n",
+ "\n",
+ "Do you need to remove a key from a dictionary? Then `pop()` is the method for you. The `pop()` method takes a key and an option default string. If you don't set the default and the key is not found, a `KeyError` will be raised.\n",
+ "\n",
+ "Here are some examples:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "KeyError",
+ "evalue": "'something'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0msample_dict\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m'first_name'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'James'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'last_name'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'Doe'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'email'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'jdoe@gmail.com'\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0msample_dict\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'something'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mKeyError\u001b[0m: 'something'"
+ ]
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "sample_dict.pop('something')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Not found!'"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict.pop('something', 'Not found!')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'James'"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict.pop('first_name')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'last_name': 'Doe', 'email': 'jdoe@gmail.com'}"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### d.popitem()\n",
+ "\n",
+ "The `popitem()` method is used to remove and return a `(key, value)` pair from the dictionary. The pairs are returned in last-in first-out (LIFO) order. If called on an empty dictionary, you will receive a `KeyError`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "('email', 'jdoe@gmail.com')"
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "sample_dict.popitem()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Modifying Your Dictionary\n",
+ "\n",
+ "You will need to modify your dictionary from time to time. Let's assume that you need to add a new key, value pair:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'first_name': 'James',\n",
+ " 'last_name': 'Doe',\n",
+ " 'email': 'jdoe@gmail.com',\n",
+ " 'address': '123 Dunn St'}"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "sample_dict['address'] = '123 Dunn St'\n",
+ "sample_dict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To add a new item to a dictionary, you can use the square braces to enter a new key and set it to a value.\n",
+ "\n",
+ "If you need to update a pre-existing key, you can do the following:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'first_name': 'James', 'last_name': 'Doe', 'email': 'jame@doe.com'}"
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "sample_dict['email'] = 'jame@doe.com'\n",
+ "sample_dict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Deleting Items From Your Dictionary\n",
+ "\n",
+ "Sometimes you will need to remove a key from a dictionary. You can use Python's `del` keyword for that:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'first_name': 'James', 'last_name': 'Doe'}"
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "del sample_dict['email']\n",
+ "sample_dict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The other method for removing a key is to use the dictionary's `pop()` method, which was mentioned in the previous section:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'first_name': 'James', 'last_name': 'Doe'}"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sample_dict = {'first_name': 'James', 'last_name': 'Doe', 'email': 'jdoe@gmail.com'}\n",
+ "sample_dict.pop('email')\n",
+ "sample_dict"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When you use `pop()`, it will return the value that is being removed."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter09_sets/Chapter 9 - Learning About Sets.ipynb b/chapter09_sets/Chapter 9 - Learning About Sets.ipynb
new file mode 100644
index 0000000..3ffd92b
--- /dev/null
+++ b/chapter09_sets/Chapter 9 - Learning About Sets.ipynb
@@ -0,0 +1,672 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 9 - Learning About Sets"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "A `set` data type is defined as an \"unordered collection of distinct hashable objects\" according to the Python 3 documentation. You can use a `set` for membership testing, removing duplicates from a sequence and computing mathematical operations, like intersection, union, difference, and symmetric difference."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "There is two types of `set` built-in to the Python language:\n",
+ "\n",
+ "* `set` - which is mutable\n",
+ "* `frozenset` - which is immutable and hashable\n",
+ "\n",
+ "This chapter will focus on `set`.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Creating a Set\n",
+ "\n",
+ "Creating a `set` is pretty straight-forward. You can create them by adding a series of comma-separated objects inside of curly braces or you can pass a sequence to the `set()` built-in function.\n",
+ "\n",
+ "Let's look at an example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'a', 'b', 'c'}"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "my_set"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now let's try creating a `set` using `set()`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{1, 2, 3, 4}"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3, 4]\n",
+ "my_set = set(my_list)\n",
+ "my_set"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Accessing Set Members\n",
+ "\n",
+ "You can check if an item is in a `set` by using Python's `is` operator"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "\"a\" in my_set"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Sets do not allow you to use slicing or the like to access individual members of the `set`. Instead, you would need to iterate over a `set`. You can do that using a loop, such as a `while` loop or a `for` loop. You won't be covering loops until **chapter 12**, but here is the basic syntax using a `for` loop:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "a\n",
+ "b\n",
+ "c\n"
+ ]
+ }
+ ],
+ "source": [
+ "for item in my_set:\n",
+ " print(item)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Changing Items\n",
+ "\n",
+ "Once a `set` is created, you cannot change any of its items. \n",
+ "\n",
+ "However, you can add new items to a `set`. Let's find out how!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Adding Items\n",
+ "\n",
+ "There are two ways to add items to a `set`:\n",
+ "\n",
+ "* `add()`\n",
+ "* `update()`\n",
+ "\n",
+ "Let's try adding an item using `add()`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'a', 'b', 'c', 'd'}"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "my_set.add('d')\n",
+ "my_set"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If you'd like to add multiple items all at once, then you should use `update()` instead:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'a', 'b', 'e', 'd', 'c', 'f'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "my_set.update(['d', 'e', 'f'])\n",
+ "print(my_set)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note that `update()` will take any iterable you pass to it. So it could take a `list`, `tuple` or `set` for example."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Removing Items\n",
+ "\n",
+ "You can remove items from sets in several different ways.\n",
+ "\n",
+ "You can use:\n",
+ "\n",
+ "* `remove()`\n",
+ "* `discard()`\n",
+ "* `pop()`"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Using .remove()\n",
+ "\n",
+ "The `remove()` method will attempt to remove the specified item from a `set`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'b', 'c'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "my_set.remove('a')\n",
+ "print(my_set)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If you happen to ask the `set` to `remove()` an item that does not exist, you will receive an error:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "KeyError",
+ "evalue": "'f'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mmy_set\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m\"a\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"b\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"c\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"c\"\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mmy_set\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mremove\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'f'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mKeyError\u001b[0m: 'f'"
+ ]
+ }
+ ],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "my_set.remove('f')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Using .discard()\n",
+ "\n",
+ "The `discard()` method works in almost exactly the same way as `remove()` in that it will remove the specified item from the `set`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "my_set.discard('b')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The difference with `discard()` though is that it **won't** throw an error if you try to remove an item that doesn't exist:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "my_set.discard('d')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Using .pop()\n",
+ "\n",
+ "The `pop()` method will remove and return an arbitrary item from the `set`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'a'"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "my_set.pop()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'b', 'c'}"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_set"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If your set is empty and you try to `pop()` and item out, you will receive an error"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Clearing or Deleting a Set\n",
+ "\n",
+ "Sometimes you will want to empty a `set` or even completely remove it. \n",
+ "\n",
+ "To empty a `set`, you can use `clear()`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "set()"
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "my_set.clear()\n",
+ "my_set"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If you want to completely remove the `set`, then you can use Python's `del` built-in:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'my_set' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mmy_set\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m\"a\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"b\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"c\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"c\"\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mdel\u001b[0m \u001b[0mmy_set\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mmy_set\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m: name 'my_set' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "my_set = {\"a\", \"b\", \"c\", \"c\"}\n",
+ "del my_set\n",
+ "my_set"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Set Operations\n",
+ "\n",
+ "Sets provide you with some common operations such as:\n",
+ "\n",
+ "* `union()` - Combines two sets and returns a new set\n",
+ "* `intersection()` - Returns a new set with the elements that are common between the two sets\n",
+ "* `difference()` - Returns a new with elements in the set that are not in the other set\n",
+ "\n",
+ "These operations are the most common ones that you will use when working with `sets`. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `union()` method is actually kind of like the `update()` method that you learned about earlier, in that it combines two or more sets together into a new set. However the difference is that it returns a new set rather than updating the original set with new items:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'banana', 'one', 'orange', 'peach', 'three', 'two'}"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "first_set = {'one', 'two', 'three'}\n",
+ "second_set = {'orange', 'banana', 'peach'}\n",
+ "first_set.union(second_set)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'one', 'three', 'two'}"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "first_set"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this example, you create two sets. Then you use `union()` on the first set to add the second set to it. However `union` doesn't update the `set`. It creates a new `set`. If you want to save the new `set`, then you should do the following instead:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'banana', 'one', 'orange', 'peach', 'three', 'two'}"
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "united_set = first_set.union(second_set)\n",
+ "united_set"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `intersection()` method will take two sets and returns a new `set` that contains only the items that are the same in the two sets.\n",
+ "\n",
+ "Let's look at an example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'one'}"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "first_set = {'one', 'two', 'three'}\n",
+ "second_set = {'orange', 'banana', 'peach', 'one'}\n",
+ "first_set.intersection(second_set)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "These two sets have only one item in common: the string \"one\". So when you call `intersection()`, it returns a new `set` with a single element in it. As with `union()`, if you want to save off this new `set`, then you would want to assign the result to a variable"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `difference()` method will return a new set with the elements in the set that are **not** in the other sets. This can be a bit confusing, so let's look at a couple of examples:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'two'}"
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "first_set = {'one', 'two', 'three'}\n",
+ "second_set = {'three', 'four', 'one'}\n",
+ "first_set.difference(second_set)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'four'}"
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "second_set.difference(first_set)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When you call `difference()` on the `first_set`, it returns a `set` with \"two\" as its only element. This is because \"two\" is the only string not found in the `second_set`. When you call `difference()` on the `second_set`, it will return \"four\" because \"four\" is not in the `first_set`.\n",
+ "\n",
+ "There are other methods that you can use with sets, but they are used pretty infrequently. You should go check the documentation for full details on them though should you need to use them."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter10_bool/Chapter 10 - Boolean Operations and None.ipynb b/chapter10_bool/Chapter 10 - Boolean Operations and None.ipynb
new file mode 100644
index 0000000..5e9d744
--- /dev/null
+++ b/chapter10_bool/Chapter 10 - Boolean Operations and None.ipynb
@@ -0,0 +1,517 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 10 - Boolean Operations and None"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You will find that you often need to know if something is `True` or `False`. For example, you might want to know if someone's old enough to create a bank account. If they are, that is usually represented as `True`. These are known as Boolean operations or `bool` for short.\n",
+ "\n",
+ "In Python, `False` maps to 0 (zero) and `True` maps to 1 (one). \n",
+ "\n",
+ "You can easily see this is true using Python's interpreter:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "True == 1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "False == 0"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "False == True"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When you want to compare two values in Python, you need to use `==` instead of a single `=`. A single `=` is known as the assignment operator, as was mentioned in previous chapters. It assigns the value on the right to the variable on the left.\n",
+ "\n",
+ "Let's try to assign a value to `True` and see what happens:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "SyntaxError",
+ "evalue": "can't assign to keyword (, line 1)",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m True = 1\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m can't assign to keyword\n"
+ ]
+ }
+ ],
+ "source": [
+ "True = 1"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Python doesn't allow that!\n",
+ "\n",
+ "You can't assign anything to keywords in Python."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## The bool() Function\n",
+ "\n",
+ "Python also provides the `bool()` function, which allows you to cast other types to `True` or `False`.\n",
+ "\n",
+ "Let's give it a try:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool('1')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool('2')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool('0')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Anything greater than zero should be cast as `True`. But wait, that third one is a string with a zero in it and it returned `True` as well! What's going on here?\n",
+ "\n",
+ "Python has the concept of \"truthy\" and \"falsey\". What that means is that when you are dealing with non-Numeric types, `True` will map to sequences with one or more items and `False` will map to sequences with zero items.\n",
+ "\n",
+ "In this case, the string, `'0'`, has one character, so it maps to `True`. Let's try it with an empty string:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool('')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Since the string is empty (i.e. it has no characters in it), it will cast to `False`. \n",
+ "\n",
+ "Let's see what happens when we try casting some of Python's other types:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool([])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool(['something'])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool({})"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool({1: 'one'})"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool(12)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here you try casting an empty list, a list with one item, an empty dictionary, a dictionary with one key/value pair and an integer. Empty lists and dictionaries map to `False`, while lists and dictionaries with one or more items map to `True`. Integers or floats that are 0 or 0.0 will map to `False`, while any other value will map to `True`."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## What About None?\n",
+ "\n",
+ "Python also has the concept of `None`, which is Python's null value. `None` is a keyword in Python and its data type is the `NoneType`. `None` is not the same as 0, `False` or an empty string. In fact, comparing `None` to anything other than itself will return `False`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "None == 1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "None == []"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "None == ''"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "None == None"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can assign `None` to a variable. Note that all instances of `None` point to the same object though:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "x = None\n",
+ "y = None"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "4304537616"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "id(x)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "4304537616"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "id(y)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When you want to check if a variable is `None`, you should use Python's `is` operator. The reason for that is that `is` will check the variable's identity and verify that it really is `None`. You will learn more about why this is important in the next chapter."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter11_conditionals/Chapter 11 - Conditional Statements.ipynb b/chapter11_conditionals/Chapter 11 - Conditional Statements.ipynb
new file mode 100644
index 0000000..44fd594
--- /dev/null
+++ b/chapter11_conditionals/Chapter 11 - Conditional Statements.ipynb
@@ -0,0 +1,592 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 11 - Conditional Statements\n",
+ "\n",
+ "Developers have to make decisions all the time. How do you approach this problem? Do you use technology X or technology Y? Which programming language(s) can you use to solve this? Your code also sometimes needs to make a decision.\n",
+ "\n",
+ "In this chapter you will learn about the following:\n",
+ "\n",
+ "* Comparison operators\n",
+ "* Creating a simple conditional\n",
+ "* Branching conditional statements\n",
+ "* Nesting conditionals\n",
+ "* Logical operators\n",
+ "* Special operators\n",
+ "\n",
+ "Let's get started by learning about comparison operators!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Comparison Operators\n",
+ "\n",
+ "Before you get started using conditionals, it will be useful to learn about comparison operator. Comparison operators let you ask if something equals something else or if they are greater than or less than a value, etc.\n",
+ "\n",
+ "Python's comparison operators are shown in the following table:\n",
+ "\n",
+ "|Operator |Meaning |\n",
+ "|---------|--------|\n",
+ "|> |Greater than - This is `True` is the left operand is greater than the right|\n",
+ "|< |Less than - This is `True` is the left operand is less than the right one|\n",
+ "|== |Equal to - This is `True` only when both operands are equal|\n",
+ "|!= |Not equal to - This is `True` if the operands are not equal|\n",
+ "|>= |Greater than or equal to - This is `True` when the left operand is greater than or equal to the right|\n",
+ "|<= |Less than or equal to - This is `True` when the left operand is less than or equal to the right|\n",
+ "\n",
+ "Now that you know what comparison operators are available to you in Python, you can start using them!\n",
+ "\n",
+ "Here are some examples:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a = 2\n",
+ "b = 3\n",
+ "a == b"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a > b"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a < b"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a >= b"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a <= b"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a != b"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Creating a Simple Conditional"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Creating a conditional statement allows your code to branch down two different paths. Let's take authentication as an example. If you go to your web mail account on a new computer, you will need to login to view your email. The code for the main page will either load up your email box when you go there or it will prompt you to login.\n",
+ "\n",
+ "You can make a pretty safe bet that the code is using a conditional statement to check and see if you authenticated / authorized to view the email. If you are, it loads your email. If you are not, it loads the login screen.\n",
+ "\n",
+ "Let's create a pretend authentication example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "You are logged in\n"
+ ]
+ }
+ ],
+ "source": [
+ "authenticated = True\n",
+ "if authenticated:\n",
+ " print('You are logged in')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this example, you create a variable called `authenticated` and set it to `True`. Then you create a conditional statement using Python's `if` keyword. A conditional statement in Python takes this form:\n",
+ "\n",
+ "```\n",
+ "if :\n",
+ " # do something here\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Branching Conditional Statements\n",
+ "\n",
+ "You will often need to do different things depending on the answer of a question. So for this hypothetical situation, you want to let the user know when they aren't authenticated so that they will go login.\n",
+ "\n",
+ "To get that to work, you can use the keyword `else`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Please login\n"
+ ]
+ }
+ ],
+ "source": [
+ "authenticated = False\n",
+ "if authenticated:\n",
+ " print('You are logged in')\n",
+ "else:\n",
+ " print('Please login')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "What this code is doing is that if you are `authenticated`, it will print \"You are logged in\" and when you are not, it will print \"Please login\". In a real program, you would have more than just a `print()` statement. You would have code that would redirect the user to the login page or if they were authenticated, it would run code to load their inbox.\n",
+ "\n",
+ "Let's create a new scenario. Let's create a conditional statement that will check your age and let you purchase different items depending on that factor:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "You can buy candy\n"
+ ]
+ }
+ ],
+ "source": [
+ "age = 10\n",
+ "if age < 18:\n",
+ " print('You can buy candy')\n",
+ "elif age < 21:\n",
+ " print('You can purchase tobacco and candy, but not alcohol')\n",
+ "elif age >= 21:\n",
+ " print('You can buy anything!')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this example, you use `if` and `elif`. The keyword, `elif` is short for \"else if\". So what you are doing here is that you are checking the age against different hard-coded values. If the age is less than 18, then the buyer can only buy candy. \n",
+ "\n",
+ "If they are older than 18 but less than 21, they can purchase tobacco. Of course, you shouldn't do that because tobacco is not good for you, but it has an age restriction in most places. Next you check if the buyer's age is greater than or equal to 21. Then they can buy whatever they want.\n",
+ "\n",
+ "You could change the last `elif` to be simply an `else` clause if you wanted to, but Python encourages developers to be explicit in their code and it's easier to understand by using `elif` in this case.\n",
+ "\n",
+ "You can use as many `elif` statements as you need, although it is usually recommended that when you see a long `if/elif` statement, that code probably needs to be reworked."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Nesting Conditionals\n",
+ "\n",
+ "You can put an `if` statement inside of another `if` statement. This is known as nesting.\n",
+ "\n",
+ "Let's look at a silly example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "You buy American\n"
+ ]
+ }
+ ],
+ "source": [
+ "age = 21\n",
+ "car = 'Ford'\n",
+ "if age >= 21:\n",
+ " if car in ['Honda', 'Toyota']:\n",
+ " print('You buy foreign cars')\n",
+ " elif car in ['Ford', 'Chevrolet']:\n",
+ " print('You buy American')\n",
+ "else:\n",
+ " print('You are too young!')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This code has multiple paths that it can take because it depends on two variables: `age` and `car`. If the age is greater than a certain value, then it falls into that code block and will execute the nested `if` statement, which checks the `car` type. If the `age` is less than an arbitrary amount then it will simply print out a message.\n",
+ "\n",
+ "Theoretically, you can nest conditionals any number of times. However, the more nesting you do, the more complicated it is to debug later. You should keep the nesting to only one or two levels deep in most cases.\n",
+ "\n",
+ "Fortunately, logical operators can help alleviate this issue!\n",
+ "\n",
+ "## Logical Operators\n",
+ "\n",
+ "Logical operators allow you to chain multiple expressions together using special keywords.\n",
+ "\n",
+ "Here are the three logical operators that Python supports:\n",
+ "\n",
+ "* `and` - Only `True` is both the operands are true\n",
+ "* `or` - `True` is either of the operands are true\n",
+ "* `not` - `True` is the operand is false\n",
+ "\n",
+ "Let's try using the logical operator, `and` with the example from the last section to flatten your conditional statements:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "You buy American\n"
+ ]
+ }
+ ],
+ "source": [
+ "age = 21\n",
+ "car = 'Ford'\n",
+ "if age >= 21 and car in ['Honda', 'Toyota']:\n",
+ " print('You buy foreign cars')\n",
+ "elif age >= 21 and car in ['Ford', 'Chevrolet']:\n",
+ " print('You buy American')\n",
+ "else:\n",
+ " print('You are too young!')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When you use `and`, both expressions must evaluate to `True` for the code underneath them to execute. So the first conditional checks to see if the age is greater than or equal to 21 AND the car is in the list of Japanese cars. Since it isn't both of those things, you drop down to the `elif` and check those conditions. This time both conditions are `True`, so it prints your car preference.\n",
+ "\n",
+ "Let's see what happens if you change the `and` to an `or`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "You buy foreign cars\n"
+ ]
+ }
+ ],
+ "source": [
+ "age = 21\n",
+ "car = 'Ford'\n",
+ "if age >= 21 or car in ['Honda', 'Toyota']:\n",
+ " print('You buy foreign cars')\n",
+ "elif age >= 21 and car in ['Ford', 'Chevrolet']:\n",
+ " print('You buy American')\n",
+ "else:\n",
+ " print('You are too young!')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Wait a minute! You said your car was \"Ford\", but this code is saying you buy foreign cars! What's going on here?\n",
+ "\n",
+ "Well when you use a logical `or`, that means that the code in that code block will execute if either of the statements are `True`. \n",
+ "\n",
+ "Let's break this down a bit. There are two expressions in `if age >= 21 or car in ['Honda', 'Toyota']`. The first one is `age >= 21`. That evaluates to `True`. As soon as Python sees the `or` and that the first statement is `True`, it evaluates the whole thing as `True`. Either your age is greater than or equal to 21 **or** your car is Ford. Either way, it's true and that code gets executed.\n",
+ "\n",
+ "Using `not` is a bit different. It doesn't really fit with this example at all, so you'll have to write something else. \n",
+ "\n",
+ "Here is one way you could use `not`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3, 4]\n",
+ "5 not in my_list"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this case, you are checking to see if an integer is `not` in a `list`.\n",
+ "\n",
+ "Let's use another authentication example to demonstrate how you might use `not`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "You are not authorized!\n"
+ ]
+ }
+ ],
+ "source": [
+ "ids = [1234, 5678]\n",
+ "my_id = 1001\n",
+ "if my_id not in ids:\n",
+ " print('You are not authorized!')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here you have a set of known ids. These ids could be numeric like they are here or they could be email addresses or something else. Regardless, you need to check if the given id, `my_id` is in your list of known ids. If it's not, then you can let the user know that they are not authorized to continue.\n",
+ "\n",
+ "You can also combine logical operators in a conditional statement. Here's an example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "You are 21 years old with brown hair\n"
+ ]
+ }
+ ],
+ "source": [
+ "hair = 'brown'\n",
+ "age = 21\n",
+ "if age >= 21 and (hair == 'brown' or hair == 'blue'):\n",
+ " print(f'You are {age} years old with {hair} hair')\n",
+ "else:\n",
+ " print(f'You are too young at {age} years old')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Special Operators\n",
+ "\n",
+ "There are some special operators that you can use in conditional expressions. In fact, you already used one of them in the previous section.\n",
+ "\n",
+ "Do you remember which one of these you just used?\n",
+ "\n",
+ "* `is` - `True` when the operands are identical (i.e. have the same id)\n",
+ "* `is not` - `True` when the operands are not identical\n",
+ "* `in` - `True` when the value is in the sequence \n",
+ "* `not in` - `True` when the value is not in the sequence\n",
+ "\n",
+ "You used the last one, `not in` to determine if an id was not in the authorized access list. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can use `in` and `not in` to test if something is in a sequence. Sequences in Python refer to such things as lists, strings, tuples, etc. \n",
+ "\n",
+ "Here's one way you could use this knowledge:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "x is not in yn\n"
+ ]
+ }
+ ],
+ "source": [
+ "valid_chars = 'yn'\n",
+ "char = 'x'\n",
+ "if char in valid_chars:\n",
+ " print(f'{char} is a valid character')\n",
+ "else:\n",
+ " print(f'{char} is not in {valid_chars}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here you check to see if the `char` is in the string of `valid_chars`. If it isn't, it will print out what the valid letters are."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter12_loops/Chapter 12 - Learning About Loops.ipynb b/chapter12_loops/Chapter 12 - Learning About Loops.ipynb
new file mode 100644
index 0000000..963595b
--- /dev/null
+++ b/chapter12_loops/Chapter 12 - Learning About Loops.ipynb
@@ -0,0 +1,629 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 12 - Learning About Loops\n",
+ "\n",
+ "There are many times when you are writing code that you will need to find a way to iterate over something. Perhaps you'll need to iterate over the letters in a string or the objects in a `list`. The process of iterating over something is done via a loop. \n",
+ "\n",
+ "A loop is a programming construct that allows you to iterate over chunks. Those chunks could be the letters in the string or the lines of a file. \n",
+ "\n",
+ "In Python, there are two types of loop constructs:\n",
+ "\n",
+ "* The `for` loop\n",
+ "* The `while` loop"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Creating a `for` Loop\n",
+ "\n",
+ "The `for` loop is the most popular looping construct in Python. A `for` loop is created using the following syntax:\n",
+ "\n",
+ "```python\n",
+ "for x in iterable:\n",
+ "\t# do something\n",
+ "```\n",
+ "\n",
+ "Now the code above does nothing. So let's write a `for` loop that iterates over a list, one item at a time:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "1\n",
+ "2\n",
+ "3\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "for item in my_list:\n",
+ " print(item)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this code, you create a `list` with three integers in it. Next you create a `for` loop that says \"for each item in my list, print out the item\".\n",
+ "\n",
+ "Of course, most of the time you will actually want to do something to the item. For example, you might want to double it:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "2\n",
+ "4\n",
+ "6\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "for item in my_list:\n",
+ " print(f'{item * 2}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Or you might want to only print out only the even numbered items:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "2 is even\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "for item in my_list:\n",
+ " if item % 2 == 0:\n",
+ " print(f'{item} is even')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here you use the modulus operator, `%`, to find the remainder of the item divided by 2. If the remainder is 0, then you know that the item is an even number.\n",
+ "\n",
+ "You can use loops and conditionals and any other Python construct to create complex pieces of code that are only limited by your imagination.\n",
+ "\n",
+ "Let's learn what else you can loop over besides lists."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Looping Over a String\n",
+ "\n",
+ "One of the differences of the `for` loop in Python versus other programming languages is that you can iterate over any sequence. So you can iterate over other data types.\n",
+ "\n",
+ "Let's look at iterating over a string:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "a\n",
+ "b\n",
+ "c\n",
+ "d\n",
+ "e\n",
+ "f\n",
+ "g\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_str = 'abcdefg'\n",
+ "for letter in my_str:\n",
+ " print(letter)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Looping Over a Dictionary\n",
+ "\n",
+ "Python dictionaries also allow looping. By default, when you loop over a dictionary, you will loop over its keys:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "mdriscoll\n",
+ "guido\n",
+ "steve\n"
+ ]
+ }
+ ],
+ "source": [
+ "users = {'mdriscoll': 'password', 'guido': 'python', 'steve': 'guac'}\n",
+ "for user in users:\n",
+ " print(user)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this example, you specify that you want to extract the `user` and the `password` in each iteration. As you might recall, the `items()` method returns a view that is formatted like a list of tuples. Because of that, you can extract each `key: value` pair from this view and print them out.\n",
+ "\n",
+ "This leads us to looping over tuples and getting out individual items from a tuple while looping!\n",
+ "\n",
+ "## Extracting Multiple Values in a Tuple While Looping\n",
+ "\n",
+ "Sometimes you will need to loop over a list of tuples and get each item within the tuple. It sounds kind of weird, but you will find that it is a fairly common programming task.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "1 - banana\n",
+ "2 - apple\n",
+ "3 - pear\n"
+ ]
+ }
+ ],
+ "source": [
+ "list_of_tuples = [(1, 'banana'), (2, 'apple'), (3, 'pear')]\n",
+ "for number, fruit in list_of_tuples:\n",
+ " print(f'{number} - {fruit}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To get this to work, you take advantage of the fact that you know each tuple has two items in it. Since you know the format of the list of tuples ahead of time, you know how to extract the values.\n",
+ "\n",
+ "If you hadn't extracted the items individually from the tuples, you would have ended up with this kind of output:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(1, 'banana')\n",
+ "(2, 'apple')\n",
+ "(3, 'pear')\n"
+ ]
+ }
+ ],
+ "source": [
+ "list_of_tuples = [(1, 'banana'), (2, 'apple'), (3, 'pear')]\n",
+ "for item in list_of_tuples:\n",
+ " print(item)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Using `enumerate` with Loops\n",
+ "\n",
+ "Python comes with a built-in function called `enumerate`. This function takes in an iterator or sequence, like a string or list, and returns a tuple in the form of `(position, item)`. \n",
+ "\n",
+ "This allows you to know the position of the item in the sequence easily while looping over the sequence.\n",
+ "\n",
+ "Here's an example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "0 - a\n",
+ "1 - b\n",
+ "2 - c\n",
+ "3 - d\n",
+ "4 - e\n",
+ "5 - f\n",
+ "6 - g\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_str = 'abcdefg'\n",
+ "for pos, letter in enumerate(my_str):\n",
+ " print(f'{pos} - {letter}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Creating a `while` Loop\n",
+ "\n",
+ "Python has one other type of looping construct that is called the `while` loop. A `while` loop is created with the keyword `while` followed by an expression. In other words, `while` loops will run until a specific condition is met.\n",
+ "\n",
+ "Let's take a look at how these loops work:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "0\n",
+ "1\n",
+ "2\n",
+ "3\n",
+ "4\n",
+ "5\n",
+ "6\n",
+ "7\n",
+ "8\n",
+ "9\n"
+ ]
+ }
+ ],
+ "source": [
+ "count = 0\n",
+ "while count < 10:\n",
+ " print(count)\n",
+ " count += 1"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This loop is formulated in much the same way as a conditional statement. You tell Python that you want the loop to run as long as the `count` is less than 10. Inside of the loop, you print out the current `count` and then you increment the `count` by one.\n",
+ "\n",
+ "If you forgot to increment the `count`, the loop would run until you stop or terminate the Python process. \n",
+ "\n",
+ "You can create an infinite loop by making that mistake or you could do something like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "while True:\n",
+ " print('Program running')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Since the expression is always `True`, this code will print out the string, \"Program running\", forever or until you kill the process."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Breaking Out of a Loop\n",
+ "\n",
+ "Sometimes you want to stop a loop early. For example, you might want to loop until you find something specific. A good use case would be looping over the lines in a text file and stopping when you find the first occurrence of a particular string. \n",
+ "\n",
+ "To stop a loop early, you can use the keyword `break`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "0\n",
+ "1\n",
+ "2\n",
+ "3\n",
+ "count=4\n"
+ ]
+ }
+ ],
+ "source": [
+ "count = 0\n",
+ "while count < 10:\n",
+ " if count == 4:\n",
+ " print(f'count={count}')\n",
+ " break\n",
+ " print(count)\n",
+ " count += 1"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can also use `break` in a `for` loop:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "1 - banana\n",
+ "Apple found!\n"
+ ]
+ }
+ ],
+ "source": [
+ "list_of_tuples = [(1, 'banana'), (2, 'apple'), (3, 'pear')]\n",
+ "for number, fruit in list_of_tuples:\n",
+ " if fruit == 'apple':\n",
+ " print('Apple found!')\n",
+ " break\n",
+ " print(f'{number} - {fruit}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "For this example, you want to break out of the loop when you find an apple. Otherwise you print out what fruit you have found. Since the apple is in the second tuple, you will never get to the third one.\n",
+ "\n",
+ "When you use `break`, the loop will only break out of the innermost loop that the `break` statement is in.\n",
+ "\n",
+ "You can use `break` to help control the flow of the program. In fact, conditional statements along with `break` are known as `flow control` statements.\n",
+ "\n",
+ "## Using `continue`\n",
+ "\n",
+ "The `continue` statement is used for continuing to the next iteration in the loop. You can use `continue` to skip over something.\n",
+ "\n",
+ "Let's write a loop that skips over even numbers:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "3\n",
+ "5\n",
+ "7\n",
+ "9\n",
+ "11\n"
+ ]
+ }
+ ],
+ "source": [
+ "for number in range(2, 12):\n",
+ " if number % 2 == 0:\n",
+ " continue\n",
+ " print(number)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this code, you loop over a range of numbers starting at 2 and ending at 11. For each number in this range, you use the modulus operator, `%`, to get the remainder of the number divided by 2. If the remainder is zero, it's an even number and you use the `continue` statement to continue to the next value in the sequence. This effectively skips even numbers so that you only print out the odd ones.\n",
+ "\n",
+ "You can use clever conditional statements to skip over any number of things in a sequence by using the `continue` statement.\n",
+ "\n",
+ "## Loops and the `else` Statement\n",
+ "\n",
+ "A little known fact about Python loops is that you can add an `else` statement to them like you do with an `if/else` statement. The `else` statement only gets executed when no `break` statement occurs.\n",
+ "\n",
+ "Another way to look at it is that the `else` statement only executes if the loop completes successfully.\n",
+ "\n",
+ "The primary use case for the `else` statement in a loop is for searching for an item in a sequence. You would use the `else` statement to raise an exception if the item was not found.\n",
+ "\n",
+ "Let's look at a quick example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "1\n",
+ "2\n",
+ "3\n",
+ "Number 4 not found\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3]\n",
+ "for number in my_list:\n",
+ " if number == 4:\n",
+ " print('Found number 4!')\n",
+ " break\n",
+ " print(number)\n",
+ "else:\n",
+ " print('Number 4 not found')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This example loops over a `list` of three integers. It looks for the number 4 and will break out of the loop if it is found. If that number is not found, then the `else` statement will execute and let you know.\n",
+ "\n",
+ "Try adding the number 4 to the `list` and then re-run the code:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "1\n",
+ "2\n",
+ "3\n",
+ "Found number 4!\n"
+ ]
+ }
+ ],
+ "source": [
+ "my_list = [1, 2, 3, 4]\n",
+ "for number in my_list:\n",
+ " if number == 4:\n",
+ " print('Found number 4!')\n",
+ " break\n",
+ " print(number)\n",
+ "else:\n",
+ " print('Number 4 not found')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Nesting Loops\n",
+ "\n",
+ "Loops can also be nested inside of each other. There are many reasons to nest loops. One of the most common reasons is to unravel a nested data structure. \n",
+ "\n",
+ "Let's use a nested `list` for your example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "List = ['mike', 12]\n",
+ "Item -> mike\n",
+ "Item -> 12\n",
+ "List = ['jan', 15]\n",
+ "Item -> jan\n",
+ "Item -> 15\n",
+ "List = ['alice', 8]\n",
+ "Item -> alice\n",
+ "Item -> 8\n"
+ ]
+ }
+ ],
+ "source": [
+ "nested = [['mike', 12], ['jan', 15], ['alice', 8]]\n",
+ "for lst in nested:\n",
+ " print(f'List = {lst}')\n",
+ " for item in lst:\n",
+ " print(f'Item -> {item}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The outer loop will extract each nested `list` and print it out as well. Then in the inner loop, your code will extract each item within the nested list and print it out.\n",
+ "\n",
+ "This type of code is especially useful when the nested lists are of varying lengths. You may need to do extra processing on the lists that have extra data or not enough data in them, for example."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter12_loops/for_loop_else.py b/chapter12_loops/for_loop_else.py
new file mode 100644
index 0000000..159cc5a
--- /dev/null
+++ b/chapter12_loops/for_loop_else.py
@@ -0,0 +1,8 @@
+my_list = [1, 2, 3]
+for number in my_list:
+ if number == 4:
+ print('Found number 4!')
+ break
+ print(number)
+else:
+ print('Number 4 not found')
\ No newline at end of file
diff --git a/chapter12_loops/for_loop_else_2.py b/chapter12_loops/for_loop_else_2.py
new file mode 100644
index 0000000..0ca6b8e
--- /dev/null
+++ b/chapter12_loops/for_loop_else_2.py
@@ -0,0 +1,8 @@
+my_list = [1, 2, 3, 4]
+for number in my_list:
+ if number == 4:
+ print('Found number 4!')
+ break
+ print(number)
+else:
+ print('Number 4 not found')
\ No newline at end of file
diff --git a/chapter12_loops/for_loop_with_break.py b/chapter12_loops/for_loop_with_break.py
new file mode 100644
index 0000000..4fb2e9a
--- /dev/null
+++ b/chapter12_loops/for_loop_with_break.py
@@ -0,0 +1,6 @@
+list_of_tuples = [(1, 'banana'), (2, 'apple'), (3, 'pear')]
+for number, fruit in list_of_tuples:
+ if fruit == 'apple':
+ print('Apple found!')
+ break
+ print(f'{number} - {fruit}')
\ No newline at end of file
diff --git a/chapter12_loops/nested_loops.py b/chapter12_loops/nested_loops.py
new file mode 100644
index 0000000..75c3246
--- /dev/null
+++ b/chapter12_loops/nested_loops.py
@@ -0,0 +1,5 @@
+nested = [['mike', 12], ['jan', 15], ['alice', 8]]
+for lst in nested:
+ print(f'List = {lst}')
+ for item in lst:
+ print(f'Item -> {item}')
\ No newline at end of file
diff --git a/chapter12_loops/while_with_break.py b/chapter12_loops/while_with_break.py
new file mode 100644
index 0000000..d024329
--- /dev/null
+++ b/chapter12_loops/while_with_break.py
@@ -0,0 +1,7 @@
+count = 0
+while count < 10:
+ if count == 4:
+ print(f'count={count}')
+ break
+ print(count)
+ count += 1
\ No newline at end of file
diff --git a/chapter13_comprehensions/Chapter 13 - Python Comprehensions.ipynb b/chapter13_comprehensions/Chapter 13 - Python Comprehensions.ipynb
new file mode 100644
index 0000000..1e596cb
--- /dev/null
+++ b/chapter13_comprehensions/Chapter 13 - Python Comprehensions.ipynb
@@ -0,0 +1,460 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 13 - Python Comprehensions\n",
+ "\n",
+ "Python supports a short hand method for creating lists, dictionaries and sets that is known as **comprehensions**. The common use case is that you want to create a new list where each element has had some kind of operation done to them. For example, if you have a `list` of numbers and you want to create a new `list` with all the numbers doubled, you could use a comprehension.\n",
+ "\n",
+ "In this chapter you will learn about:\n",
+ "\n",
+ "* List comprehensions\n",
+ "* Dictionary comprehensions\n",
+ "* Set comprehensions\n",
+ "\n",
+ "## List Comprehensions\n",
+ "\n",
+ "A `list` comprehension allows you to create a list from another sequence, such as a `list` or `dict`. You end up using list-like syntax with a `for` loop on a single line.\n",
+ "\n",
+ "The syntax goes of a list comprehension is having square brackets that contain an expression followed by a `for` loop. This can optionally be followed by zero or more `for` or `if` clauses.\n",
+ "\n",
+ "Here is an example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[1, 2, 3]"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sequence = [1, 2, 3]\n",
+ "new_list = [x for x in sequence]\n",
+ "new_list"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This is equivalent to the following loop:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[1, 2, 3]"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sequence = [1, 2, 3]\n",
+ "new_list = []\n",
+ "for x in sequence:\n",
+ " new_list.append(x)\n",
+ "new_list"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Usually when you use a list comprehension, you want to do something to each of the items in the sequence. For example, let's try doubling each of the items:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[2, 4, 6]"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sequence = [1, 2, 3]\n",
+ "new_list = [x * 2 for x in sequence]\n",
+ "new_list"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Filtering List Comprehensions\n",
+ "\n",
+ "You can add an `if` statement to a list comprehension as a type of filter. Python comes with a built-in `range()` function that takes in an integer. It then returns an iterable `range` object that allows you to get a range of integers starting at 0 and ending at the integer you passed in minus one.\n",
+ "\n",
+ "Here is how it works:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "range(0, 10)"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "range(10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "list(range(10))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can use Python's `list()` function to turn the `range` object into a list of numbers, 0-9.\n",
+ "\n",
+ "Now let's say you want to create a list that contains only the odd numbers in that range. You can use a list comprehension with an `if` statement in it to do that:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[1, 3, 5, 7, 9]"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "odd_numbers = [x for x in range(10) if x % 2]\n",
+ "odd_numbers"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's try using nested `for` loops in a list comprehension. For this exercise, you will create a `dict` and transform it into a `list` of tuples:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[(1, 'dog'), (2, 'cat'), (3, 'python')]"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_dict = {1: 'dog', 2: 'cat', 3: 'python'}\n",
+ "[(num, animal) for num in my_dict for animal in my_dict.values() if my_dict[num] == animal]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This code creates a `tuple` of number and animals for each number in the dictionary and each animal, but it filters it so that it will only create the `tuple` if the dictionary key equals its value.\n",
+ "\n",
+ "Here is the equivalent as a regular `for` loop:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[(1, 'dog'), (2, 'cat'), (3, 'python')]"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_dict = {1: 'dog', 2: 'cat', 3: 'python'}\n",
+ "my_list = []\n",
+ "for num in my_dict:\n",
+ " for animal in my_dict.values():\n",
+ " if my_dict[num] == animal:\n",
+ " my_list.append((num, animal))\n",
+ "my_list"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can make the previous list comprehension a bit more readable by putting some line breaks in it, like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[(1, 'dog'), (2, 'cat'), (3, 'python')]"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_dict = {1: 'dog', 2: 'cat', 3: 'python'}\n",
+ "[(num, animal) for num in my_dict \n",
+ " for animal in my_dict.values() \n",
+ " if my_dict[num] == animal]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This is easier to read than the one-liner version. List comprehensions are fun to write, but they can be difficult to debug or reacquaint yourself with. Always be sure to give good names to the variables inside of list comprehensions. If the comprehension gets too complex, it would probably be better to break it down into smaller pieces.\n",
+ "\n",
+ "## Nested List Comprehensions\n",
+ "\n",
+ "You can also nest list comprehensions inside of each other. For the most part, this is not recommended. If you search the Internet, you will find that the most common use case for nesting list comprehensions is for matrix math.\n",
+ "\n",
+ "A matrix is usually represented as a list of lists where the internal lists contain integers or floats. \n",
+ "\n",
+ "Let's look at an example of that:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[[18, 16, 14], [12, 10, 8], [6, 4, 2]]"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "matrix = [[9, 8, 7], [6, 5, 4], [3, 2, 1]]\n",
+ "[[element * 2 for element in row] for row in matrix]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This matrix has three lists in it. These internal lists can be thought of as rows. Next you create a nested list comprehension that will loop over each element in a row and multiply that element by 2. Then in the outer portion of the list comprehension, you will loop over each row in the matrix itself.\n",
+ "\n",
+ "If you get the chance, you should go check out Python's documentation on list comprehensions. It has several other interesting examples in it that are well worth your time."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Dictionary Comprehensions\n",
+ "\n",
+ "Dictionary comprehensions were originally created in Python 3.0, but they were then backported to Python 2.7. You can read all about them in [Python Enhancement Proposal 274 (PEP 274)](http://www.python.org/dev/peps/pep-0274/), which goes into all the details of how they work.\n",
+ "\n",
+ "The syntax for a dictionary comprehension is quite similar to a list comprehension. Instead of square braces, you use curly braces. Inside the braces, you have a `key: value` expression followed by the `for` loop which itself can be followed by additional `if` or `for` clauses.\n",
+ "\n",
+ "You can write a dictionary comprehension like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "{key: value for key, value in enumerate('abcde')}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this example, you create a `key: value` pair for every `key` and `value` that is returned from `enumerate`. The `enumerate` function returns the position of an item and the item itself as it iterates over the data structure. \n",
+ "\n",
+ "You probably won't see dictionary comprehensions as often as you will list comprehensions. They just aren't as useful. You also have to be careful when you create a dictionary comprehension as they keys have to be immutable. If they aren't, you will receive an exception."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Set Comprehensions\n",
+ "\n",
+ "You learned about sets back in chapter 8. They are useful for creating sequences that contain a unique group of elements. You can create a `set` using a set comprehension.\n",
+ "\n",
+ "To create a set comprehension, you will need to use curly braces and loop over a sequence. In fact, the syntax for a set comprehension matches a list comprehension completely except that set comprehensions use curly braces instead of square braces.\n",
+ "\n",
+ "Let's take a look:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['a', 'a', 'a', 'b', 'b', 'c', 'd', 'e']"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_list = list('aaabbcde')\n",
+ "my_list"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'a', 'b', 'c', 'd', 'e'}"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_set = {item for item in my_list}\n",
+ "my_set"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Set comprehensions are pretty straightforward. Here you loop over each item in the `list` and put it into a `set`. Then you print out the `set` to verify that the elements were deduped."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter14_files/example.txt b/chapter14_files/example.txt
new file mode 100644
index 0000000..92819ab
--- /dev/null
+++ b/chapter14_files/example.txt
@@ -0,0 +1,3 @@
+This is an example text file
+with multiple lines
+for reading by Python
\ No newline at end of file
diff --git a/chapter14_files/read_file.py b/chapter14_files/read_file.py
new file mode 100644
index 0000000..dc43fc0
--- /dev/null
+++ b/chapter14_files/read_file.py
@@ -0,0 +1,4 @@
+file_handler = open('example.txt')
+for line in file_handler:
+ print(line)
+file_handler.close()
\ No newline at end of file
diff --git a/chapter14_files/read_file_with.py b/chapter14_files/read_file_with.py
new file mode 100644
index 0000000..fae2a8a
--- /dev/null
+++ b/chapter14_files/read_file_with.py
@@ -0,0 +1,3 @@
+with open('example.txt') as file_handler:
+ for line in file_handler:
+ print(line)
\ No newline at end of file
diff --git a/chapter18_classes/__pycache__/ball.cpython-38.pyc b/chapter18_classes/__pycache__/ball.cpython-38.pyc
new file mode 100644
index 0000000..8aa99da
Binary files /dev/null and b/chapter18_classes/__pycache__/ball.cpython-38.pyc differ
diff --git a/chapter18_classes/ball.py b/chapter18_classes/ball.py
new file mode 100644
index 0000000..117fda2
--- /dev/null
+++ b/chapter18_classes/ball.py
@@ -0,0 +1,24 @@
+# ball.py
+
+class Ball:
+
+ def __init__(self, color: str, size: float, weight: float,
+ ball_type: str) -> None:
+ self.color = color
+ self.size = size
+ self.weight = weight
+ self.ball_type = ball_type
+
+ def bounce(self):
+ if self.ball_type.lower() == 'bowling':
+ print("Bowling balls can't bounce!")
+ else:
+ print(f"The {self.ball_type} ball is bouncing!")
+
+
+if __name__ == "__main__":
+ ball_one = Ball('black', 6, 12, 'bowling')
+ ball_two = Ball('red', 12, 1, 'beach')
+
+ ball_one.bounce()
+ ball_two.bounce()
\ No newline at end of file
diff --git a/chapter18_classes/ball_printable.py b/chapter18_classes/ball_printable.py
new file mode 100644
index 0000000..41ad44e
--- /dev/null
+++ b/chapter18_classes/ball_printable.py
@@ -0,0 +1,27 @@
+# ball_printable.py
+
+class Ball:
+
+ def __init__(self, color: str, size: float, weight: float,
+ ball_type: str) -> None:
+ self.color = color
+ self.size = size
+ self.weight = weight
+ self.ball_type = ball_type
+
+ def bounce(self):
+ if self.ball_type.lower() == 'bowling':
+ print("Bowling balls can't bounce!")
+ else:
+ print(f'The {self.ball_type} ball is bouncing!')
+
+ def __repr__(self):
+ return f''
+
+
+if __name__ == "__main__":
+ ball_one = Ball('black', 6, 12, 'bowling')
+ ball_two = Ball('red', 12, 1, 'beach')
+
+ print(ball_one)
+ print(ball_two)
\ No newline at end of file
diff --git a/chapter18_classes/ball_printable_str.py b/chapter18_classes/ball_printable_str.py
new file mode 100644
index 0000000..4fc530b
--- /dev/null
+++ b/chapter18_classes/ball_printable_str.py
@@ -0,0 +1,33 @@
+# ball_printable.py
+
+class Ball:
+
+ def __init__(self, color: str, size: float, weight: float,
+ ball_type: str) -> None:
+ self.color = color
+ self.size = size
+ self.weight = weight
+ self.ball_type = ball_type
+
+ def bounce(self):
+ if self.ball_type.lower() == 'bowling':
+ print("Bowling balls can't bounce!")
+ else:
+ print(f'The {self.ball_type} ball is bouncing!')
+
+ def __repr__(self):
+ return f''
+
+ def __str__(self):
+ return f'{self.color} {self.ball_type} ball'
+
+
+if __name__ == "__main__":
+ ball_one = Ball('black', 6, 12, 'bowling')
+ ball_two = Ball('red', 12, 1, 'beach')
+
+ print(ball_one)
+ print(ball_two)
+
+ print(f'{ball_one.__repr__()}')
+ print(f'{ball_one.__str__()}')
\ No newline at end of file
diff --git a/chapter18_classes/bowling_ball.py b/chapter18_classes/bowling_ball.py
new file mode 100644
index 0000000..09d2a72
--- /dev/null
+++ b/chapter18_classes/bowling_ball.py
@@ -0,0 +1,12 @@
+# bowling_ball.py
+import ball
+
+class BowlingBall(ball.Ball):
+
+ def roll(self):
+ print(f'You are rolling the {self.ball_type} ball')
+
+if __name__ == '__main__':
+ ball = BowlingBall('green', 10, 15, 'bowling')
+ ball.roll()
+
diff --git a/chapter18_classes/simple_ball.py b/chapter18_classes/simple_ball.py
new file mode 100644
index 0000000..9425718
--- /dev/null
+++ b/chapter18_classes/simple_ball.py
@@ -0,0 +1,7 @@
+class Ball:
+
+ def __init__(self, color, size, weight):
+ """Constructor"""
+ self.color = color
+ self.size = size
+ self.weight = weight
\ No newline at end of file
diff --git a/chapter18_classes/simple_ball_type_hints.py b/chapter18_classes/simple_ball_type_hints.py
new file mode 100644
index 0000000..c9824ae
--- /dev/null
+++ b/chapter18_classes/simple_ball_type_hints.py
@@ -0,0 +1,6 @@
+class Ball:
+
+ def __init__(self, color: str, size: float, weight: float) -> None:
+ self.color = color
+ self.size = size
+ self.weight = weight
\ No newline at end of file
diff --git a/chapter22_type_hints/bad_type_hinting.py b/chapter22_type_hints/bad_type_hinting.py
new file mode 100644
index 0000000..917f127
--- /dev/null
+++ b/chapter22_type_hints/bad_type_hinting.py
@@ -0,0 +1,4 @@
+# bad_type_hinting.py
+
+def my_function(a: str, b: str) -> None:
+ return a.keys() + b.keys()
diff --git a/chapter22_type_hints/bad_type_hinting2.py b/chapter22_type_hints/bad_type_hinting2.py
new file mode 100644
index 0000000..76caf86
--- /dev/null
+++ b/chapter22_type_hints/bad_type_hinting2.py
@@ -0,0 +1,4 @@
+# bad_type_hinting2.py
+
+def my_function(a: str, b: str) -> str:
+ return a + b
diff --git a/chapter22_type_hints/good_type_hinting.py b/chapter22_type_hints/good_type_hinting.py
new file mode 100644
index 0000000..81066c7
--- /dev/null
+++ b/chapter22_type_hints/good_type_hinting.py
@@ -0,0 +1,4 @@
+# good_type_hinting.py
+
+def my_function(a: str, b: str) -> str:
+ return a + b
diff --git a/chapter23_threading/worker_thread_subclass.py b/chapter23_threading/worker_thread_subclass.py
new file mode 100644
index 0000000..0b83bf9
--- /dev/null
+++ b/chapter23_threading/worker_thread_subclass.py
@@ -0,0 +1,30 @@
+# worker_thread_subclass.py
+
+import random
+import threading
+import time
+
+class WorkerThread(threading.Thread):
+
+ def __init__(self, name):
+ threading.Thread.__init__(self)
+ self.name = name
+ self.id = id(self)
+
+ def run(self):
+ """
+ Run the thread
+ """
+ worker(self.name, self.id)
+
+def worker(name: str, instance_id: int) -> None:
+ print(f'Started worker {name} - {instance_id}')
+ worker_time = random.choice(range(1, 5))
+ time.sleep(worker_time)
+ print(f'{name} - {instance_id} worker finished in '
+ f'{worker_time} seconds')
+
+if __name__ == '__main__':
+ for i in range(5):
+ thread = WorkerThread(name=f'computer_{i}')
+ thread.start()
diff --git a/chapter23_threading/worker_threads.py b/chapter23_threading/worker_threads.py
new file mode 100644
index 0000000..0091535
--- /dev/null
+++ b/chapter23_threading/worker_threads.py
@@ -0,0 +1,18 @@
+# worker_threads.py
+
+import random
+import threading
+import time
+
+
+def worker(name: str) -> None:
+ print(f'Started worker {name}')
+ worker_time = random.choice(range(1, 5))
+ time.sleep(worker_time)
+ print(f'{name} worker finished in {worker_time} seconds')
+
+if __name__ == '__main__':
+ for i in range(5):
+ thread = threading.Thread(target=worker,
+ args=(f'computer_{i}',))
+ thread.start()
diff --git a/chapter23_threading/writing_thread.py b/chapter23_threading/writing_thread.py
new file mode 100644
index 0000000..57f1ef7
--- /dev/null
+++ b/chapter23_threading/writing_thread.py
@@ -0,0 +1,36 @@
+# writing_thread.py
+
+import random
+import time
+from threading import Thread
+
+
+class WritingThread(Thread):
+
+ def __init__(self, filename: str, number_of_lines: int,
+ work_time: int = 1) -> None:
+ Thread.__init__(self)
+ self.filename = filename
+ self.number_of_lines = number_of_lines
+ self.work_time = work_time
+
+ def run(self) -> None:
+ """
+ Run the thread
+ """
+ print(f'Writing {self.number_of_lines} lines of text to '
+ f'{self.filename}')
+ with open(self.filename, 'w') as f:
+ for line in range(self.number_of_lines):
+ text = f'This is line {line+1}\n'
+ f.write(text)
+ time.sleep(self.work_time)
+ print(f'Finished writing {self.filename}')
+
+if __name__ == '__main__':
+ files = [f'test{x}.txt' for x in range(1, 6)]
+ for filename in files:
+ work_time = random.choice(range(1, 3))
+ number_of_lines = random.choice(range(5, 20))
+ thread = WritingThread(filename, number_of_lines, work_time)
+ thread.start()
\ No newline at end of file
diff --git a/chapter24_multiprocessing/process_pool.py b/chapter24_multiprocessing/process_pool.py
new file mode 100644
index 0000000..12a32df
--- /dev/null
+++ b/chapter24_multiprocessing/process_pool.py
@@ -0,0 +1,17 @@
+import random
+import time
+
+from multiprocessing import Pool
+
+
+def worker(name: str) -> None:
+ print(f'Started worker {name}')
+ worker_time = random.choice(range(1, 5))
+ time.sleep(worker_time)
+ print(f'{name} worker finished in {worker_time} seconds')
+
+if __name__ == '__main__':
+ process_names = [f'computer_{i}' for i in range(15)]
+ pool = Pool(processes=5)
+ pool.map(worker, process_names)
+ #pool.terminate()
\ No newline at end of file
diff --git a/chapter24_multiprocessing/worker_process_subclass.py b/chapter24_multiprocessing/worker_process_subclass.py
new file mode 100644
index 0000000..f9ff58e
--- /dev/null
+++ b/chapter24_multiprocessing/worker_process_subclass.py
@@ -0,0 +1,33 @@
+# worker_thread_subclass.py
+
+import random
+import multiprocessing
+import time
+
+class WorkerProcess(multiprocessing.Process):
+
+ def __init__(self, name):
+ multiprocessing.Process.__init__(self)
+ self.name = name
+
+ def run(self):
+ """
+ Run the thread
+ """
+ worker(self.name)
+
+def worker(name: str) -> None:
+ print(f'Started worker {name}')
+ worker_time = random.choice(range(1, 5))
+ time.sleep(worker_time)
+ print(f'{name} worker finished in {worker_time} seconds')
+
+if __name__ == '__main__':
+ processes = []
+ for i in range(5):
+ process = WorkerProcess(name=f'computer_{i}')
+ processes.append(process)
+ process.start()
+
+ for process in processes:
+ process.join()
diff --git a/chapter24_multiprocessing/worker_processes.py b/chapter24_multiprocessing/worker_processes.py
new file mode 100644
index 0000000..4920645
--- /dev/null
+++ b/chapter24_multiprocessing/worker_processes.py
@@ -0,0 +1,21 @@
+import multiprocessing
+import random
+import time
+
+
+def worker(name: str) -> None:
+ print(f'Started worker {name}')
+ worker_time = random.choice(range(1, 5))
+ time.sleep(worker_time)
+ print(f'{name} worker finished in {worker_time} seconds')
+
+if __name__ == '__main__':
+ processes = []
+ for i in range(5):
+ process = multiprocessing.Process(target=worker,
+ args=(f'computer_{i}',))
+ processes.append(process)
+ process.start()
+
+ for proc in processes:
+ proc.join()
\ No newline at end of file
diff --git a/chapter26_debugging/debug_code.py b/chapter26_debugging/debug_code.py
new file mode 100644
index 0000000..b963634
--- /dev/null
+++ b/chapter26_debugging/debug_code.py
@@ -0,0 +1,13 @@
+# debug_code.py
+
+def log(number):
+ print(f'Processing {number}')
+ print(f'Adding 2 to number: {number + 2}')
+
+
+def looper(number):
+ for i in range(number):
+ log(i)
+
+if __name__ == '__main__':
+ looper(5)
\ No newline at end of file
diff --git a/chapter26_debugging/debug_code_with_breakpoint.py b/chapter26_debugging/debug_code_with_breakpoint.py
new file mode 100644
index 0000000..f310fc6
--- /dev/null
+++ b/chapter26_debugging/debug_code_with_breakpoint.py
@@ -0,0 +1,14 @@
+# debug_code_with_breakpoint.py
+
+def log(number):
+ print(f'Processing {number}')
+ print(f'Adding 2 to number: {number + 2}')
+
+
+def looper(number):
+ for i in range(number):
+ breakpoint()
+ log(i)
+
+if __name__ == '__main__':
+ looper(5)
\ No newline at end of file
diff --git a/chapter26_debugging/debug_code_with_settrace.py b/chapter26_debugging/debug_code_with_settrace.py
new file mode 100644
index 0000000..3de0a72
--- /dev/null
+++ b/chapter26_debugging/debug_code_with_settrace.py
@@ -0,0 +1,14 @@
+# debug_code_with_settrace.py
+
+def log(number):
+ print(f'Processing {number}')
+ print(f'Adding 2 to number: {number + 2}')
+
+
+def looper(number):
+ for i in range(number):
+ import pdb; pdb.set_trace()
+ log(i)
+
+if __name__ == '__main__':
+ looper(5)
\ No newline at end of file
diff --git a/chapter27_decorators/amount_with_properties.py b/chapter27_decorators/amount_with_properties.py
new file mode 100644
index 0000000..6fce4ee
--- /dev/null
+++ b/chapter27_decorators/amount_with_properties.py
@@ -0,0 +1,24 @@
+class Amount:
+
+ def __init__(self):
+ # private attribute
+ self._amount = None
+
+ def get_amount(self):
+ return self._amount
+
+ def set_amount(self, value):
+ if isinstance(value, int) or isinstance(value, float):
+ self._amount = value
+ else:
+ print(f'Value must be an int or float')
+
+ amount = property(get_amount, set_amount)
+
+if __name__ == '__main__':
+ amt = Amount()
+ print(f'The current amount is {amt.amount}')
+ amt.amount = 'the'
+ print(f'The current amount is {amt.amount}')
+ amt.amount = 5.5
+ print(f'The current amount is {amt.amount}')
diff --git a/chapter27_decorators/amount_with_property_decorator.py b/chapter27_decorators/amount_with_property_decorator.py
new file mode 100644
index 0000000..fa6074d
--- /dev/null
+++ b/chapter27_decorators/amount_with_property_decorator.py
@@ -0,0 +1,25 @@
+class Amount:
+
+ def __init__(self):
+ # private attribute
+ self._amount = None
+
+ @property
+ def amount(self):
+ return self._amount
+
+ @amount.setter
+ def amount(self, value):
+ if isinstance(value, int) or isinstance(value, float):
+ self._amount = value
+ else:
+ print(f'Value must be an int or float')
+
+
+if __name__ == '__main__':
+ amt = Amount()
+ print(f'The current amount is {amt.amount}')
+ amt.amount = 'the'
+ print(f'The current amount is {amt.amount}')
+ amt.amount = 5.5
+ print(f'The current amount is {amt.amount}')
diff --git a/chapter27_decorators/amount_without_properties.py b/chapter27_decorators/amount_without_properties.py
new file mode 100644
index 0000000..a384f94
--- /dev/null
+++ b/chapter27_decorators/amount_without_properties.py
@@ -0,0 +1,22 @@
+class Amount:
+
+ def __init__(self):
+ # private attribute
+ self._amount = None
+
+ def get_amount(self):
+ return self._amount
+
+ def set_amount(self, value):
+ if isinstance(value, int) or isinstance(value, float):
+ self._amount = value
+ else:
+ print(f'Value must be an int or float')
+
+if __name__ == '__main__':
+ amt = Amount()
+ print(f'The current amount is {amt.get_amount()}')
+ amt.set_amount('the')
+ print(f'The current amount is {amt.get_amount()}')
+ amt.set_amount(5.5)
+ print(f'The current amount is {amt.get_amount()}')
diff --git a/chapter27_decorators/classmethod_example.py b/chapter27_decorators/classmethod_example.py
new file mode 100644
index 0000000..e35b726
--- /dev/null
+++ b/chapter27_decorators/classmethod_example.py
@@ -0,0 +1,27 @@
+class Time:
+ """an example 24-hour time class"""
+
+ def __init__(self, hour, minute):
+ self.hour = hour
+ self.minute = minute
+
+ def __repr__(self):
+ return "Time(%d, %d)" % (self.hour, self.minute)
+
+ @classmethod
+ def from_float(cls, moment):
+ """2.5 == 2 hours, 30 minutes, 0 seconds, 0 microseconds"""
+ hours = int(moment)
+ if hours:
+ moment = moment % hours
+ minutes = int(moment * 60)
+ return cls(hours, minutes)
+
+ def to_float(self):
+ """return self as a floating point number"""
+ return self.hour + self.minute / 60
+
+Time(7, 30)
+Time.from_float(5.75)
+t = Time(10, 15)
+t.to_float()
\ No newline at end of file
diff --git a/chapter27_decorators/decorator_class.py b/chapter27_decorators/decorator_class.py
new file mode 100644
index 0000000..1ab3964
--- /dev/null
+++ b/chapter27_decorators/decorator_class.py
@@ -0,0 +1,24 @@
+# decorator_class.py
+
+class info:
+
+ def __init__(self, arg1, arg2):
+ print('running __init__')
+ self.arg1 = arg1
+ self.arg2 = arg2
+ print('Decorator args: {}, {}'.format(arg1, arg2))
+
+ def __call__(self, function):
+ print('in __call__')
+
+ def wrapper(*args, **kwargs):
+ print('in wrapper()')
+ return function(*args, **kwargs)
+
+ return wrapper
+
+@info(3, 'Python')
+def treble(number):
+ return number * 3
+
+print(treble(5))
\ No newline at end of file
diff --git a/chapter27_decorators/decorator_syntax.py b/chapter27_decorators/decorator_syntax.py
new file mode 100644
index 0000000..1c5dd13
--- /dev/null
+++ b/chapter27_decorators/decorator_syntax.py
@@ -0,0 +1,16 @@
+# decorator_syntax.py
+
+def func_info(func):
+ def wrapper(*args):
+ print('Function name: ' + func.__name__)
+ print('Function docstring: ' + str(func.__doc__))
+ result = func(*args)
+ return result
+ return wrapper
+
+@func_info
+def treble(a: int) -> int:
+ """A function that triples its input"""
+ return a * 3
+
+print(treble(5))
diff --git a/chapter27_decorators/decorator_syntax_with_arguments.py b/chapter27_decorators/decorator_syntax_with_arguments.py
new file mode 100644
index 0000000..bfd6ea8
--- /dev/null
+++ b/chapter27_decorators/decorator_syntax_with_arguments.py
@@ -0,0 +1,24 @@
+# decorator_syntax_with_arguments.py
+
+def func_info(arg1, arg2):
+ print('Decorator arg1 = ' + str(arg1))
+ print('Decorator arg2 = ' + str(arg2))
+
+ def the_real_decorator(function):
+
+ def wrapper(*args, **kwargs):
+ print('Function {} args: {} kwargs: {}'
+ .format(
+ function.__name__,
+ str(args),
+ str(kwargs)))
+ return function(*args, **kwargs)
+ return wrapper
+
+ return the_real_decorator
+
+@func_info(3, 'Python')
+def treble(number):
+ return number * 3
+
+print(treble(5))
diff --git a/chapter27_decorators/first_decorator.py b/chapter27_decorators/first_decorator.py
new file mode 100644
index 0000000..57c6293
--- /dev/null
+++ b/chapter27_decorators/first_decorator.py
@@ -0,0 +1,16 @@
+
+
+def func_info(func):
+ def wrapper():
+ print('Function name: ' + func.__name__)
+ print('Function docstring: ' + str(func.__doc__))
+ result = func()
+ return result
+ return wrapper
+
+
+def treble():
+ return 3 * 3
+
+decorator = func_info(treble)
+print(decorator())
diff --git a/chapter27_decorators/first_decorator_updated.py b/chapter27_decorators/first_decorator_updated.py
new file mode 100644
index 0000000..1d61a9c
--- /dev/null
+++ b/chapter27_decorators/first_decorator_updated.py
@@ -0,0 +1,18 @@
+# first_decorator_updated.py
+
+def func_info(func):
+ def wrapper(*args):
+ print('Function name: ' + func.__name__)
+ print('Function docstring: ' + str(func.__doc__))
+ result = func(*args)
+ return result
+ return wrapper
+
+
+def treble(a: int) -> int:
+ """A function that triples its input"""
+ return a * 3
+
+
+my_decorator = func_info(treble)
+print(my_decorator(5))
diff --git a/chapter27_decorators/logging_decorator.py b/chapter27_decorators/logging_decorator.py
new file mode 100644
index 0000000..ca71d71
--- /dev/null
+++ b/chapter27_decorators/logging_decorator.py
@@ -0,0 +1,37 @@
+import logging
+
+def logging_formatter(logger, name):
+ """
+ Format logger and add file handler
+ """
+ fh = logging.FileHandler(f"{name}.log")
+ fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+ formatter = logging.Formatter(fmt)
+ fh.setFormatter(formatter)
+ logger.addHandler(fh)
+
+def log(func):
+ """
+ Log what function is called
+ """
+ def wrapper(*args, **kwargs):
+ name = func.__name__
+ logger = logging.getLogger(name)
+ logger.setLevel(logging.INFO)
+
+ # add logging formatter and file handler
+ logging_formatter(logger, name)
+
+ logger.info(f"Running function: {name}")
+ logger.info(f"{args=}, {kwargs=}")
+ result = func(*args, **kwargs)
+ logger.info("Result: %s" % result)
+ return func
+ return wrapper
+
+@log
+def treble(a):
+ return a * 3
+
+if __name__ == '__main__':
+ treble(5)
diff --git a/chapter27_decorators/stacked_decorator_tracing.py b/chapter27_decorators/stacked_decorator_tracing.py
new file mode 100644
index 0000000..07b25a9
--- /dev/null
+++ b/chapter27_decorators/stacked_decorator_tracing.py
@@ -0,0 +1,18 @@
+def bold(func):
+ print(f'You are wrapping {func.__name__} in bold')
+ def bold_wrapper():
+ return "" + func() + ""
+ return bold_wrapper
+
+def italic(func):
+ print(f'You are wrapping {func.__name__} in italic')
+ def italic_wrapper():
+ return "" + func() + ""
+ return italic_wrapper
+
+@bold
+@italic
+def formatted_text():
+ return 'Python rocks!'
+
+print(formatted_text())
\ No newline at end of file
diff --git a/chapter27_decorators/stacked_decorators.py b/chapter27_decorators/stacked_decorators.py
new file mode 100644
index 0000000..9ebdf05
--- /dev/null
+++ b/chapter27_decorators/stacked_decorators.py
@@ -0,0 +1,16 @@
+def bold(func):
+ def wrapper():
+ return "" + func() + ""
+ return wrapper
+
+def italic(func):
+ def wrapper():
+ return "" + func() + ""
+ return wrapper
+
+@bold
+@italic
+def formatted_text():
+ return 'Python rocks!'
+
+print(formatted_text())
\ No newline at end of file
diff --git a/chapter27_decorators/treble.log b/chapter27_decorators/treble.log
new file mode 100644
index 0000000..ccf0f36
--- /dev/null
+++ b/chapter27_decorators/treble.log
@@ -0,0 +1,3 @@
+2020-05-04 16:22:02,781 - treble - INFO - Running function: treble
+2020-05-04 16:22:02,781 - treble - INFO - args=(5,), kwargs={}
+2020-05-04 16:22:02,781 - treble - INFO - Result: 15
diff --git a/chapter29_profiling/callee_stats.py b/chapter29_profiling/callee_stats.py
new file mode 100644
index 0000000..a1a631c
--- /dev/null
+++ b/chapter29_profiling/callee_stats.py
@@ -0,0 +1,12 @@
+import pstats
+
+def formatted_stats_output(path):
+ p = pstats.Stats(path)
+ stripped_dirs = p.strip_dirs()
+ sorted_stats = stripped_dirs.sort_stats('filename')
+ sorted_stats.print_callers('\(main')
+ sorted_stats.print_callees('\(main')
+
+if __name__ =='__main__':
+ path = 'profile_output.txt'
+ formatted_stats_output(path)
\ No newline at end of file
diff --git a/chapter29_profiling/filtered_stats.py b/chapter29_profiling/filtered_stats.py
new file mode 100644
index 0000000..086c800
--- /dev/null
+++ b/chapter29_profiling/filtered_stats.py
@@ -0,0 +1,11 @@
+import pstats
+
+def formatted_stats_output(path):
+ p = pstats.Stats(path)
+ stripped_dirs = p.strip_dirs()
+ sorted_stats = stripped_dirs.sort_stats('filename')
+ sorted_stats.print_stats('\(main')
+
+if __name__ =='__main__':
+ path = 'profile_output.txt'
+ formatted_stats_output(path)
\ No newline at end of file
diff --git a/chapter29_profiling/formatted_output.py b/chapter29_profiling/formatted_output.py
new file mode 100644
index 0000000..d35ca8a
--- /dev/null
+++ b/chapter29_profiling/formatted_output.py
@@ -0,0 +1,11 @@
+import pstats
+
+def formatted_stats_output(path):
+ p = pstats.Stats(path)
+ stripped_dirs = p.strip_dirs()
+ sorted_stats = stripped_dirs.sort_stats('filename')
+ sorted_stats.print_stats()
+
+if __name__ =='__main__':
+ path = 'profile_output.txt'
+ formatted_stats_output(path)
\ No newline at end of file
diff --git a/chapter29_profiling/profile_output.txt b/chapter29_profiling/profile_output.txt
new file mode 100644
index 0000000..3b7e13e
Binary files /dev/null and b/chapter29_profiling/profile_output.txt differ
diff --git a/chapter29_profiling/profile_test.py b/chapter29_profiling/profile_test.py
new file mode 100644
index 0000000..6b8641b
--- /dev/null
+++ b/chapter29_profiling/profile_test.py
@@ -0,0 +1,24 @@
+# profile_test.py
+
+import time
+
+def quick():
+ print('Running quick')
+ return 1 + 1
+
+def average():
+ print('Running average')
+ time.sleep(0.5)
+
+def super_slow():
+ print('Running super slowly')
+ time.sleep(2)
+
+def main():
+ quick()
+ super_slow()
+ quick()
+ average()
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/chapter30_testing/add_doctest.py b/chapter30_testing/add_doctest.py
new file mode 100644
index 0000000..5e0c3cd
--- /dev/null
+++ b/chapter30_testing/add_doctest.py
@@ -0,0 +1,10 @@
+# add_doctest.py
+
+def add(a: int, b: int) -> int:
+ """
+ >>> add(1, 2)
+ 3
+ >>> add(4, 5)
+ 9
+ """
+ a + b
\ No newline at end of file
diff --git a/chapter30_testing/add_doctest_working.py b/chapter30_testing/add_doctest_working.py
new file mode 100644
index 0000000..b8c161b
--- /dev/null
+++ b/chapter30_testing/add_doctest_working.py
@@ -0,0 +1,10 @@
+# add_doctest.py
+
+def add(a: int, b: int) -> int:
+ """
+ >>> add(1, 2)
+ 3
+ >>> add(4, 5)
+ 9
+ """
+ return a + b
\ No newline at end of file
diff --git a/chapter30_testing/add_test_in_code.py b/chapter30_testing/add_test_in_code.py
new file mode 100644
index 0000000..3918d37
--- /dev/null
+++ b/chapter30_testing/add_test_in_code.py
@@ -0,0 +1,14 @@
+# add_test_in_code.py
+
+def add(a: int, b: int) -> int:
+ """
+ >>> add(1, 2)
+ 3
+ >>> add(4, 5)
+ 9
+ """
+ return a + b
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod(verbose=True)
\ No newline at end of file
diff --git a/chapter30_testing/doctest_external.py b/chapter30_testing/doctest_external.py
new file mode 100644
index 0000000..e4861c1
--- /dev/null
+++ b/chapter30_testing/doctest_external.py
@@ -0,0 +1,4 @@
+# doctest_external.py
+
+def add(a: int, b: int) -> int:
+ return a + b
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_buzz_test/fizzbuzz.py b/chapter30_testing/fizzbuzz_buzz_test/fizzbuzz.py
new file mode 100644
index 0000000..5d4c54a
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_buzz_test/fizzbuzz.py
@@ -0,0 +1,3 @@
+def process(number):
+ if number % 3 == 0:
+ return 'Fizz'
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_buzz_test/test_fizzbuzz.py b/chapter30_testing/fizzbuzz_buzz_test/test_fizzbuzz.py
new file mode 100644
index 0000000..93d0e2a
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_buzz_test/test_fizzbuzz.py
@@ -0,0 +1,13 @@
+import fizzbuzz
+import unittest
+
+class TestFizzBuzz(unittest.TestCase):
+
+ def test_multiple_of_three(self):
+ self.assertEqual(fizzbuzz.process(6), 'Fizz')
+
+ def test_multiple_of_five(self):
+ self.assertEqual(fizzbuzz.process(20), 'Buzz')
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_buzz_test_passing/fizzbuzz.py b/chapter30_testing/fizzbuzz_buzz_test_passing/fizzbuzz.py
new file mode 100644
index 0000000..026ca50
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_buzz_test_passing/fizzbuzz.py
@@ -0,0 +1,5 @@
+def process(number):
+ if number % 3 == 0:
+ return 'Fizz'
+ elif number % 5 == 0:
+ return 'Buzz'
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_buzz_test_passing/test_fizzbuzz.py b/chapter30_testing/fizzbuzz_buzz_test_passing/test_fizzbuzz.py
new file mode 100644
index 0000000..93d0e2a
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_buzz_test_passing/test_fizzbuzz.py
@@ -0,0 +1,13 @@
+import fizzbuzz
+import unittest
+
+class TestFizzBuzz(unittest.TestCase):
+
+ def test_multiple_of_three(self):
+ self.assertEqual(fizzbuzz.process(6), 'Fizz')
+
+ def test_multiple_of_five(self):
+ self.assertEqual(fizzbuzz.process(20), 'Buzz')
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_final_test/fizzbuzz.py b/chapter30_testing/fizzbuzz_final_test/fizzbuzz.py
new file mode 100644
index 0000000..7510daa
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_final_test/fizzbuzz.py
@@ -0,0 +1,7 @@
+def process(number):
+ if number % 3 == 0 and number % 5 == 0:
+ return 'FizzBuzz'
+ elif number % 3 == 0:
+ return 'Fizz'
+ elif number % 5 == 0:
+ return 'Buzz'
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_final_test/test_fizzbuzz.py b/chapter30_testing/fizzbuzz_final_test/test_fizzbuzz.py
new file mode 100644
index 0000000..1326335
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_final_test/test_fizzbuzz.py
@@ -0,0 +1,20 @@
+import fizzbuzz
+import unittest
+
+class TestFizzBuzz(unittest.TestCase):
+
+ def test_multiple_of_three(self):
+ self.assertEqual(fizzbuzz.process(6), 'Fizz')
+
+ def test_multiple_of_five(self):
+ self.assertEqual(fizzbuzz.process(20), 'Buzz')
+
+ def test_fizzbuzz(self):
+ self.assertEqual(fizzbuzz.process(15), 'FizzBuzz')
+
+ def test_regular_numbers(self):
+ self.assertEqual(fizzbuzz.process(2), 2)
+ self.assertEqual(fizzbuzz.process(98), 98)
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_final_test_passing/fizzbuzz.py b/chapter30_testing/fizzbuzz_final_test_passing/fizzbuzz.py
new file mode 100644
index 0000000..6407376
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_final_test_passing/fizzbuzz.py
@@ -0,0 +1,9 @@
+def process(number):
+ if number % 3 == 0 and number % 5 == 0:
+ return 'FizzBuzz'
+ elif number % 3 == 0:
+ return 'Fizz'
+ elif number % 5 == 0:
+ return 'Buzz'
+ else:
+ return number
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_final_test_passing/test_fizzbuzz.py b/chapter30_testing/fizzbuzz_final_test_passing/test_fizzbuzz.py
new file mode 100644
index 0000000..1326335
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_final_test_passing/test_fizzbuzz.py
@@ -0,0 +1,20 @@
+import fizzbuzz
+import unittest
+
+class TestFizzBuzz(unittest.TestCase):
+
+ def test_multiple_of_three(self):
+ self.assertEqual(fizzbuzz.process(6), 'Fizz')
+
+ def test_multiple_of_five(self):
+ self.assertEqual(fizzbuzz.process(20), 'Buzz')
+
+ def test_fizzbuzz(self):
+ self.assertEqual(fizzbuzz.process(15), 'FizzBuzz')
+
+ def test_regular_numbers(self):
+ self.assertEqual(fizzbuzz.process(2), 2)
+ self.assertEqual(fizzbuzz.process(98), 98)
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_fizz_test/fizzbuzz.py b/chapter30_testing/fizzbuzz_fizz_test/fizzbuzz.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_fizz_test/fizzbuzz.py
@@ -0,0 +1 @@
+
diff --git a/chapter30_testing/fizzbuzz_fizz_test/test_fizzbuzz.py b/chapter30_testing/fizzbuzz_fizz_test/test_fizzbuzz.py
new file mode 100644
index 0000000..344ed73
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_fizz_test/test_fizzbuzz.py
@@ -0,0 +1,10 @@
+import fizzbuzz
+import unittest
+
+class TestFizzBuzz(unittest.TestCase):
+
+ def test_multiple_of_three(self):
+ self.assertEqual(fizzbuzz.process(6), 'Fizz')
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_fizz_test_passing/fizzbuzz.py b/chapter30_testing/fizzbuzz_fizz_test_passing/fizzbuzz.py
new file mode 100644
index 0000000..5d4c54a
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_fizz_test_passing/fizzbuzz.py
@@ -0,0 +1,3 @@
+def process(number):
+ if number % 3 == 0:
+ return 'Fizz'
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_fizz_test_passing/test_fizzbuzz.py b/chapter30_testing/fizzbuzz_fizz_test_passing/test_fizzbuzz.py
new file mode 100644
index 0000000..344ed73
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_fizz_test_passing/test_fizzbuzz.py
@@ -0,0 +1,10 @@
+import fizzbuzz
+import unittest
+
+class TestFizzBuzz(unittest.TestCase):
+
+ def test_multiple_of_three(self):
+ self.assertEqual(fizzbuzz.process(6), 'Fizz')
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_fizzbuzz_test/fizzbuzz.py b/chapter30_testing/fizzbuzz_fizzbuzz_test/fizzbuzz.py
new file mode 100644
index 0000000..026ca50
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_fizzbuzz_test/fizzbuzz.py
@@ -0,0 +1,5 @@
+def process(number):
+ if number % 3 == 0:
+ return 'Fizz'
+ elif number % 5 == 0:
+ return 'Buzz'
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_fizzbuzz_test/test_fizzbuzz.py b/chapter30_testing/fizzbuzz_fizzbuzz_test/test_fizzbuzz.py
new file mode 100644
index 0000000..d2b08ed
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_fizzbuzz_test/test_fizzbuzz.py
@@ -0,0 +1,16 @@
+import fizzbuzz
+import unittest
+
+class TestFizzBuzz(unittest.TestCase):
+
+ def test_multiple_of_three(self):
+ self.assertEqual(fizzbuzz.process(6), 'Fizz')
+
+ def test_multiple_of_five(self):
+ self.assertEqual(fizzbuzz.process(20), 'Buzz')
+
+ def test_fizzbuzz(self):
+ self.assertEqual(fizzbuzz.process(15), 'FizzBuzz')
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_fizzbuzz_test_passing/fizzbuzz.py b/chapter30_testing/fizzbuzz_fizzbuzz_test_passing/fizzbuzz.py
new file mode 100644
index 0000000..7510daa
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_fizzbuzz_test_passing/fizzbuzz.py
@@ -0,0 +1,7 @@
+def process(number):
+ if number % 3 == 0 and number % 5 == 0:
+ return 'FizzBuzz'
+ elif number % 3 == 0:
+ return 'Fizz'
+ elif number % 5 == 0:
+ return 'Buzz'
\ No newline at end of file
diff --git a/chapter30_testing/fizzbuzz_fizzbuzz_test_passing/test_fizzbuzz.py b/chapter30_testing/fizzbuzz_fizzbuzz_test_passing/test_fizzbuzz.py
new file mode 100644
index 0000000..d2b08ed
--- /dev/null
+++ b/chapter30_testing/fizzbuzz_fizzbuzz_test_passing/test_fizzbuzz.py
@@ -0,0 +1,16 @@
+import fizzbuzz
+import unittest
+
+class TestFizzBuzz(unittest.TestCase):
+
+ def test_multiple_of_three(self):
+ self.assertEqual(fizzbuzz.process(6), 'Fizz')
+
+ def test_multiple_of_five(self):
+ self.assertEqual(fizzbuzz.process(20), 'Buzz')
+
+ def test_fizzbuzz(self):
+ self.assertEqual(fizzbuzz.process(15), 'FizzBuzz')
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/chapter30_testing/test.txt b/chapter30_testing/test.txt
new file mode 100644
index 0000000..5ae2e6b
--- /dev/null
+++ b/chapter30_testing/test.txt
@@ -0,0 +1,7 @@
+The following are tests for doctest_external
+
+>>> from doctest_external import add
+>>> add(1, 2)
+3
+>>> add(4, 5)
+9
\ No newline at end of file
diff --git a/chapter31_jupyter/Hello World.ipynb b/chapter31_jupyter/Hello World.ipynb
new file mode 100644
index 0000000..9309eed
--- /dev/null
+++ b/chapter31_jupyter/Hello World.ipynb
@@ -0,0 +1,45 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This is an example of printing in Python: `print('Hello')`\n",
+ "\n",
+ "Code block:\n",
+ "\n",
+ "```python\n",
+ "print('hello world')\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/chapter32_argparse/file_parser.py b/chapter32_argparse/file_parser.py
new file mode 100644
index 0000000..9b3db74
--- /dev/null
+++ b/chapter32_argparse/file_parser.py
@@ -0,0 +1,20 @@
+# file_parser.py
+
+import argparse
+
+def file_parser(input_file, output_file=''):
+ print(f'Processing {input_file}')
+ print('Finished processing')
+ if output_file:
+ print(f'Creating {output_file}')
+
+def main():
+ parser = argparse.ArgumentParser('File parser')
+ parser.add_argument('--infile', help='Input file')
+ parser.add_argument('--out', help='Output file')
+ args = parser.parse_args()
+ if args.infile:
+ file_parser(args.infile, args.out)
+
+if __name__ == '__main__':
+ main()
diff --git a/chapter32_argparse/file_parser_aliases.py b/chapter32_argparse/file_parser_aliases.py
new file mode 100644
index 0000000..d56f8b9
--- /dev/null
+++ b/chapter32_argparse/file_parser_aliases.py
@@ -0,0 +1,23 @@
+# file_parser_aliases.py
+
+import argparse
+
+def file_parser(input_file, output_file=''):
+ print(f'Processing {input_file}')
+ print('Finished processing')
+ if output_file:
+ print(f'Creating {output_file}')
+
+def main():
+ parser = argparse.ArgumentParser('File parser',
+ description='PyParse - The File Processor',
+ epilog='Thank you for choosing PyParse!',
+ add_help=False)
+ parser.add_argument('-i', '--infile', help='Input file for conversion')
+ parser.add_argument('-o', '--out', help='Converted output file')
+ args = parser.parse_args()
+ if args.infile:
+ file_parser(args.infile, args.out)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/chapter32_argparse/file_parser_aliases2.py b/chapter32_argparse/file_parser_aliases2.py
new file mode 100644
index 0000000..e64d642
--- /dev/null
+++ b/chapter32_argparse/file_parser_aliases2.py
@@ -0,0 +1,23 @@
+# file_parser_aliases2.py
+
+import argparse
+
+def file_parser(input_file, output_file=''):
+ print(f'Processing {input_file}')
+ print('Finished processing')
+ if output_file:
+ print(f'Creating {output_file}')
+
+def main():
+ parser = argparse.ArgumentParser('File parser',
+ description='PyParse - The File Processor',
+ epilog='Thank you for choosing PyParse!',
+ add_help=False)
+ parser.add_argument('-i', '--infile', help='Input file for conversion')
+ parser.add_argument('-o', '--out', help='Converted output file')
+ args = parser.parse_args()
+ if args.infile:
+ file_parser(args.infile, args.out)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/chapter32_argparse/file_parser_exclusive.py b/chapter32_argparse/file_parser_exclusive.py
new file mode 100644
index 0000000..7eb3b82
--- /dev/null
+++ b/chapter32_argparse/file_parser_exclusive.py
@@ -0,0 +1,24 @@
+# file_parser_exclusive.py
+
+import argparse
+
+def file_parser(input_file, output_file=''):
+ print(f'Processing {input_file}')
+ print('Finished processing')
+ if output_file:
+ print(f'Creating {output_file}')
+
+def main():
+ parser = argparse.ArgumentParser('File parser',
+ description='PyParse - The File Processor',
+ epilog='Thank you for choosing PyParse!',
+ add_help=False)
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument('-i', '--infile', help='Input file for conversion')
+ group.add_argument('-o', '--out', help='Converted output file')
+ args = parser.parse_args()
+ if args.infile:
+ file_parser(args.infile, args.out)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/chapter32_argparse/file_parser_no_help.py b/chapter32_argparse/file_parser_no_help.py
new file mode 100644
index 0000000..b69614e
--- /dev/null
+++ b/chapter32_argparse/file_parser_no_help.py
@@ -0,0 +1,23 @@
+# file_parser_no_help.py
+
+import argparse
+
+def file_parser(input_file, output_file=''):
+ print(f'Processing {input_file}')
+ print('Finished processing')
+ if output_file:
+ print(f'Creating {output_file}')
+
+def main():
+ parser = argparse.ArgumentParser('File parser',
+ description='PyParse - The File Processor',
+ epilog='Thank you for choosing PyParse!',
+ add_help=False)
+ parser.add_argument('--infile', help='Input file for conversion')
+ parser.add_argument('--out', help='Converted output file')
+ args = parser.parse_args()
+ if args.infile:
+ file_parser(args.infile, args.out)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/chapter32_argparse/file_parser_with_description.py b/chapter32_argparse/file_parser_with_description.py
new file mode 100644
index 0000000..c755a64
--- /dev/null
+++ b/chapter32_argparse/file_parser_with_description.py
@@ -0,0 +1,22 @@
+# file_parser_with_description.py
+
+import argparse
+
+def file_parser(input_file, output_file=''):
+ print(f'Processing {input_file}')
+ print('Finished processing')
+ if output_file:
+ print(f'Creating {output_file}')
+
+def main():
+ parser = argparse.ArgumentParser('File parser',
+ description='PyParse - The File Processor',
+ epilog='Thank you for choosing PyParse!')
+ parser.add_argument('--infile', help='Input file for conversion')
+ parser.add_argument('--out', help='Converted output file')
+ args = parser.parse_args()
+ if args.infile:
+ file_parser(args.infile, args.out)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/chapter32_argparse/pysearch.py b/chapter32_argparse/pysearch.py
new file mode 100644
index 0000000..9a2e0cc
--- /dev/null
+++ b/chapter32_argparse/pysearch.py
@@ -0,0 +1,49 @@
+# pysearch.py
+
+import argparse
+import pathlib
+
+
+def search_folder(path, extension, file_size=None):
+ """
+ Search folder for files
+ """
+ folder = pathlib.Path(path)
+ files = list(folder.rglob(f'*.{extension}'))
+
+ if not files:
+ print(f'No files found with {extension=}')
+ return
+
+ if file_size is not None:
+ files = [f for f in files
+ if f.stat().st_size > file_size]
+
+ print(f'{len(files)} *.{extension} files found:')
+ for file_path in files:
+ print(file_path)
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ 'PySearch',
+ description='PySearch - The Python Powered File Searcher')
+ parser.add_argument('-p', '--path',
+ help='The path to search for files',
+ required=True,
+ dest='path')
+ parser.add_argument('-e', '--ext',
+ help='The extension to search for',
+ required=True,
+ dest='extension')
+ parser.add_argument('-s', '--size',
+ help='The file size to filter on in bytes',
+ type=int,
+ dest='size',
+ default=None)
+
+ args = parser.parse_args()
+ search_folder(args.path, args.extension, args.size)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/chapter32_argparse/sys_args.py b/chapter32_argparse/sys_args.py
new file mode 100644
index 0000000..2d1e1a2
--- /dev/null
+++ b/chapter32_argparse/sys_args.py
@@ -0,0 +1,10 @@
+# sys_args.py
+
+import sys
+
+def main():
+ print('You passed the following arguments:')
+ print(sys.argv)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/Chapter 23 - xml/original_appt.xml b/chapter33_xml/appts.xml
similarity index 89%
rename from Chapter 23 - xml/original_appt.xml
rename to chapter33_xml/appts.xml
index 0ba8878..5b59f28 100644
--- a/Chapter 23 - xml/original_appt.xml
+++ b/chapter33_xml/appts.xml
@@ -1,21 +1,21 @@
-
-
-
- 1181251680
- 040000008200E000
- 1181572063
-
-
- 1800
- Bring pizza home
-
-
- 1181253977
- sdlkjlkadhdakhdfd
- 1181588888
- TX
- Dallas
- 1800
- Bring pizza home
-
+
+
+
+ 1181251680
+ 040000008200E000
+ 1181572063
+
+
+ 1800
+ Bring pizza home
+
+
+ 1181253977
+ sdlkjlkadhdakhdfd
+ 1181588888
+ TX
+ Dallas
+ 1800
+ Bring pizza home
+
\ No newline at end of file
diff --git a/chapter33_xml/create_xml.py b/chapter33_xml/create_xml.py
new file mode 100644
index 0000000..e10ad5f
--- /dev/null
+++ b/chapter33_xml/create_xml.py
@@ -0,0 +1,26 @@
+# create_xml.py
+
+import xml.etree.ElementTree as ET
+
+
+def create_xml(xml_file):
+ root_element = ET.Element('note_taker')
+ note_element = ET.Element('note')
+ root_element.append(note_element)
+
+ # add note sub-elements
+ to_element = ET.SubElement(note_element, 'to')
+ to_element.text = 'Mike'
+ from_element = ET.SubElement(note_element, 'from')
+ from_element.text = 'Nick'
+ heading_element = ET.SubElement(note_element, 'heading')
+ heading_element.text = 'Appointment'
+ body_element = ET.SubElement(note_element, 'body')
+ body_element.text = 'blah blah'
+
+ tree = ET.ElementTree(root_element)
+ with open(xml_file, "wb") as fh:
+ tree.write(fh)
+
+if __name__ == '__main__':
+ create_xml('test_create.xml')
\ No newline at end of file
diff --git a/chapter33_xml/edit_xml.py b/chapter33_xml/edit_xml.py
new file mode 100644
index 0000000..d2177c3
--- /dev/null
+++ b/chapter33_xml/edit_xml.py
@@ -0,0 +1,18 @@
+# edit_xml.py
+
+
+import xml.etree.cElementTree as ET
+
+def edit_xml(xml_file, output_file, from_person):
+ tree = ET.ElementTree(file=xml_file)
+ root = tree.getroot()
+
+ for from_element in tree.iter(tag='from'):
+ from_element.text = from_person
+
+ tree = ET.ElementTree(root)
+ with open(output_file, "wb") as f:
+ tree.write(f)
+
+if __name__ == '__main__':
+ edit_xml('note.xml', 'output.xml', 'Guido')
\ No newline at end of file
diff --git a/chapter33_xml/lxml_output.xml b/chapter33_xml/lxml_output.xml
new file mode 100644
index 0000000..aa4455c
--- /dev/null
+++ b/chapter33_xml/lxml_output.xml
@@ -0,0 +1,15 @@
+
+
+ Guido
+ Nadine
+ Reminder
+ Don't forget the milk
+ I'm new!
+
+
+ Nicole
+ Nadine
+ Appointment
+ Eye doctor
+
+
diff --git a/chapter33_xml/note.xml b/chapter33_xml/note.xml
new file mode 100644
index 0000000..737369c
--- /dev/null
+++ b/chapter33_xml/note.xml
@@ -0,0 +1,15 @@
+
+
+
+ Mike
+ Nadine
+ Reminder
+ Don't forget the milk
+
+
+ Nicole
+ Nadine
+ Appointment
+ Eye doctor
+
+
\ No newline at end of file
diff --git a/chapter33_xml/output.xml b/chapter33_xml/output.xml
new file mode 100644
index 0000000..f5539f4
--- /dev/null
+++ b/chapter33_xml/output.xml
@@ -0,0 +1,14 @@
+
+
+ Mike
+ Guido
+ Reminder
+ Don't forget the milk
+
+
+ Nicole
+ Guido
+ Appointment
+ Eye doctor
+
+
\ No newline at end of file
diff --git a/chapter33_xml/parse_xml.py b/chapter33_xml/parse_xml.py
new file mode 100644
index 0000000..4083e82
--- /dev/null
+++ b/chapter33_xml/parse_xml.py
@@ -0,0 +1,19 @@
+# parse_xml.py
+
+from xml.etree.ElementTree import ElementTree
+
+def parse_xml(xml_file):
+ tree = ElementTree(file=xml_file)
+ root_element = tree.getroot()
+ print(f"The root element's tag is '{root_element.tag}'")
+
+ for child_element in root_element:
+ print(f'{child_element.tag=}, {child_element.text=}')
+ if child_element.tag == 'note':
+ for note_element in child_element:
+ print(f'{note_element.tag=}, {note_element.text=}')
+
+
+if __name__ == '__main__':
+ parse_xml('note.xml')
+
diff --git a/chapter33_xml/parse_xml_with_lxml.py b/chapter33_xml/parse_xml_with_lxml.py
new file mode 100644
index 0000000..d81ba59
--- /dev/null
+++ b/chapter33_xml/parse_xml_with_lxml.py
@@ -0,0 +1,39 @@
+# parse_xml_with_lxml.py
+
+from lxml import etree, objectify
+
+def parse_xml(xml_file):
+ with open(xml_file) as f:
+ xml = f.read()
+
+ root = objectify.fromstring(xml)
+
+ # Get an element
+ to = root.note.to
+ print(f'The {to=}')
+
+ # print out all the note element's tags and text values
+ for note in root.getchildren():
+ for note_element in note.getchildren():
+ print(f'{note_element.tag=}, {note_element.text=}')
+ print()
+
+ # modify a text value
+ print(f'Original: {root.note.to=}')
+ root.note.to = 'Guido'
+ print(f'Modified: {root.note.to=}')
+
+ # add a new element
+ root.note.new_element = "I'm new!"
+
+ # cleanup the XML before writing to disk
+ objectify.deannotate(root)
+ etree.cleanup_namespaces(root)
+ obj_xml = etree.tostring(root, pretty_print=True)
+
+ # save your xml
+ with open("lxml_output.xml", "wb") as f:
+ f.write(obj_xml)
+
+if __name__ == '__main__':
+ parse_xml('note.xml')
\ No newline at end of file
diff --git a/chapter33_xml/test_create.xml b/chapter33_xml/test_create.xml
new file mode 100644
index 0000000..ef03836
--- /dev/null
+++ b/chapter33_xml/test_create.xml
@@ -0,0 +1,2 @@
+
+MikeNickAppointmentblah blah
\ No newline at end of file
diff --git a/chapter33_xml/xml_tree_iterator.py b/chapter33_xml/xml_tree_iterator.py
new file mode 100644
index 0000000..c7b0b95
--- /dev/null
+++ b/chapter33_xml/xml_tree_iterator.py
@@ -0,0 +1,13 @@
+# xml_tree_iterator.py
+
+from xml.etree.cElementTree import ElementTree
+
+def parse_xml(xml_file):
+ tree = ElementTree(file=xml_file)
+ print("Iterating using a tree iterator")
+ for elem in tree.iter():
+ print(f'{elem.tag=}, {elem.text=}')
+
+
+if __name__ == '__main__':
+ parse_xml('note.xml')
diff --git a/chapter34_json/create_json_file.py b/chapter34_json/create_json_file.py
new file mode 100644
index 0000000..6466678
--- /dev/null
+++ b/chapter34_json/create_json_file.py
@@ -0,0 +1,21 @@
+# create_json_file.py
+
+import json
+
+def create_json_file(path, obj):
+ with open(path, 'w') as fh:
+ json.dump(obj, fh)
+
+if __name__ == '__main__':
+ j = {"menu": {
+ "id": "file",
+ "value": "File",
+ "popup": {
+ "menuitem": [
+ {"value": "New", "onclick": "CreateNewDoc()"},
+ {"value": "Open", "onclick": "OpenDoc()"},
+ {"value": "Close", "onclick": "CloseDoc()"}
+ ]
+ }
+ }}
+ create_json_file('test.json', j)
\ No newline at end of file
diff --git a/chapter34_json/example.json b/chapter34_json/example.json
new file mode 100644
index 0000000..1faefce
--- /dev/null
+++ b/chapter34_json/example.json
@@ -0,0 +1 @@
+{"menu": {"id": "file", "value": "File", "popup": {"menuitem": [{"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"}]}}}
\ No newline at end of file
diff --git a/chapter34_json/load_json_file.py b/chapter34_json/load_json_file.py
new file mode 100644
index 0000000..769a42c
--- /dev/null
+++ b/chapter34_json/load_json_file.py
@@ -0,0 +1,12 @@
+# load_json_file.py
+
+import json
+
+def load_json_file(path):
+ with open(path) as fh:
+ j_obj = json.load(fh)
+ print(type(j_obj))
+
+
+if __name__ == '__main__':
+ load_json_file('example.json')
\ No newline at end of file
diff --git a/chapter35_scrape_website/downloading_files.py b/chapter35_scrape_website/downloading_files.py
new file mode 100644
index 0000000..ee766f7
--- /dev/null
+++ b/chapter35_scrape_website/downloading_files.py
@@ -0,0 +1,15 @@
+import urllib.request
+
+def download_file(url):
+ urllib.request.urlretrieve(url, "code.zip")
+
+def alternate_download(url):
+ with urllib.request.urlopen(url) as response:
+ data = response.read()
+
+ with open("code2.zip", "wb") as code:
+ code.write(data)
+
+if __name__ == '__main__':
+ url = 'http://www.blog.pythonlibrary.org/wp-content/uploads/2012/06/wxDbViewer.zip'
+ download_file(url)
\ No newline at end of file
diff --git a/chapter35_scrape_website/scraper.py b/chapter35_scrape_website/scraper.py
new file mode 100644
index 0000000..2da8526
--- /dev/null
+++ b/chapter35_scrape_website/scraper.py
@@ -0,0 +1,29 @@
+# scraper.py
+
+import urllib.request
+
+from bs4 import BeautifulSoup
+
+
+def download_html(url):
+ with urllib.request.urlopen(url) as response:
+ html = response.read()
+ return html
+
+def scraper(url):
+ html = download_html(url)
+ soup = BeautifulSoup(html, 'html.parser')
+
+ title_links = soup.findAll('h1')
+ articles = {}
+ for link in title_links:
+ if link.a:
+ articles[link.a['href']] = link.text.strip()
+
+ for article in articles:
+ print(f'{articles[article]} - {article}')
+
+
+if __name__ == '__main__':
+ url = 'https://www.blog.pythonlibrary.org'
+ scraper(url)
\ No newline at end of file
diff --git a/chapter36_csv/books.csv b/chapter36_csv/books.csv
new file mode 100644
index 0000000..9833652
--- /dev/null
+++ b/chapter36_csv/books.csv
@@ -0,0 +1,4 @@
+book_title,author,publisher,pub_date,isbn
+Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
+wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
+Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081
\ No newline at end of file
diff --git a/chapter36_csv/csv_dict_reader.py b/chapter36_csv/csv_dict_reader.py
new file mode 100644
index 0000000..0e0acc4
--- /dev/null
+++ b/chapter36_csv/csv_dict_reader.py
@@ -0,0 +1,12 @@
+# csv_dict_reader.py
+
+import csv
+
+def process_csv_dict_reader(file_obj):
+ reader = csv.DictReader(file_obj)
+ for line in reader:
+ print(f'{line["book_title"]} by {line["author"]}')
+
+if __name__ == '__main__':
+ with open('books.csv', newline='') as csvfile:
+ process_csv_dict_reader(csvfile)
\ No newline at end of file
diff --git a/chapter36_csv/csv_dict_writer.py b/chapter36_csv/csv_dict_writer.py
new file mode 100644
index 0000000..964144b
--- /dev/null
+++ b/chapter36_csv/csv_dict_writer.py
@@ -0,0 +1,28 @@
+# csv_dict_writer.py
+
+import csv
+
+def csv_dict_writer(path, headers, data):
+ with open(path, 'w', newline='') as csvfile:
+ writer = csv.DictWriter(csvfile, delimiter=',',
+ fieldnames=headers)
+ writer.writeheader()
+ for record in data:
+ writer.writerow(record)
+
+if __name__ == '__main__':
+ data = '''book_title,author,publisher,pub_date,isbn
+ Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
+ wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
+ Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081'''
+ records = []
+ for line in data.splitlines():
+ records.append(line.strip().split(','))
+ headers = records.pop(0)
+
+ list_of_dicts = []
+ for row in records:
+ my_dict = dict(zip(headers, row))
+ list_of_dicts.append(my_dict)
+
+ csv_dict_writer('output_dict.csv', headers, list_of_dicts)
\ No newline at end of file
diff --git a/chapter36_csv/csv_reader.py b/chapter36_csv/csv_reader.py
new file mode 100644
index 0000000..ccdc251
--- /dev/null
+++ b/chapter36_csv/csv_reader.py
@@ -0,0 +1,12 @@
+# csv_reader.py
+
+import csv
+
+def process_csv(path):
+ with open(path, newline='') as csvfile:
+ reader = csv.reader(csvfile)
+ for row in reader:
+ print(row)
+
+if __name__ == '__main__':
+ process_csv('books.csv')
\ No newline at end of file
diff --git a/chapter36_csv/csv_reader_no_header.py b/chapter36_csv/csv_reader_no_header.py
new file mode 100644
index 0000000..5030e66
--- /dev/null
+++ b/chapter36_csv/csv_reader_no_header.py
@@ -0,0 +1,14 @@
+# csv_reader_no_header.py
+
+import csv
+
+def process_csv(path):
+ with open(path, newline='') as csvfile:
+ reader = csv.reader(csvfile)
+ # Skip the header
+ next(reader, None)
+ for row in reader:
+ print(row)
+
+if __name__ == '__main__':
+ process_csv('books.csv')
\ No newline at end of file
diff --git a/chapter36_csv/csv_writer.py b/chapter36_csv/csv_writer.py
new file mode 100644
index 0000000..0fa594b
--- /dev/null
+++ b/chapter36_csv/csv_writer.py
@@ -0,0 +1,19 @@
+# csv_writer.py
+
+import csv
+
+def csv_writer(path, data):
+ with open(path, 'w', newline='') as csvfile:
+ writer = csv.writer(csvfile, delimiter=',')
+ for row in data:
+ writer.writerow(row)
+
+if __name__ == '__main__':
+ data = '''book_title,author,publisher,pub_date,isbn
+ Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
+ wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
+ Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081'''
+ records = []
+ for line in data.splitlines():
+ records.append(line.strip().split(','))
+ csv_writer('output.csv', records)
\ No newline at end of file
diff --git a/chapter36_csv/csv_writer_rows.py b/chapter36_csv/csv_writer_rows.py
new file mode 100644
index 0000000..0143498
--- /dev/null
+++ b/chapter36_csv/csv_writer_rows.py
@@ -0,0 +1,18 @@
+# csv_writer_rows.py
+
+import csv
+
+def csv_writer(path, data):
+ with open(path, 'w', newline='') as csvfile:
+ writer = csv.writer(csvfile, delimiter=',')
+ writer.writerows(data)
+
+if __name__ == '__main__':
+ data = '''book_title,author,publisher,pub_date,isbn
+ Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
+ wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
+ Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081'''
+ records = []
+ for line in data.splitlines():
+ records.append(line.strip().split(','))
+ csv_writer('output2.csv', records)
\ No newline at end of file
diff --git a/chapter36_csv/output.csv b/chapter36_csv/output.csv
new file mode 100644
index 0000000..6d9c4de
--- /dev/null
+++ b/chapter36_csv/output.csv
@@ -0,0 +1,4 @@
+book_title,author,publisher,pub_date,isbn
+Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
+wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
+Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081
diff --git a/chapter36_csv/output_dict.csv b/chapter36_csv/output_dict.csv
new file mode 100644
index 0000000..6d9c4de
--- /dev/null
+++ b/chapter36_csv/output_dict.csv
@@ -0,0 +1,4 @@
+book_title,author,publisher,pub_date,isbn
+Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
+wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
+Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081
diff --git a/chapter37_sqlite/add_data.py b/chapter37_sqlite/add_data.py
new file mode 100644
index 0000000..77c6a82
--- /dev/null
+++ b/chapter37_sqlite/add_data.py
@@ -0,0 +1,25 @@
+# add_data.py
+
+import sqlite3
+
+conn = sqlite3.connect("books.db")
+cursor = conn.cursor()
+
+# insert a record into the database
+cursor.execute("""INSERT INTO books
+ VALUES ('Python 101', 'Mike Driscoll', '9/01/2020',
+ 'Mouse Vs Python', 'epub')"""
+ )
+
+# save data to database
+conn.commit()
+
+# insert multiple records using the more secure "?" method
+books = [('Python Interviews', 'Mike Driscoll',
+ '2/1/2018', 'Packt Publishing', 'softcover'),
+ ('Automate the Boring Stuff with Python',
+ 'Al Sweigart', '', 'No Starch Press', 'PDF'),
+ ('The Well-Grounded Python Developer',
+ 'Doug Farrell', '2020', 'Manning', 'Kindle')]
+cursor.executemany("INSERT INTO books VALUES (?,?,?,?,?)", books)
+conn.commit()
\ No newline at end of file
diff --git a/chapter37_sqlite/create_database.py b/chapter37_sqlite/create_database.py
new file mode 100644
index 0000000..54ab740
--- /dev/null
+++ b/chapter37_sqlite/create_database.py
@@ -0,0 +1,13 @@
+# create_database.py
+
+import sqlite3
+
+conn = sqlite3.connect("books.db")
+
+cursor = conn.cursor()
+
+# create a table
+cursor.execute("""CREATE TABLE books
+ (title text, author text, release_date text,
+ publisher text, book_type text)
+ """)
\ No newline at end of file
diff --git a/chapter37_sqlite/delete_record.py b/chapter37_sqlite/delete_record.py
new file mode 100644
index 0000000..43c0726
--- /dev/null
+++ b/chapter37_sqlite/delete_record.py
@@ -0,0 +1,17 @@
+# delete_record.py
+
+import sqlite3
+
+def delete_author(author):
+ conn = sqlite3.connect("books.db")
+ cursor = conn.cursor()
+
+ sql = f"""
+ DELETE FROM books
+ WHERE author = '{author}'
+ """
+ cursor.execute(sql)
+ conn.commit()
+
+if __name__ == '__main__':
+ delete_author(author='Al Sweigart')
\ No newline at end of file
diff --git a/chapter37_sqlite/queries.py b/chapter37_sqlite/queries.py
new file mode 100644
index 0000000..7cb106f
--- /dev/null
+++ b/chapter37_sqlite/queries.py
@@ -0,0 +1,29 @@
+# queries.py
+
+import sqlite3
+
+def get_cursor():
+ conn = sqlite3.connect("books.db")
+ return conn.cursor()
+
+def select_all_records_by_author(cursor, author):
+ sql = "SELECT * FROM books WHERE author=?"
+ cursor.execute(sql, [author])
+ print(cursor.fetchall()) # or use fetchone()
+ print("\nHere is a listing of the rows in the table\n")
+ for row in cursor.execute("SELECT rowid, * FROM books ORDER BY author"):
+ print(row)
+
+def select_using_like(cursor, text):
+ print("\nLIKE query results:\n")
+ sql = f"""
+ SELECT * FROM books
+ WHERE title LIKE '{text}%'"""
+ cursor.execute(sql)
+ print(cursor.fetchall())
+
+if __name__ == '__main__':
+ cursor = get_cursor()
+ select_all_records_by_author(cursor,
+ author='Mike Driscoll')
+ select_using_like(cursor, text='Python')
\ No newline at end of file
diff --git a/chapter37_sqlite/update_record.py b/chapter37_sqlite/update_record.py
new file mode 100644
index 0000000..46ae430
--- /dev/null
+++ b/chapter37_sqlite/update_record.py
@@ -0,0 +1,19 @@
+# update_record.py
+
+import sqlite3
+
+
+def update_author(old_name, new_name):
+ conn = sqlite3.connect("books.db")
+ cursor = conn.cursor()
+ sql = f"""
+ UPDATE books
+ SET author = '{new_name}'
+ WHERE author = '{old_name}'
+ """
+ cursor.execute(sql)
+ conn.commit()
+
+if __name__ == '__main__':
+ update_author(old_name='Mike Driscoll',
+ new_name='Michael Driscoll')
\ No newline at end of file
diff --git a/chapter38_excel/books.xlsx b/chapter38_excel/books.xlsx
new file mode 100644
index 0000000..f57e615
Binary files /dev/null and b/chapter38_excel/books.xlsx differ
diff --git a/chapter38_excel/creating_sheets.py b/chapter38_excel/creating_sheets.py
new file mode 100644
index 0000000..d8bdb38
--- /dev/null
+++ b/chapter38_excel/creating_sheets.py
@@ -0,0 +1,18 @@
+# creating_sheets.py
+
+import openpyxl
+
+def create_worksheets(path):
+ workbook = openpyxl.Workbook()
+ print(workbook.sheetnames)
+ # Add a new worksheet
+ workbook.create_sheet()
+ print(workbook.sheetnames)
+ # Insert a worksheet
+ workbook.create_sheet(index=1,
+ title='Second sheet')
+ print(workbook.sheetnames)
+ workbook.save(path)
+
+if __name__ == '__main__':
+ create_worksheets('sheets.xlsx')
\ No newline at end of file
diff --git a/chapter38_excel/delete_demo.py b/chapter38_excel/delete_demo.py
new file mode 100644
index 0000000..58098a3
--- /dev/null
+++ b/chapter38_excel/delete_demo.py
@@ -0,0 +1,21 @@
+# delete_demo.py
+
+from openpyxl import Workbook
+
+def deleting_cols_rows(path):
+ workbook = Workbook()
+ sheet = workbook.active
+ sheet['A1'] = 'Hello'
+ sheet['B1'] = 'from'
+ sheet['C1'] = 'OpenPyXL'
+ sheet['A2'] = 'row 2'
+ sheet['A3'] = 'row 3'
+ sheet['A4'] = 'row 4'
+ # Delete column A
+ sheet.delete_cols(idx=1)
+ # delete 2 rows starting on the second row
+ sheet.delete_rows(idx=2, amount=2)
+ workbook.save(path)
+
+if __name__ == '__main__':
+ deleting_cols_rows('deleting.xlsx')
\ No newline at end of file
diff --git a/chapter38_excel/delete_sheets.py b/chapter38_excel/delete_sheets.py
new file mode 100644
index 0000000..026234e
--- /dev/null
+++ b/chapter38_excel/delete_sheets.py
@@ -0,0 +1,17 @@
+# delete_sheets.py
+
+import openpyxl
+
+def create_worksheets(path):
+ workbook = openpyxl.Workbook()
+ workbook.create_sheet()
+ # Insert a worksheet
+ workbook.create_sheet(index=1,
+ title='Second sheet')
+ print(workbook.sheetnames)
+ del workbook['Second sheet']
+ print(workbook.sheetnames)
+ workbook.save(path)
+
+if __name__ == '__main__':
+ create_worksheets('del_sheets.xlsx')
\ No newline at end of file
diff --git a/chapter38_excel/insert_demo.py b/chapter38_excel/insert_demo.py
new file mode 100644
index 0000000..8046b29
--- /dev/null
+++ b/chapter38_excel/insert_demo.py
@@ -0,0 +1,18 @@
+# insert_demo.py
+
+from openpyxl import Workbook
+
+def inserting_cols_rows(path):
+ workbook = Workbook()
+ sheet = workbook.active
+ sheet['A1'] = 'Hello'
+ sheet['A2'] = 'from'
+ sheet['A3'] = 'OpenPyXL'
+ # insert a column before A
+ sheet.insert_cols(idx=1)
+ # insert 2 rows starting on the second row
+ sheet.insert_rows(idx=2, amount=2)
+ workbook.save(path)
+
+if __name__ == '__main__':
+ inserting_cols_rows('inserting.xlsx')
\ No newline at end of file
diff --git a/chapter38_excel/iterating_over_cell_values.py b/chapter38_excel/iterating_over_cell_values.py
new file mode 100644
index 0000000..3f64c5e
--- /dev/null
+++ b/chapter38_excel/iterating_over_cell_values.py
@@ -0,0 +1,14 @@
+# iterating_over_cell_values.py
+
+from openpyxl import load_workbook
+
+def iterating_over_values(path):
+ workbook = load_workbook(filename=path)
+ sheet = workbook.active
+ for value in sheet.iter_rows(min_row=1, max_row=3,
+ min_col=1, max_col=3,
+ values_only=True):
+ print(value)
+
+if __name__ == '__main__':
+ iterating_over_values('books.xlsx')
\ No newline at end of file
diff --git a/chapter38_excel/iterating_over_cells.py b/chapter38_excel/iterating_over_cells.py
new file mode 100644
index 0000000..0cdd545
--- /dev/null
+++ b/chapter38_excel/iterating_over_cells.py
@@ -0,0 +1,12 @@
+# iterating_over_cells.py
+
+from openpyxl import load_workbook
+
+def iterating_range(path):
+ workbook = load_workbook(filename=path)
+ sheet = workbook.active
+ for cell in sheet['A']:
+ print(cell)
+
+if __name__ == '__main__':
+ iterating_range('books.xlsx')
\ No newline at end of file
diff --git a/chapter38_excel/open_workbook.py b/chapter38_excel/open_workbook.py
new file mode 100644
index 0000000..8e889d7
--- /dev/null
+++ b/chapter38_excel/open_workbook.py
@@ -0,0 +1,13 @@
+# open_workbook.py
+
+from openpyxl import load_workbook
+
+def open_workbook(path):
+ workbook = load_workbook(filename=path)
+ print(f'Worksheet names: {workbook.sheetnames}')
+ sheet = workbook.active
+ print(sheet)
+ print(f'The title of the Worksheet is: {sheet.title}')
+
+if __name__ == '__main__':
+ open_workbook('books.xlsx')
\ No newline at end of file
diff --git a/chapter38_excel/remove_sheets.py b/chapter38_excel/remove_sheets.py
new file mode 100644
index 0000000..9dbeb4f
--- /dev/null
+++ b/chapter38_excel/remove_sheets.py
@@ -0,0 +1,17 @@
+# remove_sheets.py
+
+import openpyxl
+
+def create_worksheets(path):
+ workbook = openpyxl.Workbook()
+ sheet1 = workbook.create_sheet()
+ # Insert a worksheet
+ workbook.create_sheet(index=1,
+ title='Second sheet')
+ print(workbook.sheetnames)
+ workbook.remove(workbook['Second sheet'])
+ print(workbook.sheetnames)
+ workbook.save(path)
+
+if __name__ == '__main__':
+ create_worksheets('remove_sheets.xlsx')
\ No newline at end of file
diff --git a/chapter38_excel/workbook_cells.py b/chapter38_excel/workbook_cells.py
new file mode 100644
index 0000000..82d6668
--- /dev/null
+++ b/chapter38_excel/workbook_cells.py
@@ -0,0 +1,24 @@
+# workbook_cells.py
+
+from openpyxl import load_workbook
+
+def get_cell_info(path):
+ workbook = load_workbook(filename=path)
+ sheet = workbook.active
+ print(sheet)
+ print(f'The title of the Worksheet is: {sheet.title}')
+ print(f'The value of {sheet["A2"].value=}')
+ print(f'The value of {sheet["A3"].value=}')
+ cell = sheet['B3']
+ print(f'{cell.value=}')
+
+def get_info_by_coord(path):
+ workbook = load_workbook(filename=path)
+ sheet = workbook.active
+ cell = sheet['A2']
+ print(f'Row {cell.row}, Col {cell.column} = {cell.value}')
+ print(f'{cell.value=} is at {cell.coordinate=}')
+
+if __name__ == '__main__':
+ get_cell_info('books.xlsx')
+ get_info_by_coord('books.xlsx')
\ No newline at end of file
diff --git a/chapter38_excel/writing_hello.py b/chapter38_excel/writing_hello.py
new file mode 100644
index 0000000..09be8ec
--- /dev/null
+++ b/chapter38_excel/writing_hello.py
@@ -0,0 +1,14 @@
+# writing_hello.py
+
+from openpyxl import Workbook
+
+def create_workbook(path):
+ workbook = Workbook()
+ sheet = workbook.active
+ sheet['A1'] = 'Hello'
+ sheet['A2'] = 'from'
+ sheet['A3'] = 'OpenPyXL'
+ workbook.save(path)
+
+if __name__ == '__main__':
+ create_workbook('hello.xlsx')
\ No newline at end of file
diff --git a/chapter39_reportlab/canvas_form.py b/chapter39_reportlab/canvas_form.py
new file mode 100644
index 0000000..f7cc75e
--- /dev/null
+++ b/chapter39_reportlab/canvas_form.py
@@ -0,0 +1,23 @@
+# canvas_form.py
+
+from reportlab.lib.pagesizes import letter
+from reportlab.pdfgen import canvas
+
+def form(path):
+ my_canvas = canvas.Canvas(path, pagesize=letter)
+ my_canvas.setLineWidth(.3)
+ my_canvas.setFont('Helvetica', 12)
+ my_canvas.drawString(30, 750, 'OFFICIAL COMMUNIQUE')
+ my_canvas.drawString(30, 735, 'OF ACME INDUSTRIES')
+ my_canvas.drawString(500, 750, "12/12/2010")
+ my_canvas.line(480, 747, 580, 747)
+ my_canvas.drawString(275, 725, 'AMOUNT OWED:')
+ my_canvas.drawString(500, 725, "$1,000.00")
+ my_canvas.line(378, 723, 580, 723)
+ my_canvas.drawString(30, 703, 'RECEIVED BY:')
+ my_canvas.line(120, 700, 580, 700)
+ my_canvas.drawString(120, 703, "JOHN DOE")
+ my_canvas.save()
+
+if __name__ == '__main__':
+ form('canvas_form.pdf')
\ No newline at end of file
diff --git a/chapter39_reportlab/drawing_polygons.py b/chapter39_reportlab/drawing_polygons.py
new file mode 100644
index 0000000..8c838e7
--- /dev/null
+++ b/chapter39_reportlab/drawing_polygons.py
@@ -0,0 +1,16 @@
+# drawing_polygons.py
+
+from reportlab.lib.pagesizes import letter
+from reportlab.pdfgen import canvas
+
+def draw_shapes():
+ my_canvas = canvas.Canvas("drawing_polygons.pdf")
+ my_canvas.setStrokeColorRGB(0.2, 0.5, 0.3)
+ my_canvas.rect(10, 740, 100, 80, stroke=1, fill=0)
+ my_canvas.ellipse(10, 680, 100, 630, stroke=1, fill=1)
+ my_canvas.wedge(10, 600, 100, 550, 45, 90, stroke=1, fill=0)
+ my_canvas.circle(300, 600, 50)
+ my_canvas.save()
+
+if __name__ == '__main__':
+ draw_shapes()
\ No newline at end of file
diff --git a/chapter39_reportlab/hello_platypus.py b/chapter39_reportlab/hello_platypus.py
new file mode 100644
index 0000000..7e29ee4
--- /dev/null
+++ b/chapter39_reportlab/hello_platypus.py
@@ -0,0 +1,25 @@
+# hello_platypus.py
+
+from reportlab.lib.pagesizes import letter
+from reportlab.platypus import SimpleDocTemplate, Paragraph
+from reportlab.lib.styles import getSampleStyleSheet
+
+def hello():
+ doc = SimpleDocTemplate("hello_platypus.pdf",
+ pagesize=letter,
+ rightMargin=72,
+ leftMargin=72,
+ topMargin=72,
+ bottomMargin=18)
+ styles = getSampleStyleSheet()
+
+ flowables = []
+
+ text = "Hello, I'm a Paragraph"
+ para = Paragraph(text, style=styles["Normal"])
+ flowables.append(para)
+
+ doc.build(flowables)
+
+if __name__ == '__main__':
+ hello()
\ No newline at end of file
diff --git a/chapter39_reportlab/hello_reportlab.py b/chapter39_reportlab/hello_reportlab.py
new file mode 100644
index 0000000..f1d75f9
--- /dev/null
+++ b/chapter39_reportlab/hello_reportlab.py
@@ -0,0 +1,7 @@
+# hello_reportlab.py
+
+from reportlab.pdfgen import canvas
+
+my_canvas = canvas.Canvas("hello.pdf")
+my_canvas.drawString(100, 750, "Welcome to Reportlab!")
+my_canvas.save()
\ No newline at end of file
diff --git a/chapter39_reportlab/image_on_canvas.py b/chapter39_reportlab/image_on_canvas.py
new file mode 100644
index 0000000..8be2a08
--- /dev/null
+++ b/chapter39_reportlab/image_on_canvas.py
@@ -0,0 +1,16 @@
+# image_on_canvas.py
+
+from reportlab.lib.pagesizes import letter
+from reportlab.pdfgen import canvas
+
+
+def add_image(image_path):
+ my_canvas = canvas.Canvas("canvas_image.pdf",
+ pagesize=letter)
+ my_canvas.drawImage(image_path, 30, 600,
+ width=100, height=100)
+ my_canvas.save()
+
+if __name__ == '__main__':
+ image_path = 'snakehead.jpg'
+ add_image(image_path)
\ No newline at end of file
diff --git a/chapter39_reportlab/platypus_multipage.py b/chapter39_reportlab/platypus_multipage.py
new file mode 100644
index 0000000..9a0fe76
--- /dev/null
+++ b/chapter39_reportlab/platypus_multipage.py
@@ -0,0 +1,26 @@
+# platypus_multipage.py
+
+from reportlab.lib.pagesizes import letter
+from reportlab.lib.styles import getSampleStyleSheet
+from reportlab.lib.units import inch
+from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
+
+
+def create_document():
+ doc = SimpleDocTemplate("platypus_multipage.pdf",
+ pagesize=letter)
+ styles = getSampleStyleSheet()
+ flowables = []
+ spacer = Spacer(1, 0.25*inch)
+
+ # Create a lot of content to make a multipage PDF
+ for i in range(50):
+ text = 'Paragraph #{}'.format(i)
+ para = Paragraph(text, styles["Normal"])
+ flowables.append(para)
+ flowables.append(spacer)
+
+ doc.build(flowables)
+
+if __name__ == '__main__':
+ create_document()
\ No newline at end of file
diff --git a/chapter39_reportlab/simple_table.py b/chapter39_reportlab/simple_table.py
new file mode 100644
index 0000000..19c201d
--- /dev/null
+++ b/chapter39_reportlab/simple_table.py
@@ -0,0 +1,21 @@
+# simple_table.py
+
+from reportlab.lib.pagesizes import letter
+from reportlab.platypus import SimpleDocTemplate, Table
+
+def simple_table():
+ doc = SimpleDocTemplate("simple_table.pdf", pagesize=letter)
+ flowables = []
+
+ data = [['col_{}'.format(x) for x in range(1, 6)],
+ [str(x) for x in range(1, 6)],
+ ['a', 'b', 'c', 'd', 'e']
+ ]
+
+ tbl = Table(data)
+ flowables.append(tbl)
+
+ doc.build(flowables)
+
+if __name__ == '__main__':
+ simple_table()
\ No newline at end of file
diff --git a/chapter39_reportlab/simple_table_with_style.py b/chapter39_reportlab/simple_table_with_style.py
new file mode 100644
index 0000000..db47c7e
--- /dev/null
+++ b/chapter39_reportlab/simple_table_with_style.py
@@ -0,0 +1,29 @@
+# simple_table_with_style.py
+
+from reportlab.lib import colors
+from reportlab.lib.pagesizes import letter
+from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
+
+def simple_table_with_style():
+ doc = SimpleDocTemplate("simple_table_with_style.pdf",
+ pagesize=letter)
+ flowables = []
+
+ data = [['col_{}'.format(x) for x in range(1, 6)],
+ [str(x) for x in range(1, 6)],
+ ['a', 'b', 'c', 'd', 'e']
+ ]
+
+ tblstyle = TableStyle(
+ [('BACKGROUND', (0, 0), (-1, 0), colors.red),
+ ('TEXTCOLOR', (0, 1), (-1, 1), colors.blue)
+ ])
+
+ tbl = Table(data)
+ tbl.setStyle(tblstyle)
+ flowables.append(tbl)
+
+ doc.build(flowables)
+
+if __name__ == '__main__':
+ simple_table_with_style()
\ No newline at end of file
diff --git a/chapter39_reportlab/snakehead.jpg b/chapter39_reportlab/snakehead.jpg
new file mode 100644
index 0000000..db89582
Binary files /dev/null and b/chapter39_reportlab/snakehead.jpg differ
diff --git a/chapter40_graphs/bar_chart.py b/chapter40_graphs/bar_chart.py
new file mode 100644
index 0000000..11808f3
--- /dev/null
+++ b/chapter40_graphs/bar_chart.py
@@ -0,0 +1,14 @@
+# bar_chart.py
+
+import matplotlib.pyplot as plt
+
+def bar_chart(numbers, labels, pos):
+ plt.bar(pos, numbers, color='blue')
+ plt.xticks(ticks=pos, labels=labels)
+ plt.show()
+
+if __name__ == '__main__':
+ numbers = [2, 1, 4, 6]
+ labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
+ pos = list(range(4))
+ bar_chart(numbers, labels, pos)
\ No newline at end of file
diff --git a/chapter40_graphs/bar_chart.title.py b/chapter40_graphs/bar_chart.title.py
new file mode 100644
index 0000000..a68a7b9
--- /dev/null
+++ b/chapter40_graphs/bar_chart.title.py
@@ -0,0 +1,18 @@
+# bar_chart_title.py
+
+import matplotlib.pyplot as plt
+
+def bar_chart(numbers, labels, pos):
+ plt.bar(pos, [4, 5, 6, 3], color='green')
+ plt.bar(pos, numbers, color='blue')
+ plt.xticks(ticks=pos, labels=labels)
+ plt.title('Gas Used in Various Vehicles')
+ plt.xlabel('Vehicle Types')
+ plt.ylabel('Number of Vehicles')
+ plt.show()
+
+if __name__ == '__main__':
+ numbers = [2, 1, 4, 6]
+ labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
+ pos = list(range(4))
+ bar_chart(numbers, labels, pos)
\ No newline at end of file
diff --git a/chapter40_graphs/bar_chart_labels.py b/chapter40_graphs/bar_chart_labels.py
new file mode 100644
index 0000000..2625f0f
--- /dev/null
+++ b/chapter40_graphs/bar_chart_labels.py
@@ -0,0 +1,16 @@
+# bar_chart_labels.py
+
+import matplotlib.pyplot as plt
+
+def bar_chart(numbers, labels, pos):
+ plt.bar(pos, numbers, color='blue')
+ plt.xticks(ticks=pos, labels=labels)
+ plt.xlabel('Vehicle Types')
+ plt.ylabel('Number of Vehicles')
+ plt.show()
+
+if __name__ == '__main__':
+ numbers = [2, 1, 4, 6]
+ labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
+ pos = list(range(4))
+ bar_chart(numbers, labels, pos)
\ No newline at end of file
diff --git a/chapter40_graphs/bar_chart_legend.py b/chapter40_graphs/bar_chart_legend.py
new file mode 100644
index 0000000..049be31
--- /dev/null
+++ b/chapter40_graphs/bar_chart_legend.py
@@ -0,0 +1,20 @@
+# bar_chart_legend.py
+
+import matplotlib.pyplot as plt
+
+def bar_chart(numbers, labels, pos):
+ plt.bar(pos, [4, 5, 6, 3], color='green')
+ plt.bar(pos, numbers, color='blue')
+ plt.xticks(ticks=pos, labels=labels)
+ plt.xlabel('Vehicle Types')
+ plt.ylabel('Number of Vehicles')
+ plt.title('Gas Used in Various Vehicles')
+ plt.legend(['First Label', 'Second Label'],
+ loc='upper left')
+ plt.show()
+
+if __name__ == '__main__':
+ numbers = [2, 1, 4, 6]
+ labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
+ pos = list(range(4))
+ bar_chart(numbers, labels, pos)
\ No newline at end of file
diff --git a/chapter40_graphs/bar_charth.py b/chapter40_graphs/bar_charth.py
new file mode 100644
index 0000000..cdd2763
--- /dev/null
+++ b/chapter40_graphs/bar_charth.py
@@ -0,0 +1,14 @@
+# bar_charth.py
+
+import matplotlib.pyplot as plt
+
+def bar_charth(numbers, labels, pos):
+ plt.barh(pos, numbers, color='blue')
+ plt.yticks(ticks=pos, labels=labels)
+ plt.show()
+
+if __name__ == '__main__':
+ numbers = [2, 1, 4, 6]
+ labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
+ pos = list(range(4))
+ bar_charth(numbers, labels, pos)
\ No newline at end of file
diff --git a/chapter40_graphs/line_plot.py b/chapter40_graphs/line_plot.py
new file mode 100644
index 0000000..03b7dd5
--- /dev/null
+++ b/chapter40_graphs/line_plot.py
@@ -0,0 +1,12 @@
+# line_plot.py
+
+import matplotlib.pyplot as plt
+
+def line_plot(numbers):
+ plt.plot(numbers)
+ plt.ylabel('Random numbers')
+ plt.show()
+
+if __name__ == '__main__':
+ numbers = [2, 4, 1, 6]
+ line_plot(numbers)
\ No newline at end of file
diff --git a/chapter40_graphs/multiple_figures.py b/chapter40_graphs/multiple_figures.py
new file mode 100644
index 0000000..ea4bf17
--- /dev/null
+++ b/chapter40_graphs/multiple_figures.py
@@ -0,0 +1,16 @@
+# multiple_figures.py
+
+import matplotlib.pyplot as plt
+
+def line_plot(numbers, numbers2):
+ first_plot = plt.figure(1)
+ plt.plot(numbers)
+
+ second_plot = plt.figure(2)
+ plt.plot(numbers2)
+ plt.show()
+
+if __name__ == '__main__':
+ numbers = [2, 4, 1, 6]
+ more_numbers = [5, 1, 10, 3]
+ line_plot(numbers, more_numbers)
\ No newline at end of file
diff --git a/chapter40_graphs/multiple_plots.py b/chapter40_graphs/multiple_plots.py
new file mode 100644
index 0000000..1b9b9af
--- /dev/null
+++ b/chapter40_graphs/multiple_plots.py
@@ -0,0 +1,18 @@
+# multiple_plots.py
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+def multiple_plots():
+ # Some example data to display
+ x = np.linspace(0, 2 * np.pi, 400)
+ y = np.sin(x ** 2)
+
+ fig, axs = plt.subplots(2)
+ fig.suptitle('Vertically stacked subplots')
+ axs[0].plot(x, y)
+ axs[1].plot(x, -y)
+ plt.show()
+
+if __name__ == '__main__':
+ multiple_plots()
\ No newline at end of file
diff --git a/chapter40_graphs/multiple_plots2.py b/chapter40_graphs/multiple_plots2.py
new file mode 100644
index 0000000..f0487cf
--- /dev/null
+++ b/chapter40_graphs/multiple_plots2.py
@@ -0,0 +1,15 @@
+# multiple_plots2.py
+
+import matplotlib.pyplot as plt
+
+def multiple_plots():
+ numbers = [2, 4, 1, 6]
+ more_numbers = [5, 1, 10, 3]
+ fig, axs = plt.subplots(2)
+ fig.suptitle('Vertically stacked subplots')
+ axs[0].plot(numbers)
+ axs[1].plot(more_numbers)
+ plt.show()
+
+if __name__ == '__main__':
+ multiple_plots()
\ No newline at end of file
diff --git a/chapter40_graphs/pie_chart_fancy.py b/chapter40_graphs/pie_chart_fancy.py
new file mode 100644
index 0000000..fef5f86
--- /dev/null
+++ b/chapter40_graphs/pie_chart_fancy.py
@@ -0,0 +1,19 @@
+# pie_chart.py
+
+import matplotlib.pyplot as plt
+
+def pie_chart():
+ numbers = [40, 35, 15, 10]
+ labels = ['Python', 'Ruby', 'C++', 'PHP']
+ # Explode the first slice (Python)
+ explode = (0.1, 0, 0, 0)
+
+ fig1, ax1 = plt.subplots()
+ ax1.pie(numbers, explode=explode, labels=labels,
+ shadow=True, startangle=90,
+ autopct='%1.1f%%')
+ ax1.axis('equal')
+ plt.show()
+
+if __name__ == '__main__':
+ pie_chart()
\ No newline at end of file
diff --git a/chapter40_graphs/pie_chart_plain.py b/chapter40_graphs/pie_chart_plain.py
new file mode 100644
index 0000000..d28980c
--- /dev/null
+++ b/chapter40_graphs/pie_chart_plain.py
@@ -0,0 +1,14 @@
+# pie_chart_plain.py
+
+import matplotlib.pyplot as plt
+
+def pie_chart():
+ numbers = [40, 35, 15, 10]
+ labels = ['Python', 'Ruby', 'C++', 'PHP']
+
+ fig1, ax1 = plt.subplots()
+ ax1.pie(numbers, labels=labels)
+ plt.show()
+
+if __name__ == '__main__':
+ pie_chart()
\ No newline at end of file
diff --git a/chapter41_images/blur.py b/chapter41_images/blur.py
new file mode 100644
index 0000000..4dff2cf
--- /dev/null
+++ b/chapter41_images/blur.py
@@ -0,0 +1,13 @@
+# blur.py
+
+from PIL import Image
+from PIL import ImageFilter
+
+
+def blur(path, modified_photo):
+ image = Image.open(path)
+ blurred_image = image.filter(ImageFilter.BLUR)
+ blurred_image.save(modified_photo)
+
+if __name__ == '__main__':
+ blur('butterfly.jpg', 'butterfly_blurred.jpg')
\ No newline at end of file
diff --git a/chapter41_images/border.py b/chapter41_images/border.py
new file mode 100644
index 0000000..675d3ff
--- /dev/null
+++ b/chapter41_images/border.py
@@ -0,0 +1,20 @@
+# border.py
+
+from PIL import Image, ImageOps
+
+
+def add_border(input_image, output_image, border):
+ img = Image.open(input_image)
+
+ if isinstance(border, int) or isinstance(border, tuple):
+ bimg = ImageOps.expand(img, border=border)
+ else:
+ raise RuntimeError('Border is not an integer or tuple!')
+
+ bimg.save(output_image)
+
+if __name__ == '__main__':
+ in_img = 'butterfly_grey.jpg'
+
+ add_border(in_img, output_image='butterfly_border.jpg',
+ border=100)
diff --git a/chapter41_images/border2.py b/chapter41_images/border2.py
new file mode 100644
index 0000000..671cbd1
--- /dev/null
+++ b/chapter41_images/border2.py
@@ -0,0 +1,20 @@
+# border2.py
+
+from PIL import Image, ImageOps
+
+
+def add_border(input_image, output_image, border):
+ img = Image.open(input_image)
+
+ if isinstance(border, int) or isinstance(border, tuple):
+ bimg = ImageOps.expand(img, border=border)
+ else:
+ raise RuntimeError('Border is not an integer or tuple!')
+
+ bimg.save(output_image)
+
+if __name__ == '__main__':
+ in_img = 'butterfly_grey.jpg'
+
+ add_border(in_img, output_image='butterfly_border2.jpg',
+ border=(10, 50))
diff --git a/chapter41_images/butterfly.jpg b/chapter41_images/butterfly.jpg
new file mode 100644
index 0000000..9750c31
Binary files /dev/null and b/chapter41_images/butterfly.jpg differ
diff --git a/chapter41_images/butterfly_grey.jpg b/chapter41_images/butterfly_grey.jpg
new file mode 100644
index 0000000..f416524
Binary files /dev/null and b/chapter41_images/butterfly_grey.jpg differ
diff --git a/chapter41_images/colored_border.py b/chapter41_images/colored_border.py
new file mode 100644
index 0000000..2c2d37a
--- /dev/null
+++ b/chapter41_images/colored_border.py
@@ -0,0 +1,25 @@
+# colored_border.py
+
+from PIL import Image, ImageOps
+
+def add_border(input_image, output_image, border, color=0):
+ img = Image.open(input_image)
+
+ if isinstance(border, int) or isinstance(
+ border, tuple):
+ bimg = ImageOps.expand(img,
+ border=border,
+ fill=color)
+ else:
+ msg = 'Border is not an integer or tuple!'
+ raise RuntimeError(msg)
+
+ bimg.save(output_image)
+
+if __name__ == '__main__':
+ in_img = 'butterfly_grey.jpg'
+
+ add_border(in_img,
+ output_image='butterfly_border_red.jpg',
+ border=100,
+ color='indianred')
\ No newline at end of file
diff --git a/chapter41_images/cropping.py b/chapter41_images/cropping.py
new file mode 100644
index 0000000..7eb5883
--- /dev/null
+++ b/chapter41_images/cropping.py
@@ -0,0 +1,12 @@
+# cropping.py
+
+from PIL import Image
+
+
+def crop_image(path, cropped_path):
+ image = Image.open(path)
+ cropped = image.crop((40, 590, 979, 1500))
+ cropped.save(cropped_path)
+
+if __name__ == '__main__':
+ crop_image('ducks.jpg', 'ducks_cropped.jpg')
\ No newline at end of file
diff --git a/chapter41_images/ducks.jpg b/chapter41_images/ducks.jpg
new file mode 100644
index 0000000..86837a1
Binary files /dev/null and b/chapter41_images/ducks.jpg differ
diff --git a/chapter41_images/get_histogram.py b/chapter41_images/get_histogram.py
new file mode 100644
index 0000000..32964ab
--- /dev/null
+++ b/chapter41_images/get_histogram.py
@@ -0,0 +1,16 @@
+# get_histrogram.py
+
+import matplotlib.pyplot as plt
+
+from PIL import Image
+
+
+def get_image_histrogram(path):
+ image = Image.open(path)
+ histogram = image.histogram()
+ plt.hist(histogram, bins=len(histogram))
+ plt.xlabel('Histogram')
+ plt.show()
+
+if __name__ == '__main__':
+ get_image_histrogram('butterfly.jpg')
\ No newline at end of file
diff --git a/chapter41_images/get_image_info.py b/chapter41_images/get_image_info.py
new file mode 100644
index 0000000..1b6736f
--- /dev/null
+++ b/chapter41_images/get_image_info.py
@@ -0,0 +1,12 @@
+# get_image_info.py
+
+from PIL import Image
+
+def get_image_info(path):
+ image = Image.open(path)
+ print(f'This image is {image.width} x {image.height}')
+ exif = image._getexif()
+ print(exif)
+
+if __name__ == '__main__':
+ get_image_info('ducks.jpg')
\ No newline at end of file
diff --git a/chapter41_images/jellyfish.jpg b/chapter41_images/jellyfish.jpg
new file mode 100644
index 0000000..3cee85e
Binary files /dev/null and b/chapter41_images/jellyfish.jpg differ
diff --git a/chapter41_images/lizard.jpg b/chapter41_images/lizard.jpg
new file mode 100644
index 0000000..535baf8
Binary files /dev/null and b/chapter41_images/lizard.jpg differ
diff --git a/chapter41_images/open_image.py b/chapter41_images/open_image.py
new file mode 100644
index 0000000..3459f7c
--- /dev/null
+++ b/chapter41_images/open_image.py
@@ -0,0 +1,6 @@
+# open_image.py
+
+from PIL import Image
+
+image = Image.open('jellyfish.jpg')
+image.show()
\ No newline at end of file
diff --git a/chapter41_images/resize_image.py b/chapter41_images/resize_image.py
new file mode 100644
index 0000000..bec9953
--- /dev/null
+++ b/chapter41_images/resize_image.py
@@ -0,0 +1,23 @@
+# resize_image.py
+
+from PIL import Image
+
+def resize_image(input_image_path,
+ output_image_path,
+ size):
+ original_image = Image.open(input_image_path)
+ width, height = original_image.size
+ print(f'The original image size is {width} wide x {height} '
+ f'high')
+
+ resized_image = original_image.resize(size)
+ width, height = resized_image.size
+ print(f'The resized image size is {width} wide x {height} '
+ f'high')
+ resized_image.show()
+ resized_image.save(output_image_path)
+
+if __name__ == '__main__':
+ resize_image(input_image_path='lizard.jpg',
+ output_image_path='lizard_small.jpg',
+ size=(800, 400))
\ No newline at end of file
diff --git a/chapter41_images/scale_image.py b/chapter41_images/scale_image.py
new file mode 100644
index 0000000..aa2febc
--- /dev/null
+++ b/chapter41_images/scale_image.py
@@ -0,0 +1,37 @@
+# scale_image.py
+
+from PIL import Image
+
+def scale_image(input_image_path,
+ output_image_path,
+ width=None,
+ height=None
+ ):
+ original_image = Image.open(input_image_path)
+ w, h = original_image.size
+ print(f'The original image size is {w} wide x {h} '
+ 'high')
+
+ if width and height:
+ max_size = (width, height)
+ elif width:
+ max_size = (width, h)
+ elif height:
+ max_size = (w, height)
+ else:
+ # No width or height specified
+ raise ValueError('Width or height required!')
+
+ original_image.thumbnail(max_size, Image.ANTIALIAS)
+ original_image.save(output_image_path)
+
+ scaled_image = Image.open(output_image_path)
+ width, height = scaled_image.size
+ print(f'The scaled image size is {width} wide x {height} '
+ 'high')
+
+
+if __name__ == '__main__':
+ scale_image(input_image_path='lizard.jpg',
+ output_image_path='lizard_scaled.jpg',
+ width=800)
\ No newline at end of file
diff --git a/chapter41_images/sharpen.py b/chapter41_images/sharpen.py
new file mode 100644
index 0000000..494b0fa
--- /dev/null
+++ b/chapter41_images/sharpen.py
@@ -0,0 +1,13 @@
+# sharpen.py
+
+from PIL import Image
+from PIL import ImageFilter
+
+
+def sharpen(path, modified_photo):
+ image = Image.open(path)
+ sharpened_image = image.filter(ImageFilter.SHARPEN)
+ sharpened_image.save(modified_photo)
+
+if __name__ == '__main__':
+ sharpen('butterfly.jpg', 'butterfly_sharper.jpg')
\ No newline at end of file
diff --git a/chapter42_gui/button_events.py b/chapter42_gui/button_events.py
new file mode 100644
index 0000000..b282fab
--- /dev/null
+++ b/chapter42_gui/button_events.py
@@ -0,0 +1,41 @@
+# button_events.py
+
+import wx
+
+
+class MyPanel(wx.Panel):
+
+ def __init__(self, parent):
+ super().__init__(parent)
+
+ button = wx.Button(self, label='Press Me')
+ button.Bind(wx.EVT_BUTTON, self.on_button1)
+ button2 = wx.Button(self, label='Second button')
+ button2.Bind(wx.EVT_BUTTON, self.on_button2)
+
+ main_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ main_sizer.Add(button, proportion=1,
+ flag=wx.ALL | wx.CENTER | wx.EXPAND,
+ border=5)
+ main_sizer.Add(button2, 0, wx.ALL, 5)
+ self.SetSizer(main_sizer)
+
+ def on_button1(self, event):
+ print('You clicked the first button')
+
+ def on_button2(self, event):
+ print('You clicked the second button')
+
+
+class MyFrame(wx.Frame):
+
+ def __init__(self):
+ super().__init__(None, title='Hello World')
+ panel = MyPanel(self)
+ self.Show()
+
+
+if __name__ == '__main__':
+ app = wx.App(redirect=False)
+ frame = MyFrame()
+ app.MainLoop()
\ No newline at end of file
diff --git a/chapter42_gui/hello_with_panel.py b/chapter42_gui/hello_with_panel.py
new file mode 100644
index 0000000..f6bb3e8
--- /dev/null
+++ b/chapter42_gui/hello_with_panel.py
@@ -0,0 +1,23 @@
+# hello_with_panel.py
+
+import wx
+
+
+class MyPanel(wx.Panel):
+
+ def __init__(self, parent):
+ super().__init__(parent)
+ button = wx.Button(self, label='Press Me')
+
+class MyFrame(wx.Frame):
+
+ def __init__(self):
+ super().__init__(None, title='Hello World')
+ panel = MyPanel(self)
+ self.Show()
+
+
+if __name__ == '__main__':
+ app = wx.App(redirect=False)
+ frame = MyFrame()
+ app.MainLoop()
\ No newline at end of file
diff --git a/chapter42_gui/hello_wx.py b/chapter42_gui/hello_wx.py
new file mode 100644
index 0000000..7dfe858
--- /dev/null
+++ b/chapter42_gui/hello_wx.py
@@ -0,0 +1,8 @@
+# hello_wx.py
+
+import wx
+
+app = wx.App(False)
+frame = wx.Frame(parent=None, title='Hello World')
+frame.Show()
+app.MainLoop()
diff --git a/chapter42_gui/hello_wx_class.py b/chapter42_gui/hello_wx_class.py
new file mode 100644
index 0000000..7a23617
--- /dev/null
+++ b/chapter42_gui/hello_wx_class.py
@@ -0,0 +1,15 @@
+# hello_wx_class.py
+
+import wx
+
+class MyFrame(wx.Frame):
+
+ def __init__(self):
+ super().__init__(None, title='Hello World')
+ self.Show()
+
+if __name__ == '__main__':
+ app = wx.App(False)
+ frame = MyFrame()
+ frame.Show()
+ app.MainLoop()
diff --git a/chapter42_gui/image_viewer.py b/chapter42_gui/image_viewer.py
new file mode 100644
index 0000000..38dd872
--- /dev/null
+++ b/chapter42_gui/image_viewer.py
@@ -0,0 +1,34 @@
+# image_viewer.py
+
+import wx
+
+class ImagePanel(wx.Panel):
+
+ def __init__(self, parent, image_size):
+ super().__init__(parent)
+
+ img = wx.Image(*image_size)
+ self.image_ctrl = wx.StaticBitmap(self,
+ bitmap=wx.Bitmap(img))
+ browse_btn = wx.Button(self, label='Browse')
+
+ main_sizer = wx.BoxSizer(wx.VERTICAL)
+ main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
+ main_sizer.Add(browse_btn)
+ self.SetSizer(main_sizer)
+ main_sizer.Fit(parent)
+ self.Layout()
+
+
+class MainFrame(wx.Frame):
+
+ def __init__(self):
+ super().__init__(None, title='Image Viewer')
+ panel = ImagePanel(self, image_size=(240,240))
+ self.Show()
+
+
+if __name__ == '__main__':
+ app = wx.App(redirect=False)
+ frame = MainFrame()
+ app.MainLoop()
\ No newline at end of file
diff --git a/chapter42_gui/image_viewer_working.py b/chapter42_gui/image_viewer_working.py
new file mode 100644
index 0000000..3abd01f
--- /dev/null
+++ b/chapter42_gui/image_viewer_working.py
@@ -0,0 +1,78 @@
+# image_viewer_working.py
+
+import wx
+
+class ImagePanel(wx.Panel):
+
+ def __init__(self, parent, image_size):
+ super().__init__(parent)
+ self.max_size = 240
+
+ img = wx.Image(*image_size)
+ self.image_ctrl = wx.StaticBitmap(self,
+ bitmap=wx.Bitmap(img))
+
+ browse_btn = wx.Button(self, label='Browse')
+ browse_btn.Bind(wx.EVT_BUTTON, self.on_browse)
+
+ self.photo_txt = wx.TextCtrl(self, size=(200, -1))
+
+ main_sizer = wx.BoxSizer(wx.VERTICAL)
+ hsizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
+ hsizer.Add(browse_btn, 0, wx.ALL, 5)
+ hsizer.Add(self.photo_txt, 0, wx.ALL, 5)
+ main_sizer.Add(hsizer, 0, wx.ALL, 5)
+
+ self.SetSizer(main_sizer)
+ main_sizer.Fit(parent)
+ self.Layout()
+
+ def on_browse(self, event):
+ """
+ Browse for an image file
+ @param event: The event object
+ """
+ wildcard = "JPEG files (*.jpg)|*.jpg"
+ with wx.FileDialog(None, "Choose a file",
+ wildcard=wildcard,
+ style=wx.ID_OPEN) as dialog:
+ if dialog.ShowModal() == wx.ID_OK:
+ self.photo_txt.SetValue(dialog.GetPaths()[0])
+ self.load_image()
+
+ def load_image(self):
+ """
+ Load the image and display it to the user
+ """
+ filepath = self.photo_txt.GetValue()
+ img = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
+
+ # scale the image, preserving the aspect ratio
+ W = img.GetWidth()
+ H = img.GetHeight()
+ if W > H:
+ NewW = self.max_size
+ NewH = self.max_size * H / W
+ else:
+ NewH = self.max_size
+ NewW = self.max_size * W / H
+ img = img.Scale(NewW,NewH)
+
+ self.image_ctrl.SetBitmap(wx.Bitmap(img))
+ self.Refresh()
+
+
+class MainFrame(wx.Frame):
+
+ def __init__(self):
+ super().__init__(None, title='Image Viewer')
+ panel = ImagePanel(self, image_size=(240,240))
+ self.Show()
+
+
+if __name__ == '__main__':
+ app = wx.App(redirect=False)
+ frame = MainFrame()
+ app.MainLoop()
\ No newline at end of file
diff --git a/chapter42_gui/sizer_with_two_widgets.py b/chapter42_gui/sizer_with_two_widgets.py
new file mode 100644
index 0000000..f69c706
--- /dev/null
+++ b/chapter42_gui/sizer_with_two_widgets.py
@@ -0,0 +1,33 @@
+# sizer_with_two_widgets.py
+
+import wx
+
+
+class MyPanel(wx.Panel):
+
+ def __init__(self, parent):
+ super().__init__(parent)
+
+ button = wx.Button(self, label='Press Me')
+ button2 = wx.Button(self, label='Second button')
+
+ main_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ main_sizer.Add(button, proportion=1,
+ flag=wx.ALL | wx.CENTER | wx.EXPAND,
+ border=5)
+ main_sizer.Add(button2, 0, wx.ALL, 5)
+ self.SetSizer(main_sizer)
+
+
+class MyFrame(wx.Frame):
+
+ def __init__(self):
+ super().__init__(None, title='Hello World')
+ panel = MyPanel(self)
+ self.Show()
+
+
+if __name__ == '__main__':
+ app = wx.App(redirect=False)
+ frame = MyFrame()
+ app.MainLoop()
\ No newline at end of file
diff --git a/chapter42_gui/stacked_buttons.py b/chapter42_gui/stacked_buttons.py
new file mode 100644
index 0000000..f8ce7de
--- /dev/null
+++ b/chapter42_gui/stacked_buttons.py
@@ -0,0 +1,25 @@
+# stacked_buttons.py
+
+import wx
+
+
+class MyPanel(wx.Panel):
+
+ def __init__(self, parent):
+ super().__init__(parent)
+ button = wx.Button(self, label='Press Me')
+ button2 = wx.Button(self, label='Press Me too')
+ button3 = wx.Button(self, label='Another button')
+
+class MyFrame(wx.Frame):
+
+ def __init__(self):
+ super().__init__(None, title='Hello World')
+ panel = MyPanel(self)
+ self.Show()
+
+
+if __name__ == '__main__':
+ app = wx.App(redirect=False)
+ frame = MyFrame()
+ app.MainLoop()
\ No newline at end of file
diff --git a/chapter43_packages/arithmetic/__init__.py b/chapter43_packages/arithmetic/__init__.py
new file mode 100644
index 0000000..be3c5fc
--- /dev/null
+++ b/chapter43_packages/arithmetic/__init__.py
@@ -0,0 +1,2 @@
+# __init__.py
+from . import add
\ No newline at end of file
diff --git a/Chapter 36 - creating modules and packages/mymath/add.py b/chapter43_packages/arithmetic/add.py
similarity index 75%
rename from Chapter 36 - creating modules and packages/mymath/add.py
rename to chapter43_packages/arithmetic/add.py
index 370d4fb..07fb1d6 100644
--- a/Chapter 36 - creating modules and packages/mymath/add.py
+++ b/chapter43_packages/arithmetic/add.py
@@ -1,2 +1,4 @@
+# add.py
+
def add(x, y):
return x + y
\ No newline at end of file
diff --git a/chapter43_packages/arithmetic/divide.py b/chapter43_packages/arithmetic/divide.py
new file mode 100644
index 0000000..1f6707b
--- /dev/null
+++ b/chapter43_packages/arithmetic/divide.py
@@ -0,0 +1,4 @@
+# divide.py
+
+def divide(x, y):
+ return x / y
\ No newline at end of file
diff --git a/Chapter 36 - creating modules and packages/mymath/multiply.py b/chapter43_packages/arithmetic/multiply.py
similarity index 70%
rename from Chapter 36 - creating modules and packages/mymath/multiply.py
rename to chapter43_packages/arithmetic/multiply.py
index 43dfa55..0a4dcbc 100644
--- a/Chapter 36 - creating modules and packages/mymath/multiply.py
+++ b/chapter43_packages/arithmetic/multiply.py
@@ -1,2 +1,4 @@
+# multiply.py
+
def multiply(x, y):
return x * y
\ No newline at end of file
diff --git a/Chapter 36 - creating modules and packages/mymath/subtract.py b/chapter43_packages/arithmetic/subtract.py
similarity index 70%
rename from Chapter 36 - creating modules and packages/mymath/subtract.py
rename to chapter43_packages/arithmetic/subtract.py
index 910a92a..f9340ac 100644
--- a/Chapter 36 - creating modules and packages/mymath/subtract.py
+++ b/chapter43_packages/arithmetic/subtract.py
@@ -1,2 +1,4 @@
+# subtract.py
+
def subtract(x, y):
return x - y
\ No newline at end of file
diff --git a/chapter43_packages/module/arithmetic.py b/chapter43_packages/module/arithmetic.py
new file mode 100644
index 0000000..f49c8db
--- /dev/null
+++ b/chapter43_packages/module/arithmetic.py
@@ -0,0 +1,13 @@
+# arithmetic.py
+
+def add(x, y):
+ return x + y
+
+def divide(x, y):
+ return x / y
+
+def multiply(x, y):
+ return x * y
+
+def subtract(x, y):
+ return x - y
diff --git a/chapter43_packages/module/test_arithmetic.py b/chapter43_packages/module/test_arithmetic.py
new file mode 100644
index 0000000..f259dcf
--- /dev/null
+++ b/chapter43_packages/module/test_arithmetic.py
@@ -0,0 +1,22 @@
+# test_arithmetic.py
+
+import arithmetic
+import unittest
+
+class TestArithmetic(unittest.TestCase):
+
+ def test_addition(self):
+ self.assertEqual(arithmetic.add(1, 2), 3)
+
+ def test_subtraction(self):
+ self.assertEqual(arithmetic.subtract(2, 1), 1)
+
+ def test_multiplication(self):
+ self.assertEqual(arithmetic.multiply(5, 5), 25)
+
+ def test_division(self):
+ self.assertEqual(arithmetic.divide(8, 2), 4)
+
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/chapter43_packages/my_package/LICENSE b/chapter43_packages/my_package/LICENSE
new file mode 100644
index 0000000..153d416
--- /dev/null
+++ b/chapter43_packages/my_package/LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
\ No newline at end of file
diff --git a/Chapter 36 - creating modules and packages/mymath/adv/__init__.py b/chapter43_packages/my_package/README.md
similarity index 100%
rename from Chapter 36 - creating modules and packages/mymath/adv/__init__.py
rename to chapter43_packages/my_package/README.md
diff --git a/chapter43_packages/my_package/arithmetic/__init__.py b/chapter43_packages/my_package/arithmetic/__init__.py
new file mode 100644
index 0000000..be3c5fc
--- /dev/null
+++ b/chapter43_packages/my_package/arithmetic/__init__.py
@@ -0,0 +1,2 @@
+# __init__.py
+from . import add
\ No newline at end of file
diff --git a/chapter43_packages/my_package/arithmetic/add.py b/chapter43_packages/my_package/arithmetic/add.py
new file mode 100644
index 0000000..07fb1d6
--- /dev/null
+++ b/chapter43_packages/my_package/arithmetic/add.py
@@ -0,0 +1,4 @@
+# add.py
+
+def add(x, y):
+ return x + y
\ No newline at end of file
diff --git a/chapter43_packages/my_package/arithmetic/divide.py b/chapter43_packages/my_package/arithmetic/divide.py
new file mode 100644
index 0000000..1f6707b
--- /dev/null
+++ b/chapter43_packages/my_package/arithmetic/divide.py
@@ -0,0 +1,4 @@
+# divide.py
+
+def divide(x, y):
+ return x / y
\ No newline at end of file
diff --git a/chapter43_packages/my_package/arithmetic/multiply.py b/chapter43_packages/my_package/arithmetic/multiply.py
new file mode 100644
index 0000000..0a4dcbc
--- /dev/null
+++ b/chapter43_packages/my_package/arithmetic/multiply.py
@@ -0,0 +1,4 @@
+# multiply.py
+
+def multiply(x, y):
+ return x * y
\ No newline at end of file
diff --git a/chapter43_packages/my_package/arithmetic/subtract.py b/chapter43_packages/my_package/arithmetic/subtract.py
new file mode 100644
index 0000000..f9340ac
--- /dev/null
+++ b/chapter43_packages/my_package/arithmetic/subtract.py
@@ -0,0 +1,4 @@
+# subtract.py
+
+def subtract(x, y):
+ return x - y
\ No newline at end of file
diff --git a/chapter43_packages/my_package/setup.py b/chapter43_packages/my_package/setup.py
new file mode 100644
index 0000000..4684c74
--- /dev/null
+++ b/chapter43_packages/my_package/setup.py
@@ -0,0 +1,22 @@
+import setuptools
+
+with open("README.md", "r") as fh:
+ long_description = fh.read()
+
+setuptools.setup(
+ name="arithmetic-YOUR-USERNAME-HERE", # Replace with your own username
+ version="0.0.1",
+ author="Mike Driscoll",
+ author_email="driscoll@example.com",
+ description="A simple arithmetic package",
+ long_description=long_description,
+ long_description_content_type="text/markdown",
+ url="https://github.com/driscollis/arithmetic",
+ packages=setuptools.find_packages(),
+ classifiers=[
+ "Programming Language :: Python :: 3",
+ "License :: OSI Approved :: MIT License",
+ "Operating System :: OS Independent",
+ ],
+ python_requires='>=3.6',
+)
\ No newline at end of file
diff --git a/chapter44_pyinstaller/image_viewer.py b/chapter44_pyinstaller/image_viewer.py
new file mode 100644
index 0000000..8e4dec4
--- /dev/null
+++ b/chapter44_pyinstaller/image_viewer.py
@@ -0,0 +1,78 @@
+# image_viewer_working.py
+
+import wx
+
+class ImagePanel(wx.Panel):
+
+ def __init__(self, parent, image_size):
+ super().__init__(parent)
+ self.max_size = 240
+
+ img = wx.Image(*image_size)
+ self.image_ctrl = wx.StaticBitmap(self,
+ bitmap=wx.Bitmap(img))
+
+ browse_btn = wx.Button(self, label='Browse')
+ browse_btn.Bind(wx.EVT_BUTTON, self.on_browse)
+
+ self.photo_txt = wx.TextCtrl(self, size=(200, -1))
+
+ main_sizer = wx.BoxSizer(wx.VERTICAL)
+ hsizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
+ hsizer.Add(browse_btn, 0, wx.ALL, 5)
+ hsizer.Add(self.photo_txt, 0, wx.ALL, 5)
+ main_sizer.Add(hsizer, 0, wx.ALL, 5)
+
+ self.SetSizer(main_sizer)
+ main_sizer.Fit(parent)
+ self.Layout()
+
+ def on_browse(self, event):
+ """
+ Browse for an image file
+ @param event: The event object
+ """
+ wildcard = "JPEG files (*.jpg)|*.jpg"
+ with wx.FileDialog(None, "Choose a file",
+ wildcard=wildcard,
+ style=wx.ID_OPEN) as dialog:
+ if dialog.ShowModal() == wx.ID_OK:
+ self.photo_txt.SetValue(dialog.GetPath())
+ self.load_image()
+
+ def load_image(self):
+ """
+ Load the image and display it to the user
+ """
+ filepath = self.photo_txt.GetValue()
+ img = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
+
+ # scale the image, preserving the aspect ratio
+ W = img.GetWidth()
+ H = img.GetHeight()
+ if W > H:
+ NewW = self.max_size
+ NewH = self.max_size * H / W
+ else:
+ NewH = self.max_size
+ NewW = self.max_size * W / H
+ img = img.Scale(NewW,NewH)
+
+ self.image_ctrl.SetBitmap(wx.Bitmap(img))
+ self.Refresh()
+
+
+class MainFrame(wx.Frame):
+
+ def __init__(self):
+ super().__init__(None, title='Image Viewer')
+ panel = ImagePanel(self, image_size=(240,240))
+ self.Show()
+
+
+if __name__ == '__main__':
+ app = wx.App(redirect=False)
+ frame = MainFrame()
+ app.MainLoop()
\ No newline at end of file
diff --git a/chapter44_pyinstaller/pysearch.py b/chapter44_pyinstaller/pysearch.py
new file mode 100644
index 0000000..9a2e0cc
--- /dev/null
+++ b/chapter44_pyinstaller/pysearch.py
@@ -0,0 +1,49 @@
+# pysearch.py
+
+import argparse
+import pathlib
+
+
+def search_folder(path, extension, file_size=None):
+ """
+ Search folder for files
+ """
+ folder = pathlib.Path(path)
+ files = list(folder.rglob(f'*.{extension}'))
+
+ if not files:
+ print(f'No files found with {extension=}')
+ return
+
+ if file_size is not None:
+ files = [f for f in files
+ if f.stat().st_size > file_size]
+
+ print(f'{len(files)} *.{extension} files found:')
+ for file_path in files:
+ print(file_path)
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ 'PySearch',
+ description='PySearch - The Python Powered File Searcher')
+ parser.add_argument('-p', '--path',
+ help='The path to search for files',
+ required=True,
+ dest='path')
+ parser.add_argument('-e', '--ext',
+ help='The extension to search for',
+ required=True,
+ dest='extension')
+ parser.add_argument('-s', '--size',
+ help='The file size to filter on in bytes',
+ type=int,
+ dest='size',
+ default=None)
+
+ args = parser.parse_args()
+ search_folder(args.path, args.extension, args.size)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/chapter46_mac/image_viewer.py b/chapter46_mac/image_viewer.py
new file mode 100644
index 0000000..8e4dec4
--- /dev/null
+++ b/chapter46_mac/image_viewer.py
@@ -0,0 +1,78 @@
+# image_viewer_working.py
+
+import wx
+
+class ImagePanel(wx.Panel):
+
+ def __init__(self, parent, image_size):
+ super().__init__(parent)
+ self.max_size = 240
+
+ img = wx.Image(*image_size)
+ self.image_ctrl = wx.StaticBitmap(self,
+ bitmap=wx.Bitmap(img))
+
+ browse_btn = wx.Button(self, label='Browse')
+ browse_btn.Bind(wx.EVT_BUTTON, self.on_browse)
+
+ self.photo_txt = wx.TextCtrl(self, size=(200, -1))
+
+ main_sizer = wx.BoxSizer(wx.VERTICAL)
+ hsizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
+ hsizer.Add(browse_btn, 0, wx.ALL, 5)
+ hsizer.Add(self.photo_txt, 0, wx.ALL, 5)
+ main_sizer.Add(hsizer, 0, wx.ALL, 5)
+
+ self.SetSizer(main_sizer)
+ main_sizer.Fit(parent)
+ self.Layout()
+
+ def on_browse(self, event):
+ """
+ Browse for an image file
+ @param event: The event object
+ """
+ wildcard = "JPEG files (*.jpg)|*.jpg"
+ with wx.FileDialog(None, "Choose a file",
+ wildcard=wildcard,
+ style=wx.ID_OPEN) as dialog:
+ if dialog.ShowModal() == wx.ID_OK:
+ self.photo_txt.SetValue(dialog.GetPath())
+ self.load_image()
+
+ def load_image(self):
+ """
+ Load the image and display it to the user
+ """
+ filepath = self.photo_txt.GetValue()
+ img = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
+
+ # scale the image, preserving the aspect ratio
+ W = img.GetWidth()
+ H = img.GetHeight()
+ if W > H:
+ NewW = self.max_size
+ NewH = self.max_size * H / W
+ else:
+ NewH = self.max_size
+ NewW = self.max_size * W / H
+ img = img.Scale(NewW,NewH)
+
+ self.image_ctrl.SetBitmap(wx.Bitmap(img))
+ self.Refresh()
+
+
+class MainFrame(wx.Frame):
+
+ def __init__(self):
+ super().__init__(None, title='Image Viewer')
+ panel = ImagePanel(self, image_size=(240,240))
+ self.Show()
+
+
+if __name__ == '__main__':
+ app = wx.App(redirect=False)
+ frame = MainFrame()
+ app.MainLoop()
\ No newline at end of file