├── .gitignore
├── README.md
├── appendix_b_git
└── arithmetic.py
├── chapter04_strings
└── Chapter 4 - Working with Strings.ipynb
├── chapter05_numeric_types
└── Chapter 5 - Numeric Types.ipynb
├── chapter06_lists
└── Chapter 6 - Learning About Lists.ipynb
├── chapter07_tuples
└── Chapter 7 - Learning About Tuples.ipynb
├── chapter08_dictionaries
└── Chapter 8 - Learning About Dictionaries.ipynb
├── chapter09_sets
└── Chapter 9 - Learning About Sets.ipynb
├── chapter10_bool
└── Chapter 10 - Boolean Operations and None.ipynb
├── chapter11_conditionals
└── Chapter 11 - Conditional Statements.ipynb
├── chapter12_loops
├── Chapter 12 - Learning About Loops.ipynb
├── for_loop_else.py
├── for_loop_else_2.py
├── for_loop_with_break.py
├── nested_loops.py
└── while_with_break.py
├── chapter13_comprehensions
└── Chapter 13 - Python Comprehensions.ipynb
├── chapter14_files
├── example.txt
├── read_file.py
└── read_file_with.py
├── chapter18_classes
├── __pycache__
│ └── ball.cpython-38.pyc
├── ball.py
├── ball_printable.py
├── ball_printable_str.py
├── bowling_ball.py
├── simple_ball.py
└── simple_ball_type_hints.py
├── chapter22_type_hints
├── bad_type_hinting.py
├── bad_type_hinting2.py
└── good_type_hinting.py
├── chapter23_threading
├── worker_thread_subclass.py
├── worker_threads.py
└── writing_thread.py
├── chapter24_multiprocessing
├── process_pool.py
├── worker_process_subclass.py
└── worker_processes.py
├── chapter26_debugging
├── debug_code.py
├── debug_code_with_breakpoint.py
└── debug_code_with_settrace.py
├── chapter27_decorators
├── amount_with_properties.py
├── amount_with_property_decorator.py
├── amount_without_properties.py
├── classmethod_example.py
├── decorator_class.py
├── decorator_syntax.py
├── decorator_syntax_with_arguments.py
├── first_decorator.py
├── first_decorator_updated.py
├── logging_decorator.py
├── stacked_decorator_tracing.py
├── stacked_decorators.py
└── treble.log
├── chapter29_profiling
├── callee_stats.py
├── filtered_stats.py
├── formatted_output.py
├── profile_output.txt
└── profile_test.py
├── chapter30_testing
├── add_doctest.py
├── add_doctest_working.py
├── add_test_in_code.py
├── doctest_external.py
├── fizzbuzz_buzz_test
│ ├── fizzbuzz.py
│ └── test_fizzbuzz.py
├── fizzbuzz_buzz_test_passing
│ ├── fizzbuzz.py
│ └── test_fizzbuzz.py
├── fizzbuzz_final_test
│ ├── fizzbuzz.py
│ └── test_fizzbuzz.py
├── fizzbuzz_final_test_passing
│ ├── fizzbuzz.py
│ └── test_fizzbuzz.py
├── fizzbuzz_fizz_test
│ ├── fizzbuzz.py
│ └── test_fizzbuzz.py
├── fizzbuzz_fizz_test_passing
│ ├── fizzbuzz.py
│ └── test_fizzbuzz.py
├── fizzbuzz_fizzbuzz_test
│ ├── fizzbuzz.py
│ └── test_fizzbuzz.py
├── fizzbuzz_fizzbuzz_test_passing
│ ├── fizzbuzz.py
│ └── test_fizzbuzz.py
└── test.txt
├── chapter31_jupyter
└── Hello World.ipynb
├── chapter32_argparse
├── file_parser.py
├── file_parser_aliases.py
├── file_parser_aliases2.py
├── file_parser_exclusive.py
├── file_parser_no_help.py
├── file_parser_with_description.py
├── pysearch.py
└── sys_args.py
├── chapter33_xml
├── appts.xml
├── create_xml.py
├── edit_xml.py
├── lxml_output.xml
├── note.xml
├── output.xml
├── parse_xml.py
├── parse_xml_with_lxml.py
├── test_create.xml
└── xml_tree_iterator.py
├── chapter34_json
├── create_json_file.py
├── example.json
└── load_json_file.py
├── chapter35_scrape_website
├── downloading_files.py
└── scraper.py
├── chapter36_csv
├── books.csv
├── csv_dict_reader.py
├── csv_dict_writer.py
├── csv_reader.py
├── csv_reader_no_header.py
├── csv_writer.py
├── csv_writer_rows.py
├── output.csv
└── output_dict.csv
├── chapter37_sqlite
├── add_data.py
├── create_database.py
├── delete_record.py
├── queries.py
└── update_record.py
├── chapter38_excel
├── books.xlsx
├── creating_sheets.py
├── delete_demo.py
├── delete_sheets.py
├── insert_demo.py
├── iterating_over_cell_values.py
├── iterating_over_cells.py
├── open_workbook.py
├── remove_sheets.py
├── workbook_cells.py
└── writing_hello.py
├── chapter39_reportlab
├── canvas_form.py
├── drawing_polygons.py
├── hello_platypus.py
├── hello_reportlab.py
├── image_on_canvas.py
├── platypus_multipage.py
├── simple_table.py
├── simple_table_with_style.py
└── snakehead.jpg
├── chapter40_graphs
├── bar_chart.py
├── bar_chart.title.py
├── bar_chart_labels.py
├── bar_chart_legend.py
├── bar_charth.py
├── line_plot.py
├── multiple_figures.py
├── multiple_plots.py
├── multiple_plots2.py
├── pie_chart_fancy.py
└── pie_chart_plain.py
├── chapter41_images
├── blur.py
├── border.py
├── border2.py
├── butterfly.jpg
├── butterfly_grey.jpg
├── colored_border.py
├── cropping.py
├── ducks.jpg
├── get_histogram.py
├── get_image_info.py
├── jellyfish.jpg
├── lizard.jpg
├── open_image.py
├── resize_image.py
├── scale_image.py
└── sharpen.py
├── chapter42_gui
├── button_events.py
├── hello_with_panel.py
├── hello_wx.py
├── hello_wx_class.py
├── image_viewer.py
├── image_viewer_working.py
├── sizer_with_two_widgets.py
└── stacked_buttons.py
├── chapter43_packages
├── arithmetic
│ ├── __init__.py
│ ├── add.py
│ ├── divide.py
│ ├── multiply.py
│ └── subtract.py
├── module
│ ├── arithmetic.py
│ └── test_arithmetic.py
└── my_package
│ ├── LICENSE
│ ├── README.md
│ ├── arithmetic
│ ├── __init__.py
│ ├── add.py
│ ├── divide.py
│ ├── multiply.py
│ └── subtract.py
│ └── setup.py
├── chapter44_pyinstaller
├── image_viewer.py
└── pysearch.py
├── chapter46_mac
└── image_viewer.py
└── contributors.txt
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | py101code\.wpr
3 |
4 | py101code\.wpu
5 |
6 | py101_2nd_code.wpr
7 |
8 | py101_2nd_code.wpu
9 |
10 | .DS_Store
11 |
12 | .ipynb_checkpoints
13 | chapter22_type_hints/.mypy_cache/
14 |
15 | *.pyc
16 | *.zip
17 | *.db
18 | *.pdf
19 | *.mypy_cache
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Python 101, 2nd Edition Book Code
2 |
3 |
4 |
5 | Code examples from the book, [Python 101](https://leanpub.com/py101) 2nd Edition by Michael Driscoll.
6 |
7 | 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**.
8 |
9 | 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.
10 |
11 | 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.
12 |
13 | 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)
14 |
15 |
--------------------------------------------------------------------------------
/appendix_b_git/arithmetic.py:
--------------------------------------------------------------------------------
1 | # arithmetic.py
2 |
3 | def add(x, y):
4 | return x + y
5 |
6 | def divide(x, y):
7 | return x / y
8 |
9 | def multiply(x, y):
10 | return x * y
11 |
12 | def subtract(x, y):
13 | return x - y
14 |
--------------------------------------------------------------------------------
/chapter05_numeric_types/Chapter 5 - Numeric Types.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Chapter 5 - Numeric Types"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "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",
15 | "\n",
16 | "The built-in numeric types are:\n",
17 | "\n",
18 | "* `int`\n",
19 | "* `float`\n",
20 | "* `complex`"
21 | ]
22 | },
23 | {
24 | "cell_type": "markdown",
25 | "metadata": {},
26 | "source": [
27 | "## Integers\n",
28 | "\n",
29 | "You can create an integer in two ways in Python. The most common way is to assign an integer to a variable:"
30 | ]
31 | },
32 | {
33 | "cell_type": "code",
34 | "execution_count": 1,
35 | "metadata": {},
36 | "outputs": [],
37 | "source": [
38 | "my_integer = 3"
39 | ]
40 | },
41 | {
42 | "cell_type": "markdown",
43 | "metadata": {},
44 | "source": [
45 | "The other way to create an integer is to use the `int` function, like this:"
46 | ]
47 | },
48 | {
49 | "cell_type": "code",
50 | "execution_count": 2,
51 | "metadata": {},
52 | "outputs": [],
53 | "source": [
54 | "my_integer = int(3)"
55 | ]
56 | },
57 | {
58 | "cell_type": "markdown",
59 | "metadata": {},
60 | "source": [
61 | "## Floats\n",
62 | "\n",
63 | "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`."
64 | ]
65 | },
66 | {
67 | "cell_type": "markdown",
68 | "metadata": {},
69 | "source": [
70 | "You can create a `float` in Python like this:"
71 | ]
72 | },
73 | {
74 | "cell_type": "code",
75 | "execution_count": 4,
76 | "metadata": {},
77 | "outputs": [],
78 | "source": [
79 | "my_float = 2.0"
80 | ]
81 | },
82 | {
83 | "cell_type": "markdown",
84 | "metadata": {},
85 | "source": [
86 | "You can also create a float like this:"
87 | ]
88 | },
89 | {
90 | "cell_type": "code",
91 | "execution_count": 5,
92 | "metadata": {},
93 | "outputs": [],
94 | "source": [
95 | "my_float = float(2.0)"
96 | ]
97 | },
98 | {
99 | "cell_type": "markdown",
100 | "metadata": {},
101 | "source": [
102 | "## Complex Numbers\n",
103 | "\n",
104 | "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."
105 | ]
106 | },
107 | {
108 | "cell_type": "markdown",
109 | "metadata": {},
110 | "source": [
111 | "Let's look at a quick example using Python's interpreter:"
112 | ]
113 | },
114 | {
115 | "cell_type": "markdown",
116 | "metadata": {},
117 | "source": [
118 | "```python\n",
119 | ">>> comp = 1 + 2j\n",
120 | ">>> type(comp)\n",
121 | "\n",
122 | ">>> comp.real\n",
123 | "1.0\n",
124 | ">>> comp.imag\n",
125 | "2.0\n",
126 | "```"
127 | ]
128 | },
129 | {
130 | "cell_type": "markdown",
131 | "metadata": {},
132 | "source": [
133 | "You can also use the `complex()` built-in function to create a complex number:"
134 | ]
135 | },
136 | {
137 | "cell_type": "code",
138 | "execution_count": 6,
139 | "metadata": {},
140 | "outputs": [
141 | {
142 | "data": {
143 | "text/plain": [
144 | "(10+12j)"
145 | ]
146 | },
147 | "execution_count": 6,
148 | "metadata": {},
149 | "output_type": "execute_result"
150 | }
151 | ],
152 | "source": [
153 | "complex(10, 12)"
154 | ]
155 | },
156 | {
157 | "cell_type": "markdown",
158 | "metadata": {},
159 | "source": [
160 | "## Numeric Operations\n",
161 | "\n",
162 | "All the numeric types, with the exception of `complex`, support a set of numeric operations.\n",
163 | "\n",
164 | "Here is a listing of the operations that you can do:\n",
165 | "\n",
166 | "|Operation |Result |\n",
167 | "|-----------------|--------------------------------------------|\n",
168 | "|a + b |The sum of a and b |\n",
169 | "|a - b |The difference of a and b |\n",
170 | "|a * b |The product of a and b |\n",
171 | "|a / b |The quotient of a and b |\n",
172 | "|a // b |The floored quotient of a and b |\n",
173 | "|a % b |The remainder of `a / b` |\n",
174 | "|-a |`a` negated (convert to negative) |\n",
175 | "|abs(a) |absolute value of `a` |\n",
176 | "|int(a) |`a` converted to integer |\n",
177 | "|float(x) |`a` converted to a floating-point number |\n",
178 | "|complex(re, im) |A complex number with real and imaginary |\n",
179 | "|c.conjugate() |The conjugate of the complex number `c` |\n",
180 | "|divmod(a, b) |The pair: (a // b, a % b) |\n",
181 | "|pow(x, b) |`a` to the power of `b` |\n",
182 | "|a ** b |`a` to the power of `b` |"
183 | ]
184 | },
185 | {
186 | "cell_type": "markdown",
187 | "metadata": {},
188 | "source": [
189 | "See also [https://docs.python.org/3/library/stdtypes.html](https://docs.python.org/3/library/stdtypes.html)"
190 | ]
191 | },
192 | {
193 | "cell_type": "markdown",
194 | "metadata": {},
195 | "source": [
196 | "## Augmented Assignment\n",
197 | "\n",
198 | "Python supports doing some types of arithmetic using a concept called **Augmented Assignment**. This idea was first proposed in PEP 203:\n",
199 | "\n",
200 | "* "
201 | ]
202 | },
203 | {
204 | "cell_type": "markdown",
205 | "metadata": {},
206 | "source": [
207 | "The syntax allows you to do various arithmetic operations using the following operators:\n",
208 | "\n",
209 | "`+= -= *= /= %= **= <<= >>= &= ^= |=`\n",
210 | "\n",
211 | "This syntax is a shortcut for doing common arithmetic in Python. With it you can replace the following code:\n",
212 | "\n",
213 | "```python\n",
214 | ">>> x = 1\n",
215 | ">>> x = x + 2\n",
216 | ">>> x\n",
217 | "3\n",
218 | "```\n",
219 | "\n",
220 | "with this:\n",
221 | "\n",
222 | "```python\n",
223 | ">>> x = 1\n",
224 | ">>> x += 2\n",
225 | ">>> x\n",
226 | "3\n",
227 | "```"
228 | ]
229 | },
230 | {
231 | "cell_type": "code",
232 | "execution_count": null,
233 | "metadata": {},
234 | "outputs": [],
235 | "source": []
236 | }
237 | ],
238 | "metadata": {
239 | "kernelspec": {
240 | "display_name": "Python 3",
241 | "language": "python",
242 | "name": "python3"
243 | },
244 | "language_info": {
245 | "codemirror_mode": {
246 | "name": "ipython",
247 | "version": 3
248 | },
249 | "file_extension": ".py",
250 | "mimetype": "text/x-python",
251 | "name": "python",
252 | "nbconvert_exporter": "python",
253 | "pygments_lexer": "ipython3",
254 | "version": "3.6.4"
255 | }
256 | },
257 | "nbformat": 4,
258 | "nbformat_minor": 2
259 | }
260 |
--------------------------------------------------------------------------------
/chapter06_lists/Chapter 6 - Learning About Lists.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Chapter 6 - Learning About Lists"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "## Creating Lists\n",
15 | "\n",
16 | "There are several ways to create a `list`. You may construct a list in any of the following ways:\n",
17 | "\n",
18 | "* Using a pair of square brackets with nothing inside creates an empty list: `[]`\n",
19 | "* Using square brackets with comma-separated items: `[1, 2, 3]`\n",
20 | "* Using a list comprehension (see Chapter 13 for more information): [x for x in iterable]\n",
21 | "* Using the `list()` function: `list(iterable)`"
22 | ]
23 | },
24 | {
25 | "cell_type": "code",
26 | "execution_count": 1,
27 | "metadata": {},
28 | "outputs": [
29 | {
30 | "name": "stdout",
31 | "output_type": "stream",
32 | "text": [
33 | "[1, 2, 3]\n"
34 | ]
35 | }
36 | ],
37 | "source": [
38 | "my_list = [1, 2, 3]\n",
39 | "print(my_list)"
40 | ]
41 | },
42 | {
43 | "cell_type": "markdown",
44 | "metadata": {},
45 | "source": [
46 | "Or use the `list()` function to create a list:"
47 | ]
48 | },
49 | {
50 | "cell_type": "code",
51 | "execution_count": null,
52 | "metadata": {},
53 | "outputs": [],
54 | "source": [
55 | "list_of_strings = list('abc')\n",
56 | "print(list_of_strings)"
57 | ]
58 | },
59 | {
60 | "cell_type": "markdown",
61 | "metadata": {},
62 | "source": [
63 | "The last example to look at is how to create empty lists:"
64 | ]
65 | },
66 | {
67 | "cell_type": "code",
68 | "execution_count": null,
69 | "metadata": {},
70 | "outputs": [],
71 | "source": [
72 | "empty_list = []\n",
73 | "another_empty_list = list()"
74 | ]
75 | },
76 | {
77 | "cell_type": "markdown",
78 | "metadata": {},
79 | "source": [
80 | "## List Methods\n",
81 | "\n",
82 | "A Python `list` has several methods that you can call. Here is a listing of the methods you can use with a `list`:\n",
83 | "\n",
84 | "* `append()`\n",
85 | "* `clear()`\n",
86 | "* `copy()`\n",
87 | "* `count()`\n",
88 | "* `extend()`\n",
89 | "* `index()`\n",
90 | "* `insert()`\n",
91 | "* `pop()`\n",
92 | "* `remove()`\n",
93 | "* `reverse()`\n",
94 | "* `sort()`"
95 | ]
96 | },
97 | {
98 | "cell_type": "code",
99 | "execution_count": 2,
100 | "metadata": {},
101 | "outputs": [],
102 | "source": [
103 | "my_list = list('abcc')"
104 | ]
105 | },
106 | {
107 | "cell_type": "code",
108 | "execution_count": 6,
109 | "metadata": {},
110 | "outputs": [
111 | {
112 | "data": {
113 | "text/plain": [
114 | "2"
115 | ]
116 | },
117 | "execution_count": 6,
118 | "metadata": {},
119 | "output_type": "execute_result"
120 | }
121 | ],
122 | "source": [
123 | "my_list.count('c')"
124 | ]
125 | },
126 | {
127 | "cell_type": "code",
128 | "execution_count": 3,
129 | "metadata": {},
130 | "outputs": [
131 | {
132 | "data": {
133 | "text/plain": [
134 | "2"
135 | ]
136 | },
137 | "execution_count": 3,
138 | "metadata": {},
139 | "output_type": "execute_result"
140 | }
141 | ],
142 | "source": [
143 | "my_list.index('c')"
144 | ]
145 | },
146 | {
147 | "cell_type": "code",
148 | "execution_count": 4,
149 | "metadata": {},
150 | "outputs": [
151 | {
152 | "data": {
153 | "text/plain": [
154 | "0"
155 | ]
156 | },
157 | "execution_count": 4,
158 | "metadata": {},
159 | "output_type": "execute_result"
160 | }
161 | ],
162 | "source": [
163 | "my_list.index('a')"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": 5,
169 | "metadata": {},
170 | "outputs": [
171 | {
172 | "name": "stdout",
173 | "output_type": "stream",
174 | "text": [
175 | "['c', 'c', 'b', 'a']\n"
176 | ]
177 | }
178 | ],
179 | "source": [
180 | "my_list = list('abcc')\n",
181 | "my_list.reverse()\n",
182 | "print(my_list)"
183 | ]
184 | },
185 | {
186 | "cell_type": "markdown",
187 | "metadata": {},
188 | "source": [
189 | "### Adding to a List\n",
190 | "\n",
191 | "There are three `list` methods that you can use to add to a list. They are as follows:\n",
192 | "\n",
193 | "* `append()`\n",
194 | "* `extend()`\n",
195 | "* `insert()`"
196 | ]
197 | },
198 | {
199 | "cell_type": "code",
200 | "execution_count": 7,
201 | "metadata": {},
202 | "outputs": [
203 | {
204 | "name": "stdout",
205 | "output_type": "stream",
206 | "text": [
207 | "['a', 'b', 'c', 'c']\n"
208 | ]
209 | }
210 | ],
211 | "source": [
212 | "my_list = list('abcc')\n",
213 | "print(my_list)"
214 | ]
215 | },
216 | {
217 | "cell_type": "code",
218 | "execution_count": 8,
219 | "metadata": {},
220 | "outputs": [
221 | {
222 | "name": "stdout",
223 | "output_type": "stream",
224 | "text": [
225 | "['a', 'b', 'c', 'c', 1]\n"
226 | ]
227 | }
228 | ],
229 | "source": [
230 | "my_list.append(1)\n",
231 | "print(my_list)"
232 | ]
233 | },
234 | {
235 | "cell_type": "code",
236 | "execution_count": 9,
237 | "metadata": {},
238 | "outputs": [
239 | {
240 | "data": {
241 | "text/plain": [
242 | "5"
243 | ]
244 | },
245 | "execution_count": 9,
246 | "metadata": {},
247 | "output_type": "execute_result"
248 | }
249 | ],
250 | "source": [
251 | "len(my_list)"
252 | ]
253 | },
254 | {
255 | "cell_type": "code",
256 | "execution_count": 10,
257 | "metadata": {},
258 | "outputs": [
259 | {
260 | "name": "stdout",
261 | "output_type": "stream",
262 | "text": [
263 | "['first', 'a', 'b', 'c', 'c', 1]\n"
264 | ]
265 | }
266 | ],
267 | "source": [
268 | "my_list.insert(0, 'first')\n",
269 | "print(my_list)"
270 | ]
271 | },
272 | {
273 | "cell_type": "markdown",
274 | "metadata": {},
275 | "source": [
276 | "There are two other ways to add items to a `list`. You can add an iterable to a `list` using `extend()`:"
277 | ]
278 | },
279 | {
280 | "cell_type": "code",
281 | "execution_count": 11,
282 | "metadata": {},
283 | "outputs": [
284 | {
285 | "name": "stdout",
286 | "output_type": "stream",
287 | "text": [
288 | "[1, 2, 3, 4, 5, 6]\n"
289 | ]
290 | }
291 | ],
292 | "source": [
293 | "my_list = [1, 2, 3]\n",
294 | "other_list = [4, 5, 6]\n",
295 | "my_list.extend(other_list)\n",
296 | "print(my_list)"
297 | ]
298 | },
299 | {
300 | "cell_type": "markdown",
301 | "metadata": {},
302 | "source": [
303 | "You can also combine lists using concatenation:"
304 | ]
305 | },
306 | {
307 | "cell_type": "code",
308 | "execution_count": 12,
309 | "metadata": {},
310 | "outputs": [
311 | {
312 | "name": "stdout",
313 | "output_type": "stream",
314 | "text": [
315 | "[1, 2, 3, 4, 5, 6]\n"
316 | ]
317 | }
318 | ],
319 | "source": [
320 | "my_list = [1, 2, 3]\n",
321 | "other_list = [4, 5, 6]\n",
322 | "my_list += other_list\n",
323 | "print(my_list)"
324 | ]
325 | },
326 | {
327 | "cell_type": "markdown",
328 | "metadata": {},
329 | "source": [
330 | "### Accessing and Changing List Elements"
331 | ]
332 | },
333 | {
334 | "cell_type": "markdown",
335 | "metadata": {},
336 | "source": [
337 | "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."
338 | ]
339 | },
340 | {
341 | "cell_type": "code",
342 | "execution_count": 13,
343 | "metadata": {},
344 | "outputs": [
345 | {
346 | "data": {
347 | "text/plain": [
348 | "1"
349 | ]
350 | },
351 | "execution_count": 13,
352 | "metadata": {},
353 | "output_type": "execute_result"
354 | }
355 | ],
356 | "source": [
357 | "my_list = [1, 2, 3]\n",
358 | "my_list[0]"
359 | ]
360 | },
361 | {
362 | "cell_type": "markdown",
363 | "metadata": {},
364 | "source": [
365 | "Lists also support accessing items in reverse by using negative values:"
366 | ]
367 | },
368 | {
369 | "cell_type": "code",
370 | "execution_count": 14,
371 | "metadata": {},
372 | "outputs": [
373 | {
374 | "data": {
375 | "text/plain": [
376 | "3"
377 | ]
378 | },
379 | "execution_count": 14,
380 | "metadata": {},
381 | "output_type": "execute_result"
382 | }
383 | ],
384 | "source": [
385 | "my_list[-1]"
386 | ]
387 | },
388 | {
389 | "cell_type": "markdown",
390 | "metadata": {},
391 | "source": [
392 | "If you try to use an index that does not exist in the `list`, you will get an `IndexError`:\n",
393 | "\n",
394 | "```python\n",
395 | ">>> my_list[-5]\n",
396 | "Traceback (most recent call last):\n",
397 | " Python Shell, prompt 41, line 1\n",
398 | "builtins.IndexError: list index out of range\n",
399 | "```"
400 | ]
401 | },
402 | {
403 | "cell_type": "markdown",
404 | "metadata": {},
405 | "source": [
406 | "### Deleting From a List"
407 | ]
408 | },
409 | {
410 | "cell_type": "markdown",
411 | "metadata": {},
412 | "source": [
413 | "Deleting items from a `list` is pretty straight-forward. There are 4 primary methods of removing items from a list:\n",
414 | "\n",
415 | "* `clear()`\n",
416 | "* `pop()`\n",
417 | "* `remove()`\n",
418 | "* `del`"
419 | ]
420 | },
421 | {
422 | "cell_type": "code",
423 | "execution_count": 15,
424 | "metadata": {},
425 | "outputs": [
426 | {
427 | "name": "stdout",
428 | "output_type": "stream",
429 | "text": [
430 | "[]\n"
431 | ]
432 | }
433 | ],
434 | "source": [
435 | "my_list = [1, 2, 3]\n",
436 | "my_list.clear()\n",
437 | "print(my_list)"
438 | ]
439 | },
440 | {
441 | "cell_type": "markdown",
442 | "metadata": {},
443 | "source": [
444 | "If you would rather remove individual items, then you should check out `pop()` or `remove()`. Let's start with `pop()`:"
445 | ]
446 | },
447 | {
448 | "cell_type": "code",
449 | "execution_count": 16,
450 | "metadata": {},
451 | "outputs": [
452 | {
453 | "data": {
454 | "text/plain": [
455 | "3"
456 | ]
457 | },
458 | "execution_count": 16,
459 | "metadata": {},
460 | "output_type": "execute_result"
461 | }
462 | ],
463 | "source": [
464 | "my_list = [1, 2, 3]\n",
465 | "my_list.pop()"
466 | ]
467 | },
468 | {
469 | "cell_type": "code",
470 | "execution_count": 17,
471 | "metadata": {},
472 | "outputs": [
473 | {
474 | "name": "stdout",
475 | "output_type": "stream",
476 | "text": [
477 | "[1, 2]\n"
478 | ]
479 | }
480 | ],
481 | "source": [
482 | "print(my_list)"
483 | ]
484 | },
485 | {
486 | "cell_type": "markdown",
487 | "metadata": {},
488 | "source": [
489 | "`remove()` will delete the first instance of the passed in item"
490 | ]
491 | },
492 | {
493 | "cell_type": "code",
494 | "execution_count": 18,
495 | "metadata": {},
496 | "outputs": [
497 | {
498 | "name": "stdout",
499 | "output_type": "stream",
500 | "text": [
501 | "[1, 3]\n"
502 | ]
503 | }
504 | ],
505 | "source": [
506 | "my_list = [1, 2, 3]\n",
507 | "my_list.remove(2)\n",
508 | "print(my_list)"
509 | ]
510 | },
511 | {
512 | "cell_type": "markdown",
513 | "metadata": {},
514 | "source": [
515 | "### Sorting a List"
516 | ]
517 | },
518 | {
519 | "cell_type": "markdown",
520 | "metadata": {},
521 | "source": [
522 | "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."
523 | ]
524 | },
525 | {
526 | "cell_type": "code",
527 | "execution_count": 19,
528 | "metadata": {},
529 | "outputs": [
530 | {
531 | "name": "stdout",
532 | "output_type": "stream",
533 | "text": [
534 | "[1, 2, 4, 9, 10, 23]\n"
535 | ]
536 | }
537 | ],
538 | "source": [
539 | "my_list = [4, 10, 2, 1, 23, 9]\n",
540 | "my_list.sort()\n",
541 | "print(my_list)"
542 | ]
543 | },
544 | {
545 | "cell_type": "markdown",
546 | "metadata": {},
547 | "source": [
548 | "A common misconception with Python is that if you call `sort()`, you can assign the result to a variable, like this:"
549 | ]
550 | },
551 | {
552 | "cell_type": "code",
553 | "execution_count": 20,
554 | "metadata": {},
555 | "outputs": [
556 | {
557 | "name": "stdout",
558 | "output_type": "stream",
559 | "text": [
560 | "None\n"
561 | ]
562 | }
563 | ],
564 | "source": [
565 | "sorted_list = my_list.sort()\n",
566 | "print(sorted_list)"
567 | ]
568 | },
569 | {
570 | "cell_type": "markdown",
571 | "metadata": {},
572 | "source": [
573 | "However, when you do that, you will see that `sort()` doesn't actually return a sorted list. It always returns `None`.\n",
574 | "\n",
575 | "Fortunately you can use Python's built-in `sorted()` method for this too:"
576 | ]
577 | },
578 | {
579 | "cell_type": "code",
580 | "execution_count": 21,
581 | "metadata": {},
582 | "outputs": [
583 | {
584 | "name": "stdout",
585 | "output_type": "stream",
586 | "text": [
587 | "[1, 2, 4, 9, 10, 23]\n"
588 | ]
589 | }
590 | ],
591 | "source": [
592 | "my_list = [4, 10, 2, 1, 23, 9]\n",
593 | "sorted_list = sorted(my_list)\n",
594 | "print(sorted_list)"
595 | ]
596 | },
597 | {
598 | "cell_type": "markdown",
599 | "metadata": {},
600 | "source": [
601 | "You can also sort in reverse using `sorted()`"
602 | ]
603 | },
604 | {
605 | "cell_type": "code",
606 | "execution_count": 22,
607 | "metadata": {},
608 | "outputs": [
609 | {
610 | "name": "stdout",
611 | "output_type": "stream",
612 | "text": [
613 | "[23, 10, 9, 4, 2, 1]\n"
614 | ]
615 | }
616 | ],
617 | "source": [
618 | "my_list = [4, 10, 2, 1, 23, 9]\n",
619 | "sorted_list = sorted(my_list, reverse=True)\n",
620 | "print(sorted_list)"
621 | ]
622 | },
623 | {
624 | "cell_type": "markdown",
625 | "metadata": {},
626 | "source": [
627 | "## List Slicing"
628 | ]
629 | },
630 | {
631 | "cell_type": "markdown",
632 | "metadata": {},
633 | "source": [
634 | "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."
635 | ]
636 | },
637 | {
638 | "cell_type": "code",
639 | "execution_count": 24,
640 | "metadata": {},
641 | "outputs": [
642 | {
643 | "data": {
644 | "text/plain": [
645 | "[10, 2]"
646 | ]
647 | },
648 | "execution_count": 24,
649 | "metadata": {},
650 | "output_type": "execute_result"
651 | }
652 | ],
653 | "source": [
654 | "my_list = [4, 10, 2, 1, 23, 9]\n",
655 | "my_list[1:3]"
656 | ]
657 | },
658 | {
659 | "cell_type": "code",
660 | "execution_count": 25,
661 | "metadata": {},
662 | "outputs": [
663 | {
664 | "data": {
665 | "text/plain": [
666 | "[23, 9]"
667 | ]
668 | },
669 | "execution_count": 25,
670 | "metadata": {},
671 | "output_type": "execute_result"
672 | }
673 | ],
674 | "source": [
675 | "my_list[-2:]"
676 | ]
677 | },
678 | {
679 | "cell_type": "code",
680 | "execution_count": 26,
681 | "metadata": {},
682 | "outputs": [
683 | {
684 | "data": {
685 | "text/plain": [
686 | "[4, 10, 2]"
687 | ]
688 | },
689 | "execution_count": 26,
690 | "metadata": {},
691 | "output_type": "execute_result"
692 | }
693 | ],
694 | "source": [
695 | "my_list[:3]"
696 | ]
697 | },
698 | {
699 | "cell_type": "markdown",
700 | "metadata": {},
701 | "source": [
702 | "## Copying a List\n",
703 | "\n",
704 | "Occasionally you will want to copy a `list`. One simple way to copy your `list` is to use the `copy` method:"
705 | ]
706 | },
707 | {
708 | "cell_type": "code",
709 | "execution_count": 27,
710 | "metadata": {},
711 | "outputs": [
712 | {
713 | "name": "stdout",
714 | "output_type": "stream",
715 | "text": [
716 | "[1, 2, 3]\n"
717 | ]
718 | }
719 | ],
720 | "source": [
721 | "my_list = [1, 2, 3]\n",
722 | "new_list = my_list.copy()\n",
723 | "print(new_list)"
724 | ]
725 | },
726 | {
727 | "cell_type": "markdown",
728 | "metadata": {},
729 | "source": [
730 | "You can also copy a list by using this funny syntax:"
731 | ]
732 | },
733 | {
734 | "cell_type": "code",
735 | "execution_count": 29,
736 | "metadata": {},
737 | "outputs": [
738 | {
739 | "name": "stdout",
740 | "output_type": "stream",
741 | "text": [
742 | "[1, 2, 3]\n"
743 | ]
744 | }
745 | ],
746 | "source": [
747 | "my_list = [1, 2, 3]\n",
748 | "new_list = my_list[:]\n",
749 | "print(new_list)"
750 | ]
751 | },
752 | {
753 | "cell_type": "markdown",
754 | "metadata": {},
755 | "source": [
756 | "You could also use Python's `list()` function to copy a list:"
757 | ]
758 | },
759 | {
760 | "cell_type": "code",
761 | "execution_count": 30,
762 | "metadata": {},
763 | "outputs": [
764 | {
765 | "name": "stdout",
766 | "output_type": "stream",
767 | "text": [
768 | "[1, 2, 3]\n"
769 | ]
770 | }
771 | ],
772 | "source": [
773 | "my_list = [1, 2, 3]\n",
774 | "new_list = list(my_list)\n",
775 | "print(new_list)"
776 | ]
777 | },
778 | {
779 | "cell_type": "markdown",
780 | "metadata": {},
781 | "source": [
782 | "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."
783 | ]
784 | },
785 | {
786 | "cell_type": "code",
787 | "execution_count": null,
788 | "metadata": {},
789 | "outputs": [],
790 | "source": []
791 | }
792 | ],
793 | "metadata": {
794 | "kernelspec": {
795 | "display_name": "Python 3",
796 | "language": "python",
797 | "name": "python3"
798 | },
799 | "language_info": {
800 | "codemirror_mode": {
801 | "name": "ipython",
802 | "version": 3
803 | },
804 | "file_extension": ".py",
805 | "mimetype": "text/x-python",
806 | "name": "python",
807 | "nbconvert_exporter": "python",
808 | "pygments_lexer": "ipython3",
809 | "version": "3.6.4"
810 | }
811 | },
812 | "nbformat": 4,
813 | "nbformat_minor": 2
814 | }
815 |
--------------------------------------------------------------------------------
/chapter07_tuples/Chapter 7 - Learning About Tuples.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Chapter 7 - Learning About Tuples\n",
8 | "\n",
9 | "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**."
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | "## Creating Tuples\n",
17 | "\n",
18 | "You can create tuples in several different ways. Let's take a look:"
19 | ]
20 | },
21 | {
22 | "cell_type": "code",
23 | "execution_count": 1,
24 | "metadata": {},
25 | "outputs": [
26 | {
27 | "data": {
28 | "text/plain": [
29 | "tuple"
30 | ]
31 | },
32 | "execution_count": 1,
33 | "metadata": {},
34 | "output_type": "execute_result"
35 | }
36 | ],
37 | "source": [
38 | "a_tuple = (4, 5)\n",
39 | "type(a_tuple)"
40 | ]
41 | },
42 | {
43 | "cell_type": "markdown",
44 | "metadata": {},
45 | "source": [
46 | "You can also cast a `list` into a `tuple` using the `tuple()` function:"
47 | ]
48 | },
49 | {
50 | "cell_type": "code",
51 | "execution_count": 2,
52 | "metadata": {},
53 | "outputs": [
54 | {
55 | "data": {
56 | "text/plain": [
57 | "tuple"
58 | ]
59 | },
60 | "execution_count": 2,
61 | "metadata": {},
62 | "output_type": "execute_result"
63 | }
64 | ],
65 | "source": [
66 | "a_tuple = tuple(['1', '2', '3'])\n",
67 | "type(a_tuple)"
68 | ]
69 | },
70 | {
71 | "cell_type": "markdown",
72 | "metadata": {},
73 | "source": [
74 | "## Working With Tuples\n",
75 | "\n",
76 | "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",
77 | "\n",
78 | "* `count()`\n",
79 | "* `index()`\n",
80 | "\n",
81 | "You can use `count()` to find out how many elements match the value that you pass in:"
82 | ]
83 | },
84 | {
85 | "cell_type": "code",
86 | "execution_count": 3,
87 | "metadata": {},
88 | "outputs": [
89 | {
90 | "data": {
91 | "text/plain": [
92 | "2"
93 | ]
94 | },
95 | "execution_count": 3,
96 | "metadata": {},
97 | "output_type": "execute_result"
98 | }
99 | ],
100 | "source": [
101 | "a_tuple = (1, 2, 3, 3)\n",
102 | "a_tuple.count(3)"
103 | ]
104 | },
105 | {
106 | "cell_type": "markdown",
107 | "metadata": {},
108 | "source": [
109 | "You can use `index()` to find the first index of a value:"
110 | ]
111 | },
112 | {
113 | "cell_type": "code",
114 | "execution_count": 4,
115 | "metadata": {},
116 | "outputs": [
117 | {
118 | "data": {
119 | "text/plain": [
120 | "3"
121 | ]
122 | },
123 | "execution_count": 4,
124 | "metadata": {},
125 | "output_type": "execute_result"
126 | }
127 | ],
128 | "source": [
129 | "a_tuple = (1, 2, 3, 3)\n",
130 | "a_tuple[2]"
131 | ]
132 | },
133 | {
134 | "cell_type": "markdown",
135 | "metadata": {},
136 | "source": [
137 | "Let's try to modify an element in your `tuple`:"
138 | ]
139 | },
140 | {
141 | "cell_type": "code",
142 | "execution_count": 5,
143 | "metadata": {},
144 | "outputs": [
145 | {
146 | "ename": "TypeError",
147 | "evalue": "'tuple' object does not support item assignment",
148 | "output_type": "error",
149 | "traceback": [
150 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
151 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
152 | "\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",
153 | "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
154 | ]
155 | }
156 | ],
157 | "source": [
158 | "a_tuple[0] = 8"
159 | ]
160 | },
161 | {
162 | "cell_type": "markdown",
163 | "metadata": {},
164 | "source": [
165 | "## Concatenating Tuples\n",
166 | "\n",
167 | "Tuples can be concatenated together. However, when you do that, you will end up creating a new tuple:"
168 | ]
169 | },
170 | {
171 | "cell_type": "code",
172 | "execution_count": 6,
173 | "metadata": {},
174 | "outputs": [
175 | {
176 | "data": {
177 | "text/plain": [
178 | "4437658264"
179 | ]
180 | },
181 | "execution_count": 6,
182 | "metadata": {},
183 | "output_type": "execute_result"
184 | }
185 | ],
186 | "source": [
187 | "a_tuple = (1, 2, 3, 3)\n",
188 | "id(a_tuple)"
189 | ]
190 | },
191 | {
192 | "cell_type": "code",
193 | "execution_count": 9,
194 | "metadata": {},
195 | "outputs": [
196 | {
197 | "data": {
198 | "text/plain": [
199 | "4434750920"
200 | ]
201 | },
202 | "execution_count": 9,
203 | "metadata": {},
204 | "output_type": "execute_result"
205 | }
206 | ],
207 | "source": [
208 | "a_tuple = a_tuple + (6, 7)\n",
209 | "id(a_tuple)"
210 | ]
211 | },
212 | {
213 | "cell_type": "markdown",
214 | "metadata": {},
215 | "source": [
216 | "## Special Case Tuples\n",
217 | "\n",
218 | "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."
219 | ]
220 | },
221 | {
222 | "cell_type": "markdown",
223 | "metadata": {},
224 | "source": [
225 | "To create an empty tuple, you can do one of the following:"
226 | ]
227 | },
228 | {
229 | "cell_type": "code",
230 | "execution_count": 11,
231 | "metadata": {},
232 | "outputs": [
233 | {
234 | "data": {
235 | "text/plain": [
236 | "0"
237 | ]
238 | },
239 | "execution_count": 11,
240 | "metadata": {},
241 | "output_type": "execute_result"
242 | }
243 | ],
244 | "source": [
245 | "empty = tuple()\n",
246 | "len(empty)"
247 | ]
248 | },
249 | {
250 | "cell_type": "code",
251 | "execution_count": 12,
252 | "metadata": {},
253 | "outputs": [
254 | {
255 | "data": {
256 | "text/plain": [
257 | "0"
258 | ]
259 | },
260 | "execution_count": 12,
261 | "metadata": {},
262 | "output_type": "execute_result"
263 | }
264 | ],
265 | "source": [
266 | "also_empty = ()\n",
267 | "len(also_empty)"
268 | ]
269 | },
270 | {
271 | "cell_type": "markdown",
272 | "metadata": {},
273 | "source": [
274 | "Now let's create a `tuple` with a single element:"
275 | ]
276 | },
277 | {
278 | "cell_type": "code",
279 | "execution_count": 13,
280 | "metadata": {},
281 | "outputs": [
282 | {
283 | "data": {
284 | "text/plain": [
285 | "1"
286 | ]
287 | },
288 | "execution_count": 13,
289 | "metadata": {},
290 | "output_type": "execute_result"
291 | }
292 | ],
293 | "source": [
294 | "single = 2, # <-- Note the comma on the end\n",
295 | "len(single)"
296 | ]
297 | },
298 | {
299 | "cell_type": "code",
300 | "execution_count": null,
301 | "metadata": {},
302 | "outputs": [],
303 | "source": []
304 | }
305 | ],
306 | "metadata": {
307 | "kernelspec": {
308 | "display_name": "Python 3",
309 | "language": "python",
310 | "name": "python3"
311 | },
312 | "language_info": {
313 | "codemirror_mode": {
314 | "name": "ipython",
315 | "version": 3
316 | },
317 | "file_extension": ".py",
318 | "mimetype": "text/x-python",
319 | "name": "python",
320 | "nbconvert_exporter": "python",
321 | "pygments_lexer": "ipython3",
322 | "version": "3.6.4"
323 | }
324 | },
325 | "nbformat": 4,
326 | "nbformat_minor": 2
327 | }
328 |
--------------------------------------------------------------------------------
/chapter10_bool/Chapter 10 - Boolean Operations and None.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Chapter 10 - Boolean Operations and None"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "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",
15 | "\n",
16 | "In Python, `False` maps to 0 (zero) and `True` maps to 1 (one). \n",
17 | "\n",
18 | "You can easily see this is true using Python's interpreter:"
19 | ]
20 | },
21 | {
22 | "cell_type": "code",
23 | "execution_count": 1,
24 | "metadata": {},
25 | "outputs": [
26 | {
27 | "data": {
28 | "text/plain": [
29 | "True"
30 | ]
31 | },
32 | "execution_count": 1,
33 | "metadata": {},
34 | "output_type": "execute_result"
35 | }
36 | ],
37 | "source": [
38 | "True == 1"
39 | ]
40 | },
41 | {
42 | "cell_type": "code",
43 | "execution_count": 3,
44 | "metadata": {},
45 | "outputs": [
46 | {
47 | "data": {
48 | "text/plain": [
49 | "True"
50 | ]
51 | },
52 | "execution_count": 3,
53 | "metadata": {},
54 | "output_type": "execute_result"
55 | }
56 | ],
57 | "source": [
58 | "False == 0"
59 | ]
60 | },
61 | {
62 | "cell_type": "code",
63 | "execution_count": 4,
64 | "metadata": {},
65 | "outputs": [
66 | {
67 | "data": {
68 | "text/plain": [
69 | "False"
70 | ]
71 | },
72 | "execution_count": 4,
73 | "metadata": {},
74 | "output_type": "execute_result"
75 | }
76 | ],
77 | "source": [
78 | "False == True"
79 | ]
80 | },
81 | {
82 | "cell_type": "markdown",
83 | "metadata": {},
84 | "source": [
85 | "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",
86 | "\n",
87 | "Let's try to assign a value to `True` and see what happens:"
88 | ]
89 | },
90 | {
91 | "cell_type": "code",
92 | "execution_count": 5,
93 | "metadata": {},
94 | "outputs": [
95 | {
96 | "ename": "SyntaxError",
97 | "evalue": "can't assign to keyword (, line 1)",
98 | "output_type": "error",
99 | "traceback": [
100 | "\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"
101 | ]
102 | }
103 | ],
104 | "source": [
105 | "True = 1"
106 | ]
107 | },
108 | {
109 | "cell_type": "markdown",
110 | "metadata": {},
111 | "source": [
112 | "Python doesn't allow that!\n",
113 | "\n",
114 | "You can't assign anything to keywords in Python."
115 | ]
116 | },
117 | {
118 | "cell_type": "markdown",
119 | "metadata": {},
120 | "source": [
121 | "## The bool() Function\n",
122 | "\n",
123 | "Python also provides the `bool()` function, which allows you to cast other types to `True` or `False`.\n",
124 | "\n",
125 | "Let's give it a try:"
126 | ]
127 | },
128 | {
129 | "cell_type": "code",
130 | "execution_count": 6,
131 | "metadata": {},
132 | "outputs": [
133 | {
134 | "data": {
135 | "text/plain": [
136 | "True"
137 | ]
138 | },
139 | "execution_count": 6,
140 | "metadata": {},
141 | "output_type": "execute_result"
142 | }
143 | ],
144 | "source": [
145 | "bool('1')"
146 | ]
147 | },
148 | {
149 | "cell_type": "code",
150 | "execution_count": 8,
151 | "metadata": {},
152 | "outputs": [
153 | {
154 | "data": {
155 | "text/plain": [
156 | "True"
157 | ]
158 | },
159 | "execution_count": 8,
160 | "metadata": {},
161 | "output_type": "execute_result"
162 | }
163 | ],
164 | "source": [
165 | "bool('2')"
166 | ]
167 | },
168 | {
169 | "cell_type": "code",
170 | "execution_count": 7,
171 | "metadata": {},
172 | "outputs": [
173 | {
174 | "data": {
175 | "text/plain": [
176 | "True"
177 | ]
178 | },
179 | "execution_count": 7,
180 | "metadata": {},
181 | "output_type": "execute_result"
182 | }
183 | ],
184 | "source": [
185 | "bool('0')"
186 | ]
187 | },
188 | {
189 | "cell_type": "markdown",
190 | "metadata": {},
191 | "source": [
192 | "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",
193 | "\n",
194 | "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",
195 | "\n",
196 | "In this case, the string, `'0'`, has one character, so it maps to `True`. Let's try it with an empty string:"
197 | ]
198 | },
199 | {
200 | "cell_type": "code",
201 | "execution_count": 9,
202 | "metadata": {},
203 | "outputs": [
204 | {
205 | "data": {
206 | "text/plain": [
207 | "False"
208 | ]
209 | },
210 | "execution_count": 9,
211 | "metadata": {},
212 | "output_type": "execute_result"
213 | }
214 | ],
215 | "source": [
216 | "bool('')"
217 | ]
218 | },
219 | {
220 | "cell_type": "markdown",
221 | "metadata": {},
222 | "source": [
223 | "Since the string is empty (i.e. it has no characters in it), it will cast to `False`. \n",
224 | "\n",
225 | "Let's see what happens when we try casting some of Python's other types:"
226 | ]
227 | },
228 | {
229 | "cell_type": "code",
230 | "execution_count": 10,
231 | "metadata": {},
232 | "outputs": [
233 | {
234 | "data": {
235 | "text/plain": [
236 | "False"
237 | ]
238 | },
239 | "execution_count": 10,
240 | "metadata": {},
241 | "output_type": "execute_result"
242 | }
243 | ],
244 | "source": [
245 | "bool([])"
246 | ]
247 | },
248 | {
249 | "cell_type": "code",
250 | "execution_count": 11,
251 | "metadata": {},
252 | "outputs": [
253 | {
254 | "data": {
255 | "text/plain": [
256 | "True"
257 | ]
258 | },
259 | "execution_count": 11,
260 | "metadata": {},
261 | "output_type": "execute_result"
262 | }
263 | ],
264 | "source": [
265 | "bool(['something'])"
266 | ]
267 | },
268 | {
269 | "cell_type": "code",
270 | "execution_count": 12,
271 | "metadata": {},
272 | "outputs": [
273 | {
274 | "data": {
275 | "text/plain": [
276 | "False"
277 | ]
278 | },
279 | "execution_count": 12,
280 | "metadata": {},
281 | "output_type": "execute_result"
282 | }
283 | ],
284 | "source": [
285 | "bool({})"
286 | ]
287 | },
288 | {
289 | "cell_type": "code",
290 | "execution_count": 13,
291 | "metadata": {},
292 | "outputs": [
293 | {
294 | "data": {
295 | "text/plain": [
296 | "True"
297 | ]
298 | },
299 | "execution_count": 13,
300 | "metadata": {},
301 | "output_type": "execute_result"
302 | }
303 | ],
304 | "source": [
305 | "bool({1: 'one'})"
306 | ]
307 | },
308 | {
309 | "cell_type": "code",
310 | "execution_count": 14,
311 | "metadata": {},
312 | "outputs": [
313 | {
314 | "data": {
315 | "text/plain": [
316 | "True"
317 | ]
318 | },
319 | "execution_count": 14,
320 | "metadata": {},
321 | "output_type": "execute_result"
322 | }
323 | ],
324 | "source": [
325 | "bool(12)"
326 | ]
327 | },
328 | {
329 | "cell_type": "markdown",
330 | "metadata": {},
331 | "source": [
332 | "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`."
333 | ]
334 | },
335 | {
336 | "cell_type": "markdown",
337 | "metadata": {},
338 | "source": [
339 | "## What About None?\n",
340 | "\n",
341 | "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`:"
342 | ]
343 | },
344 | {
345 | "cell_type": "code",
346 | "execution_count": 15,
347 | "metadata": {},
348 | "outputs": [
349 | {
350 | "data": {
351 | "text/plain": [
352 | "False"
353 | ]
354 | },
355 | "execution_count": 15,
356 | "metadata": {},
357 | "output_type": "execute_result"
358 | }
359 | ],
360 | "source": [
361 | "None == 1"
362 | ]
363 | },
364 | {
365 | "cell_type": "code",
366 | "execution_count": 16,
367 | "metadata": {},
368 | "outputs": [
369 | {
370 | "data": {
371 | "text/plain": [
372 | "False"
373 | ]
374 | },
375 | "execution_count": 16,
376 | "metadata": {},
377 | "output_type": "execute_result"
378 | }
379 | ],
380 | "source": [
381 | "None == []"
382 | ]
383 | },
384 | {
385 | "cell_type": "code",
386 | "execution_count": 17,
387 | "metadata": {},
388 | "outputs": [
389 | {
390 | "data": {
391 | "text/plain": [
392 | "False"
393 | ]
394 | },
395 | "execution_count": 17,
396 | "metadata": {},
397 | "output_type": "execute_result"
398 | }
399 | ],
400 | "source": [
401 | "None == ''"
402 | ]
403 | },
404 | {
405 | "cell_type": "code",
406 | "execution_count": 18,
407 | "metadata": {},
408 | "outputs": [
409 | {
410 | "data": {
411 | "text/plain": [
412 | "True"
413 | ]
414 | },
415 | "execution_count": 18,
416 | "metadata": {},
417 | "output_type": "execute_result"
418 | }
419 | ],
420 | "source": [
421 | "None == None"
422 | ]
423 | },
424 | {
425 | "cell_type": "markdown",
426 | "metadata": {},
427 | "source": [
428 | "You can assign `None` to a variable. Note that all instances of `None` point to the same object though:"
429 | ]
430 | },
431 | {
432 | "cell_type": "code",
433 | "execution_count": 19,
434 | "metadata": {},
435 | "outputs": [],
436 | "source": [
437 | "x = None\n",
438 | "y = None"
439 | ]
440 | },
441 | {
442 | "cell_type": "code",
443 | "execution_count": 20,
444 | "metadata": {},
445 | "outputs": [
446 | {
447 | "data": {
448 | "text/plain": [
449 | "4304537616"
450 | ]
451 | },
452 | "execution_count": 20,
453 | "metadata": {},
454 | "output_type": "execute_result"
455 | }
456 | ],
457 | "source": [
458 | "id(x)"
459 | ]
460 | },
461 | {
462 | "cell_type": "code",
463 | "execution_count": 21,
464 | "metadata": {},
465 | "outputs": [
466 | {
467 | "data": {
468 | "text/plain": [
469 | "4304537616"
470 | ]
471 | },
472 | "execution_count": 21,
473 | "metadata": {},
474 | "output_type": "execute_result"
475 | }
476 | ],
477 | "source": [
478 | "id(y)"
479 | ]
480 | },
481 | {
482 | "cell_type": "markdown",
483 | "metadata": {},
484 | "source": [
485 | "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."
486 | ]
487 | },
488 | {
489 | "cell_type": "code",
490 | "execution_count": null,
491 | "metadata": {},
492 | "outputs": [],
493 | "source": []
494 | }
495 | ],
496 | "metadata": {
497 | "kernelspec": {
498 | "display_name": "Python 3",
499 | "language": "python",
500 | "name": "python3"
501 | },
502 | "language_info": {
503 | "codemirror_mode": {
504 | "name": "ipython",
505 | "version": 3
506 | },
507 | "file_extension": ".py",
508 | "mimetype": "text/x-python",
509 | "name": "python",
510 | "nbconvert_exporter": "python",
511 | "pygments_lexer": "ipython3",
512 | "version": "3.6.4"
513 | }
514 | },
515 | "nbformat": 4,
516 | "nbformat_minor": 2
517 | }
518 |
--------------------------------------------------------------------------------
/chapter11_conditionals/Chapter 11 - Conditional Statements.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Chapter 11 - Conditional Statements\n",
8 | "\n",
9 | "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",
10 | "\n",
11 | "In this chapter you will learn about the following:\n",
12 | "\n",
13 | "* Comparison operators\n",
14 | "* Creating a simple conditional\n",
15 | "* Branching conditional statements\n",
16 | "* Nesting conditionals\n",
17 | "* Logical operators\n",
18 | "* Special operators\n",
19 | "\n",
20 | "Let's get started by learning about comparison operators!"
21 | ]
22 | },
23 | {
24 | "cell_type": "markdown",
25 | "metadata": {},
26 | "source": [
27 | "## Comparison Operators\n",
28 | "\n",
29 | "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",
30 | "\n",
31 | "Python's comparison operators are shown in the following table:\n",
32 | "\n",
33 | "|Operator |Meaning |\n",
34 | "|---------|--------|\n",
35 | "|> |Greater than - This is `True` is the left operand is greater than the right|\n",
36 | "|< |Less than - This is `True` is the left operand is less than the right one|\n",
37 | "|== |Equal to - This is `True` only when both operands are equal|\n",
38 | "|!= |Not equal to - This is `True` if the operands are not equal|\n",
39 | "|>= |Greater than or equal to - This is `True` when the left operand is greater than or equal to the right|\n",
40 | "|<= |Less than or equal to - This is `True` when the left operand is less than or equal to the right|\n",
41 | "\n",
42 | "Now that you know what comparison operators are available to you in Python, you can start using them!\n",
43 | "\n",
44 | "Here are some examples:\n"
45 | ]
46 | },
47 | {
48 | "cell_type": "code",
49 | "execution_count": 2,
50 | "metadata": {},
51 | "outputs": [
52 | {
53 | "data": {
54 | "text/plain": [
55 | "False"
56 | ]
57 | },
58 | "execution_count": 2,
59 | "metadata": {},
60 | "output_type": "execute_result"
61 | }
62 | ],
63 | "source": [
64 | "a = 2\n",
65 | "b = 3\n",
66 | "a == b"
67 | ]
68 | },
69 | {
70 | "cell_type": "code",
71 | "execution_count": 3,
72 | "metadata": {},
73 | "outputs": [
74 | {
75 | "data": {
76 | "text/plain": [
77 | "False"
78 | ]
79 | },
80 | "execution_count": 3,
81 | "metadata": {},
82 | "output_type": "execute_result"
83 | }
84 | ],
85 | "source": [
86 | "a > b"
87 | ]
88 | },
89 | {
90 | "cell_type": "code",
91 | "execution_count": 4,
92 | "metadata": {},
93 | "outputs": [
94 | {
95 | "data": {
96 | "text/plain": [
97 | "True"
98 | ]
99 | },
100 | "execution_count": 4,
101 | "metadata": {},
102 | "output_type": "execute_result"
103 | }
104 | ],
105 | "source": [
106 | "a < b"
107 | ]
108 | },
109 | {
110 | "cell_type": "code",
111 | "execution_count": 5,
112 | "metadata": {},
113 | "outputs": [
114 | {
115 | "data": {
116 | "text/plain": [
117 | "False"
118 | ]
119 | },
120 | "execution_count": 5,
121 | "metadata": {},
122 | "output_type": "execute_result"
123 | }
124 | ],
125 | "source": [
126 | "a >= b"
127 | ]
128 | },
129 | {
130 | "cell_type": "code",
131 | "execution_count": 6,
132 | "metadata": {},
133 | "outputs": [
134 | {
135 | "data": {
136 | "text/plain": [
137 | "True"
138 | ]
139 | },
140 | "execution_count": 6,
141 | "metadata": {},
142 | "output_type": "execute_result"
143 | }
144 | ],
145 | "source": [
146 | "a <= b"
147 | ]
148 | },
149 | {
150 | "cell_type": "code",
151 | "execution_count": 7,
152 | "metadata": {},
153 | "outputs": [
154 | {
155 | "data": {
156 | "text/plain": [
157 | "True"
158 | ]
159 | },
160 | "execution_count": 7,
161 | "metadata": {},
162 | "output_type": "execute_result"
163 | }
164 | ],
165 | "source": [
166 | "a != b"
167 | ]
168 | },
169 | {
170 | "cell_type": "markdown",
171 | "metadata": {},
172 | "source": [
173 | "## Creating a Simple Conditional"
174 | ]
175 | },
176 | {
177 | "cell_type": "markdown",
178 | "metadata": {},
179 | "source": [
180 | "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",
181 | "\n",
182 | "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",
183 | "\n",
184 | "Let's create a pretend authentication example:"
185 | ]
186 | },
187 | {
188 | "cell_type": "code",
189 | "execution_count": 8,
190 | "metadata": {},
191 | "outputs": [
192 | {
193 | "name": "stdout",
194 | "output_type": "stream",
195 | "text": [
196 | "You are logged in\n"
197 | ]
198 | }
199 | ],
200 | "source": [
201 | "authenticated = True\n",
202 | "if authenticated:\n",
203 | " print('You are logged in')"
204 | ]
205 | },
206 | {
207 | "cell_type": "markdown",
208 | "metadata": {},
209 | "source": [
210 | "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",
211 | "\n",
212 | "```\n",
213 | "if :\n",
214 | " # do something here\n",
215 | "```"
216 | ]
217 | },
218 | {
219 | "cell_type": "markdown",
220 | "metadata": {},
221 | "source": [
222 | "## Branching Conditional Statements\n",
223 | "\n",
224 | "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",
225 | "\n",
226 | "To get that to work, you can use the keyword `else`:"
227 | ]
228 | },
229 | {
230 | "cell_type": "code",
231 | "execution_count": 9,
232 | "metadata": {},
233 | "outputs": [
234 | {
235 | "name": "stdout",
236 | "output_type": "stream",
237 | "text": [
238 | "Please login\n"
239 | ]
240 | }
241 | ],
242 | "source": [
243 | "authenticated = False\n",
244 | "if authenticated:\n",
245 | " print('You are logged in')\n",
246 | "else:\n",
247 | " print('Please login')"
248 | ]
249 | },
250 | {
251 | "cell_type": "markdown",
252 | "metadata": {},
253 | "source": [
254 | "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",
255 | "\n",
256 | "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:"
257 | ]
258 | },
259 | {
260 | "cell_type": "code",
261 | "execution_count": 10,
262 | "metadata": {},
263 | "outputs": [
264 | {
265 | "name": "stdout",
266 | "output_type": "stream",
267 | "text": [
268 | "You can buy candy\n"
269 | ]
270 | }
271 | ],
272 | "source": [
273 | "age = 10\n",
274 | "if age < 18:\n",
275 | " print('You can buy candy')\n",
276 | "elif age < 21:\n",
277 | " print('You can purchase tobacco and candy, but not alcohol')\n",
278 | "elif age >= 21:\n",
279 | " print('You can buy anything!')"
280 | ]
281 | },
282 | {
283 | "cell_type": "markdown",
284 | "metadata": {},
285 | "source": [
286 | "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",
287 | "\n",
288 | "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",
289 | "\n",
290 | "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",
291 | "\n",
292 | "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."
293 | ]
294 | },
295 | {
296 | "cell_type": "markdown",
297 | "metadata": {},
298 | "source": [
299 | "## Nesting Conditionals\n",
300 | "\n",
301 | "You can put an `if` statement inside of another `if` statement. This is known as nesting.\n",
302 | "\n",
303 | "Let's look at a silly example:"
304 | ]
305 | },
306 | {
307 | "cell_type": "code",
308 | "execution_count": 1,
309 | "metadata": {},
310 | "outputs": [
311 | {
312 | "name": "stdout",
313 | "output_type": "stream",
314 | "text": [
315 | "You buy American\n"
316 | ]
317 | }
318 | ],
319 | "source": [
320 | "age = 21\n",
321 | "car = 'Ford'\n",
322 | "if age >= 21:\n",
323 | " if car in ['Honda', 'Toyota']:\n",
324 | " print('You buy foreign cars')\n",
325 | " elif car in ['Ford', 'Chevrolet']:\n",
326 | " print('You buy American')\n",
327 | "else:\n",
328 | " print('You are too young!')"
329 | ]
330 | },
331 | {
332 | "cell_type": "markdown",
333 | "metadata": {},
334 | "source": [
335 | "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",
336 | "\n",
337 | "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",
338 | "\n",
339 | "Fortunately, logical operators can help alleviate this issue!\n",
340 | "\n",
341 | "## Logical Operators\n",
342 | "\n",
343 | "Logical operators allow you to chain multiple expressions together using special keywords.\n",
344 | "\n",
345 | "Here are the three logical operators that Python supports:\n",
346 | "\n",
347 | "* `and` - Only `True` is both the operands are true\n",
348 | "* `or` - `True` is either of the operands are true\n",
349 | "* `not` - `True` is the operand is false\n",
350 | "\n",
351 | "Let's try using the logical operator, `and` with the example from the last section to flatten your conditional statements:"
352 | ]
353 | },
354 | {
355 | "cell_type": "code",
356 | "execution_count": 2,
357 | "metadata": {},
358 | "outputs": [
359 | {
360 | "name": "stdout",
361 | "output_type": "stream",
362 | "text": [
363 | "You buy American\n"
364 | ]
365 | }
366 | ],
367 | "source": [
368 | "age = 21\n",
369 | "car = 'Ford'\n",
370 | "if age >= 21 and car in ['Honda', 'Toyota']:\n",
371 | " print('You buy foreign cars')\n",
372 | "elif age >= 21 and car in ['Ford', 'Chevrolet']:\n",
373 | " print('You buy American')\n",
374 | "else:\n",
375 | " print('You are too young!')"
376 | ]
377 | },
378 | {
379 | "cell_type": "markdown",
380 | "metadata": {},
381 | "source": [
382 | "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",
383 | "\n",
384 | "Let's see what happens if you change the `and` to an `or`:"
385 | ]
386 | },
387 | {
388 | "cell_type": "code",
389 | "execution_count": 3,
390 | "metadata": {},
391 | "outputs": [
392 | {
393 | "name": "stdout",
394 | "output_type": "stream",
395 | "text": [
396 | "You buy foreign cars\n"
397 | ]
398 | }
399 | ],
400 | "source": [
401 | "age = 21\n",
402 | "car = 'Ford'\n",
403 | "if age >= 21 or car in ['Honda', 'Toyota']:\n",
404 | " print('You buy foreign cars')\n",
405 | "elif age >= 21 and car in ['Ford', 'Chevrolet']:\n",
406 | " print('You buy American')\n",
407 | "else:\n",
408 | " print('You are too young!')"
409 | ]
410 | },
411 | {
412 | "cell_type": "markdown",
413 | "metadata": {},
414 | "source": [
415 | "Wait a minute! You said your car was \"Ford\", but this code is saying you buy foreign cars! What's going on here?\n",
416 | "\n",
417 | "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",
418 | "\n",
419 | "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",
420 | "\n",
421 | "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",
422 | "\n",
423 | "Here is one way you could use `not`:"
424 | ]
425 | },
426 | {
427 | "cell_type": "code",
428 | "execution_count": 14,
429 | "metadata": {},
430 | "outputs": [
431 | {
432 | "data": {
433 | "text/plain": [
434 | "True"
435 | ]
436 | },
437 | "execution_count": 14,
438 | "metadata": {},
439 | "output_type": "execute_result"
440 | }
441 | ],
442 | "source": [
443 | "my_list = [1, 2, 3, 4]\n",
444 | "5 not in my_list"
445 | ]
446 | },
447 | {
448 | "cell_type": "markdown",
449 | "metadata": {},
450 | "source": [
451 | "In this case, you are checking to see if an integer is `not` in a `list`.\n",
452 | "\n",
453 | "Let's use another authentication example to demonstrate how you might use `not`:"
454 | ]
455 | },
456 | {
457 | "cell_type": "code",
458 | "execution_count": 15,
459 | "metadata": {},
460 | "outputs": [
461 | {
462 | "name": "stdout",
463 | "output_type": "stream",
464 | "text": [
465 | "You are not authorized!\n"
466 | ]
467 | }
468 | ],
469 | "source": [
470 | "ids = [1234, 5678]\n",
471 | "my_id = 1001\n",
472 | "if my_id not in ids:\n",
473 | " print('You are not authorized!')"
474 | ]
475 | },
476 | {
477 | "cell_type": "markdown",
478 | "metadata": {},
479 | "source": [
480 | "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",
481 | "\n",
482 | "You can also combine logical operators in a conditional statement. Here's an example:"
483 | ]
484 | },
485 | {
486 | "cell_type": "code",
487 | "execution_count": 16,
488 | "metadata": {},
489 | "outputs": [
490 | {
491 | "name": "stdout",
492 | "output_type": "stream",
493 | "text": [
494 | "You are 21 years old with brown hair\n"
495 | ]
496 | }
497 | ],
498 | "source": [
499 | "hair = 'brown'\n",
500 | "age = 21\n",
501 | "if age >= 21 and (hair == 'brown' or hair == 'blue'):\n",
502 | " print(f'You are {age} years old with {hair} hair')\n",
503 | "else:\n",
504 | " print(f'You are too young at {age} years old')"
505 | ]
506 | },
507 | {
508 | "cell_type": "markdown",
509 | "metadata": {},
510 | "source": [
511 | "## Special Operators\n",
512 | "\n",
513 | "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",
514 | "\n",
515 | "Do you remember which one of these you just used?\n",
516 | "\n",
517 | "* `is` - `True` when the operands are identical (i.e. have the same id)\n",
518 | "* `is not` - `True` when the operands are not identical\n",
519 | "* `in` - `True` when the value is in the sequence \n",
520 | "* `not in` - `True` when the value is not in the sequence\n",
521 | "\n",
522 | "You used the last one, `not in` to determine if an id was not in the authorized access list. "
523 | ]
524 | },
525 | {
526 | "cell_type": "markdown",
527 | "metadata": {},
528 | "source": [
529 | "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",
530 | "\n",
531 | "Here's one way you could use this knowledge:"
532 | ]
533 | },
534 | {
535 | "cell_type": "code",
536 | "execution_count": 19,
537 | "metadata": {},
538 | "outputs": [
539 | {
540 | "name": "stdout",
541 | "output_type": "stream",
542 | "text": [
543 | "x is not in yn\n"
544 | ]
545 | }
546 | ],
547 | "source": [
548 | "valid_chars = 'yn'\n",
549 | "char = 'x'\n",
550 | "if char in valid_chars:\n",
551 | " print(f'{char} is a valid character')\n",
552 | "else:\n",
553 | " print(f'{char} is not in {valid_chars}')"
554 | ]
555 | },
556 | {
557 | "cell_type": "markdown",
558 | "metadata": {},
559 | "source": [
560 | "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."
561 | ]
562 | },
563 | {
564 | "cell_type": "code",
565 | "execution_count": null,
566 | "metadata": {},
567 | "outputs": [],
568 | "source": []
569 | }
570 | ],
571 | "metadata": {
572 | "kernelspec": {
573 | "display_name": "Python 3",
574 | "language": "python",
575 | "name": "python3"
576 | },
577 | "language_info": {
578 | "codemirror_mode": {
579 | "name": "ipython",
580 | "version": 3
581 | },
582 | "file_extension": ".py",
583 | "mimetype": "text/x-python",
584 | "name": "python",
585 | "nbconvert_exporter": "python",
586 | "pygments_lexer": "ipython3",
587 | "version": "3.6.4"
588 | }
589 | },
590 | "nbformat": 4,
591 | "nbformat_minor": 2
592 | }
593 |
--------------------------------------------------------------------------------
/chapter12_loops/Chapter 12 - Learning About Loops.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Chapter 12 - Learning About Loops\n",
8 | "\n",
9 | "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",
10 | "\n",
11 | "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",
12 | "\n",
13 | "In Python, there are two types of loop constructs:\n",
14 | "\n",
15 | "* The `for` loop\n",
16 | "* The `while` loop"
17 | ]
18 | },
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {},
22 | "source": [
23 | "## Creating a `for` Loop\n",
24 | "\n",
25 | "The `for` loop is the most popular looping construct in Python. A `for` loop is created using the following syntax:\n",
26 | "\n",
27 | "```python\n",
28 | "for x in iterable:\n",
29 | "\t# do something\n",
30 | "```\n",
31 | "\n",
32 | "Now the code above does nothing. So let's write a `for` loop that iterates over a list, one item at a time:"
33 | ]
34 | },
35 | {
36 | "cell_type": "code",
37 | "execution_count": 2,
38 | "metadata": {},
39 | "outputs": [
40 | {
41 | "name": "stdout",
42 | "output_type": "stream",
43 | "text": [
44 | "1\n",
45 | "2\n",
46 | "3\n"
47 | ]
48 | }
49 | ],
50 | "source": [
51 | "my_list = [1, 2, 3]\n",
52 | "for item in my_list:\n",
53 | " print(item)"
54 | ]
55 | },
56 | {
57 | "cell_type": "markdown",
58 | "metadata": {},
59 | "source": [
60 | "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",
61 | "\n",
62 | "Of course, most of the time you will actually want to do something to the item. For example, you might want to double it:"
63 | ]
64 | },
65 | {
66 | "cell_type": "code",
67 | "execution_count": 3,
68 | "metadata": {},
69 | "outputs": [
70 | {
71 | "name": "stdout",
72 | "output_type": "stream",
73 | "text": [
74 | "2\n",
75 | "4\n",
76 | "6\n"
77 | ]
78 | }
79 | ],
80 | "source": [
81 | "my_list = [1, 2, 3]\n",
82 | "for item in my_list:\n",
83 | " print(f'{item * 2}')"
84 | ]
85 | },
86 | {
87 | "cell_type": "markdown",
88 | "metadata": {},
89 | "source": [
90 | "Or you might want to only print out only the even numbered items:"
91 | ]
92 | },
93 | {
94 | "cell_type": "code",
95 | "execution_count": 4,
96 | "metadata": {},
97 | "outputs": [
98 | {
99 | "name": "stdout",
100 | "output_type": "stream",
101 | "text": [
102 | "2 is even\n"
103 | ]
104 | }
105 | ],
106 | "source": [
107 | "my_list = [1, 2, 3]\n",
108 | "for item in my_list:\n",
109 | " if item % 2 == 0:\n",
110 | " print(f'{item} is even')"
111 | ]
112 | },
113 | {
114 | "cell_type": "markdown",
115 | "metadata": {},
116 | "source": [
117 | "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",
118 | "\n",
119 | "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",
120 | "\n",
121 | "Let's learn what else you can loop over besides lists."
122 | ]
123 | },
124 | {
125 | "cell_type": "markdown",
126 | "metadata": {},
127 | "source": [
128 | "## Looping Over a String\n",
129 | "\n",
130 | "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",
131 | "\n",
132 | "Let's look at iterating over a string:"
133 | ]
134 | },
135 | {
136 | "cell_type": "code",
137 | "execution_count": 5,
138 | "metadata": {},
139 | "outputs": [
140 | {
141 | "name": "stdout",
142 | "output_type": "stream",
143 | "text": [
144 | "a\n",
145 | "b\n",
146 | "c\n",
147 | "d\n",
148 | "e\n",
149 | "f\n",
150 | "g\n"
151 | ]
152 | }
153 | ],
154 | "source": [
155 | "my_str = 'abcdefg'\n",
156 | "for letter in my_str:\n",
157 | " print(letter)"
158 | ]
159 | },
160 | {
161 | "cell_type": "markdown",
162 | "metadata": {},
163 | "source": [
164 | "## Looping Over a Dictionary\n",
165 | "\n",
166 | "Python dictionaries also allow looping. By default, when you loop over a dictionary, you will loop over its keys:\n"
167 | ]
168 | },
169 | {
170 | "cell_type": "code",
171 | "execution_count": 6,
172 | "metadata": {},
173 | "outputs": [
174 | {
175 | "name": "stdout",
176 | "output_type": "stream",
177 | "text": [
178 | "mdriscoll\n",
179 | "guido\n",
180 | "steve\n"
181 | ]
182 | }
183 | ],
184 | "source": [
185 | "users = {'mdriscoll': 'password', 'guido': 'python', 'steve': 'guac'}\n",
186 | "for user in users:\n",
187 | " print(user)"
188 | ]
189 | },
190 | {
191 | "cell_type": "markdown",
192 | "metadata": {},
193 | "source": [
194 | "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",
195 | "\n",
196 | "This leads us to looping over tuples and getting out individual items from a tuple while looping!\n",
197 | "\n",
198 | "## Extracting Multiple Values in a Tuple While Looping\n",
199 | "\n",
200 | "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"
201 | ]
202 | },
203 | {
204 | "cell_type": "code",
205 | "execution_count": 7,
206 | "metadata": {},
207 | "outputs": [
208 | {
209 | "name": "stdout",
210 | "output_type": "stream",
211 | "text": [
212 | "1 - banana\n",
213 | "2 - apple\n",
214 | "3 - pear\n"
215 | ]
216 | }
217 | ],
218 | "source": [
219 | "list_of_tuples = [(1, 'banana'), (2, 'apple'), (3, 'pear')]\n",
220 | "for number, fruit in list_of_tuples:\n",
221 | " print(f'{number} - {fruit}')"
222 | ]
223 | },
224 | {
225 | "cell_type": "markdown",
226 | "metadata": {},
227 | "source": [
228 | "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",
229 | "\n",
230 | "If you hadn't extracted the items individually from the tuples, you would have ended up with this kind of output:"
231 | ]
232 | },
233 | {
234 | "cell_type": "code",
235 | "execution_count": 9,
236 | "metadata": {},
237 | "outputs": [
238 | {
239 | "name": "stdout",
240 | "output_type": "stream",
241 | "text": [
242 | "(1, 'banana')\n",
243 | "(2, 'apple')\n",
244 | "(3, 'pear')\n"
245 | ]
246 | }
247 | ],
248 | "source": [
249 | "list_of_tuples = [(1, 'banana'), (2, 'apple'), (3, 'pear')]\n",
250 | "for item in list_of_tuples:\n",
251 | " print(item)"
252 | ]
253 | },
254 | {
255 | "cell_type": "markdown",
256 | "metadata": {},
257 | "source": [
258 | "## Using `enumerate` with Loops\n",
259 | "\n",
260 | "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",
261 | "\n",
262 | "This allows you to know the position of the item in the sequence easily while looping over the sequence.\n",
263 | "\n",
264 | "Here's an example:"
265 | ]
266 | },
267 | {
268 | "cell_type": "code",
269 | "execution_count": 10,
270 | "metadata": {},
271 | "outputs": [
272 | {
273 | "name": "stdout",
274 | "output_type": "stream",
275 | "text": [
276 | "0 - a\n",
277 | "1 - b\n",
278 | "2 - c\n",
279 | "3 - d\n",
280 | "4 - e\n",
281 | "5 - f\n",
282 | "6 - g\n"
283 | ]
284 | }
285 | ],
286 | "source": [
287 | "my_str = 'abcdefg'\n",
288 | "for pos, letter in enumerate(my_str):\n",
289 | " print(f'{pos} - {letter}')"
290 | ]
291 | },
292 | {
293 | "cell_type": "markdown",
294 | "metadata": {},
295 | "source": [
296 | "## Creating a `while` Loop\n",
297 | "\n",
298 | "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",
299 | "\n",
300 | "Let's take a look at how these loops work:"
301 | ]
302 | },
303 | {
304 | "cell_type": "code",
305 | "execution_count": 11,
306 | "metadata": {},
307 | "outputs": [
308 | {
309 | "name": "stdout",
310 | "output_type": "stream",
311 | "text": [
312 | "0\n",
313 | "1\n",
314 | "2\n",
315 | "3\n",
316 | "4\n",
317 | "5\n",
318 | "6\n",
319 | "7\n",
320 | "8\n",
321 | "9\n"
322 | ]
323 | }
324 | ],
325 | "source": [
326 | "count = 0\n",
327 | "while count < 10:\n",
328 | " print(count)\n",
329 | " count += 1"
330 | ]
331 | },
332 | {
333 | "cell_type": "markdown",
334 | "metadata": {},
335 | "source": [
336 | "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",
337 | "\n",
338 | "If you forgot to increment the `count`, the loop would run until you stop or terminate the Python process. \n",
339 | "\n",
340 | "You can create an infinite loop by making that mistake or you could do something like this:"
341 | ]
342 | },
343 | {
344 | "cell_type": "code",
345 | "execution_count": null,
346 | "metadata": {},
347 | "outputs": [],
348 | "source": [
349 | "while True:\n",
350 | " print('Program running')"
351 | ]
352 | },
353 | {
354 | "cell_type": "markdown",
355 | "metadata": {},
356 | "source": [
357 | "Since the expression is always `True`, this code will print out the string, \"Program running\", forever or until you kill the process."
358 | ]
359 | },
360 | {
361 | "cell_type": "markdown",
362 | "metadata": {},
363 | "source": [
364 | "## Breaking Out of a Loop\n",
365 | "\n",
366 | "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",
367 | "\n",
368 | "To stop a loop early, you can use the keyword `break`:"
369 | ]
370 | },
371 | {
372 | "cell_type": "code",
373 | "execution_count": 2,
374 | "metadata": {},
375 | "outputs": [
376 | {
377 | "name": "stdout",
378 | "output_type": "stream",
379 | "text": [
380 | "0\n",
381 | "1\n",
382 | "2\n",
383 | "3\n",
384 | "count=4\n"
385 | ]
386 | }
387 | ],
388 | "source": [
389 | "count = 0\n",
390 | "while count < 10:\n",
391 | " if count == 4:\n",
392 | " print(f'count={count}')\n",
393 | " break\n",
394 | " print(count)\n",
395 | " count += 1"
396 | ]
397 | },
398 | {
399 | "cell_type": "markdown",
400 | "metadata": {},
401 | "source": [
402 | "You can also use `break` in a `for` loop:"
403 | ]
404 | },
405 | {
406 | "cell_type": "code",
407 | "execution_count": 3,
408 | "metadata": {},
409 | "outputs": [
410 | {
411 | "name": "stdout",
412 | "output_type": "stream",
413 | "text": [
414 | "1 - banana\n",
415 | "Apple found!\n"
416 | ]
417 | }
418 | ],
419 | "source": [
420 | "list_of_tuples = [(1, 'banana'), (2, 'apple'), (3, 'pear')]\n",
421 | "for number, fruit in list_of_tuples:\n",
422 | " if fruit == 'apple':\n",
423 | " print('Apple found!')\n",
424 | " break\n",
425 | " print(f'{number} - {fruit}')"
426 | ]
427 | },
428 | {
429 | "cell_type": "markdown",
430 | "metadata": {},
431 | "source": [
432 | "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",
433 | "\n",
434 | "When you use `break`, the loop will only break out of the innermost loop that the `break` statement is in.\n",
435 | "\n",
436 | "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",
437 | "\n",
438 | "## Using `continue`\n",
439 | "\n",
440 | "The `continue` statement is used for continuing to the next iteration in the loop. You can use `continue` to skip over something.\n",
441 | "\n",
442 | "Let's write a loop that skips over even numbers:"
443 | ]
444 | },
445 | {
446 | "cell_type": "code",
447 | "execution_count": 4,
448 | "metadata": {},
449 | "outputs": [
450 | {
451 | "name": "stdout",
452 | "output_type": "stream",
453 | "text": [
454 | "3\n",
455 | "5\n",
456 | "7\n",
457 | "9\n",
458 | "11\n"
459 | ]
460 | }
461 | ],
462 | "source": [
463 | "for number in range(2, 12):\n",
464 | " if number % 2 == 0:\n",
465 | " continue\n",
466 | " print(number)"
467 | ]
468 | },
469 | {
470 | "cell_type": "markdown",
471 | "metadata": {},
472 | "source": [
473 | "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",
474 | "\n",
475 | "You can use clever conditional statements to skip over any number of things in a sequence by using the `continue` statement.\n",
476 | "\n",
477 | "## Loops and the `else` Statement\n",
478 | "\n",
479 | "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",
480 | "\n",
481 | "Another way to look at it is that the `else` statement only executes if the loop completes successfully.\n",
482 | "\n",
483 | "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",
484 | "\n",
485 | "Let's look at a quick example:"
486 | ]
487 | },
488 | {
489 | "cell_type": "code",
490 | "execution_count": 5,
491 | "metadata": {},
492 | "outputs": [
493 | {
494 | "name": "stdout",
495 | "output_type": "stream",
496 | "text": [
497 | "1\n",
498 | "2\n",
499 | "3\n",
500 | "Number 4 not found\n"
501 | ]
502 | }
503 | ],
504 | "source": [
505 | "my_list = [1, 2, 3]\n",
506 | "for number in my_list:\n",
507 | " if number == 4:\n",
508 | " print('Found number 4!')\n",
509 | " break\n",
510 | " print(number)\n",
511 | "else:\n",
512 | " print('Number 4 not found')"
513 | ]
514 | },
515 | {
516 | "cell_type": "markdown",
517 | "metadata": {},
518 | "source": [
519 | "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",
520 | "\n",
521 | "Try adding the number 4 to the `list` and then re-run the code:"
522 | ]
523 | },
524 | {
525 | "cell_type": "code",
526 | "execution_count": 6,
527 | "metadata": {},
528 | "outputs": [
529 | {
530 | "name": "stdout",
531 | "output_type": "stream",
532 | "text": [
533 | "1\n",
534 | "2\n",
535 | "3\n",
536 | "Found number 4!\n"
537 | ]
538 | }
539 | ],
540 | "source": [
541 | "my_list = [1, 2, 3, 4]\n",
542 | "for number in my_list:\n",
543 | " if number == 4:\n",
544 | " print('Found number 4!')\n",
545 | " break\n",
546 | " print(number)\n",
547 | "else:\n",
548 | " print('Number 4 not found')"
549 | ]
550 | },
551 | {
552 | "cell_type": "markdown",
553 | "metadata": {},
554 | "source": [
555 | "## Nesting Loops\n",
556 | "\n",
557 | "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",
558 | "\n",
559 | "Let's use a nested `list` for your example:"
560 | ]
561 | },
562 | {
563 | "cell_type": "code",
564 | "execution_count": 7,
565 | "metadata": {},
566 | "outputs": [
567 | {
568 | "name": "stdout",
569 | "output_type": "stream",
570 | "text": [
571 | "List = ['mike', 12]\n",
572 | "Item -> mike\n",
573 | "Item -> 12\n",
574 | "List = ['jan', 15]\n",
575 | "Item -> jan\n",
576 | "Item -> 15\n",
577 | "List = ['alice', 8]\n",
578 | "Item -> alice\n",
579 | "Item -> 8\n"
580 | ]
581 | }
582 | ],
583 | "source": [
584 | "nested = [['mike', 12], ['jan', 15], ['alice', 8]]\n",
585 | "for lst in nested:\n",
586 | " print(f'List = {lst}')\n",
587 | " for item in lst:\n",
588 | " print(f'Item -> {item}')"
589 | ]
590 | },
591 | {
592 | "cell_type": "markdown",
593 | "metadata": {},
594 | "source": [
595 | "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",
596 | "\n",
597 | "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."
598 | ]
599 | },
600 | {
601 | "cell_type": "code",
602 | "execution_count": null,
603 | "metadata": {},
604 | "outputs": [],
605 | "source": []
606 | }
607 | ],
608 | "metadata": {
609 | "kernelspec": {
610 | "display_name": "Python 3",
611 | "language": "python",
612 | "name": "python3"
613 | },
614 | "language_info": {
615 | "codemirror_mode": {
616 | "name": "ipython",
617 | "version": 3
618 | },
619 | "file_extension": ".py",
620 | "mimetype": "text/x-python",
621 | "name": "python",
622 | "nbconvert_exporter": "python",
623 | "pygments_lexer": "ipython3",
624 | "version": "3.6.4"
625 | }
626 | },
627 | "nbformat": 4,
628 | "nbformat_minor": 2
629 | }
630 |
--------------------------------------------------------------------------------
/chapter12_loops/for_loop_else.py:
--------------------------------------------------------------------------------
1 | my_list = [1, 2, 3]
2 | for number in my_list:
3 | if number == 4:
4 | print('Found number 4!')
5 | break
6 | print(number)
7 | else:
8 | print('Number 4 not found')
--------------------------------------------------------------------------------
/chapter12_loops/for_loop_else_2.py:
--------------------------------------------------------------------------------
1 | my_list = [1, 2, 3, 4]
2 | for number in my_list:
3 | if number == 4:
4 | print('Found number 4!')
5 | break
6 | print(number)
7 | else:
8 | print('Number 4 not found')
--------------------------------------------------------------------------------
/chapter12_loops/for_loop_with_break.py:
--------------------------------------------------------------------------------
1 | list_of_tuples = [(1, 'banana'), (2, 'apple'), (3, 'pear')]
2 | for number, fruit in list_of_tuples:
3 | if fruit == 'apple':
4 | print('Apple found!')
5 | break
6 | print(f'{number} - {fruit}')
--------------------------------------------------------------------------------
/chapter12_loops/nested_loops.py:
--------------------------------------------------------------------------------
1 | nested = [['mike', 12], ['jan', 15], ['alice', 8]]
2 | for lst in nested:
3 | print(f'List = {lst}')
4 | for item in lst:
5 | print(f'Item -> {item}')
--------------------------------------------------------------------------------
/chapter12_loops/while_with_break.py:
--------------------------------------------------------------------------------
1 | count = 0
2 | while count < 10:
3 | if count == 4:
4 | print(f'count={count}')
5 | break
6 | print(count)
7 | count += 1
--------------------------------------------------------------------------------
/chapter13_comprehensions/Chapter 13 - Python Comprehensions.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Chapter 13 - Python Comprehensions\n",
8 | "\n",
9 | "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",
10 | "\n",
11 | "In this chapter you will learn about:\n",
12 | "\n",
13 | "* List comprehensions\n",
14 | "* Dictionary comprehensions\n",
15 | "* Set comprehensions\n",
16 | "\n",
17 | "## List Comprehensions\n",
18 | "\n",
19 | "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",
20 | "\n",
21 | "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",
22 | "\n",
23 | "Here is an example:"
24 | ]
25 | },
26 | {
27 | "cell_type": "code",
28 | "execution_count": 4,
29 | "metadata": {},
30 | "outputs": [
31 | {
32 | "data": {
33 | "text/plain": [
34 | "[1, 2, 3]"
35 | ]
36 | },
37 | "execution_count": 4,
38 | "metadata": {},
39 | "output_type": "execute_result"
40 | }
41 | ],
42 | "source": [
43 | "sequence = [1, 2, 3]\n",
44 | "new_list = [x for x in sequence]\n",
45 | "new_list"
46 | ]
47 | },
48 | {
49 | "cell_type": "markdown",
50 | "metadata": {},
51 | "source": [
52 | "This is equivalent to the following loop:"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "execution_count": 3,
58 | "metadata": {},
59 | "outputs": [
60 | {
61 | "data": {
62 | "text/plain": [
63 | "[1, 2, 3]"
64 | ]
65 | },
66 | "execution_count": 3,
67 | "metadata": {},
68 | "output_type": "execute_result"
69 | }
70 | ],
71 | "source": [
72 | "sequence = [1, 2, 3]\n",
73 | "new_list = []\n",
74 | "for x in sequence:\n",
75 | " new_list.append(x)\n",
76 | "new_list"
77 | ]
78 | },
79 | {
80 | "cell_type": "markdown",
81 | "metadata": {},
82 | "source": [
83 | "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:"
84 | ]
85 | },
86 | {
87 | "cell_type": "code",
88 | "execution_count": 5,
89 | "metadata": {},
90 | "outputs": [
91 | {
92 | "data": {
93 | "text/plain": [
94 | "[2, 4, 6]"
95 | ]
96 | },
97 | "execution_count": 5,
98 | "metadata": {},
99 | "output_type": "execute_result"
100 | }
101 | ],
102 | "source": [
103 | "sequence = [1, 2, 3]\n",
104 | "new_list = [x * 2 for x in sequence]\n",
105 | "new_list"
106 | ]
107 | },
108 | {
109 | "cell_type": "markdown",
110 | "metadata": {},
111 | "source": [
112 | "### Filtering List Comprehensions\n",
113 | "\n",
114 | "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",
115 | "\n",
116 | "Here is how it works:"
117 | ]
118 | },
119 | {
120 | "cell_type": "code",
121 | "execution_count": 7,
122 | "metadata": {},
123 | "outputs": [
124 | {
125 | "data": {
126 | "text/plain": [
127 | "range(0, 10)"
128 | ]
129 | },
130 | "execution_count": 7,
131 | "metadata": {},
132 | "output_type": "execute_result"
133 | }
134 | ],
135 | "source": [
136 | "range(10)"
137 | ]
138 | },
139 | {
140 | "cell_type": "code",
141 | "execution_count": 8,
142 | "metadata": {},
143 | "outputs": [
144 | {
145 | "data": {
146 | "text/plain": [
147 | "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"
148 | ]
149 | },
150 | "execution_count": 8,
151 | "metadata": {},
152 | "output_type": "execute_result"
153 | }
154 | ],
155 | "source": [
156 | "list(range(10))"
157 | ]
158 | },
159 | {
160 | "cell_type": "markdown",
161 | "metadata": {},
162 | "source": [
163 | "You can use Python's `list()` function to turn the `range` object into a list of numbers, 0-9.\n",
164 | "\n",
165 | "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:"
166 | ]
167 | },
168 | {
169 | "cell_type": "code",
170 | "execution_count": 9,
171 | "metadata": {},
172 | "outputs": [
173 | {
174 | "data": {
175 | "text/plain": [
176 | "[1, 3, 5, 7, 9]"
177 | ]
178 | },
179 | "execution_count": 9,
180 | "metadata": {},
181 | "output_type": "execute_result"
182 | }
183 | ],
184 | "source": [
185 | "odd_numbers = [x for x in range(10) if x % 2]\n",
186 | "odd_numbers"
187 | ]
188 | },
189 | {
190 | "cell_type": "markdown",
191 | "metadata": {},
192 | "source": [
193 | "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:"
194 | ]
195 | },
196 | {
197 | "cell_type": "code",
198 | "execution_count": 10,
199 | "metadata": {},
200 | "outputs": [
201 | {
202 | "data": {
203 | "text/plain": [
204 | "[(1, 'dog'), (2, 'cat'), (3, 'python')]"
205 | ]
206 | },
207 | "execution_count": 10,
208 | "metadata": {},
209 | "output_type": "execute_result"
210 | }
211 | ],
212 | "source": [
213 | "my_dict = {1: 'dog', 2: 'cat', 3: 'python'}\n",
214 | "[(num, animal) for num in my_dict for animal in my_dict.values() if my_dict[num] == animal]"
215 | ]
216 | },
217 | {
218 | "cell_type": "markdown",
219 | "metadata": {},
220 | "source": [
221 | "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",
222 | "\n",
223 | "Here is the equivalent as a regular `for` loop:"
224 | ]
225 | },
226 | {
227 | "cell_type": "code",
228 | "execution_count": 12,
229 | "metadata": {},
230 | "outputs": [
231 | {
232 | "data": {
233 | "text/plain": [
234 | "[(1, 'dog'), (2, 'cat'), (3, 'python')]"
235 | ]
236 | },
237 | "execution_count": 12,
238 | "metadata": {},
239 | "output_type": "execute_result"
240 | }
241 | ],
242 | "source": [
243 | "my_dict = {1: 'dog', 2: 'cat', 3: 'python'}\n",
244 | "my_list = []\n",
245 | "for num in my_dict:\n",
246 | " for animal in my_dict.values():\n",
247 | " if my_dict[num] == animal:\n",
248 | " my_list.append((num, animal))\n",
249 | "my_list"
250 | ]
251 | },
252 | {
253 | "cell_type": "markdown",
254 | "metadata": {},
255 | "source": [
256 | "You can make the previous list comprehension a bit more readable by putting some line breaks in it, like this:"
257 | ]
258 | },
259 | {
260 | "cell_type": "code",
261 | "execution_count": 13,
262 | "metadata": {},
263 | "outputs": [
264 | {
265 | "data": {
266 | "text/plain": [
267 | "[(1, 'dog'), (2, 'cat'), (3, 'python')]"
268 | ]
269 | },
270 | "execution_count": 13,
271 | "metadata": {},
272 | "output_type": "execute_result"
273 | }
274 | ],
275 | "source": [
276 | "my_dict = {1: 'dog', 2: 'cat', 3: 'python'}\n",
277 | "[(num, animal) for num in my_dict \n",
278 | " for animal in my_dict.values() \n",
279 | " if my_dict[num] == animal]"
280 | ]
281 | },
282 | {
283 | "cell_type": "markdown",
284 | "metadata": {},
285 | "source": [
286 | "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",
287 | "\n",
288 | "## Nested List Comprehensions\n",
289 | "\n",
290 | "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",
291 | "\n",
292 | "A matrix is usually represented as a list of lists where the internal lists contain integers or floats. \n",
293 | "\n",
294 | "Let's look at an example of that:"
295 | ]
296 | },
297 | {
298 | "cell_type": "code",
299 | "execution_count": 14,
300 | "metadata": {},
301 | "outputs": [
302 | {
303 | "data": {
304 | "text/plain": [
305 | "[[18, 16, 14], [12, 10, 8], [6, 4, 2]]"
306 | ]
307 | },
308 | "execution_count": 14,
309 | "metadata": {},
310 | "output_type": "execute_result"
311 | }
312 | ],
313 | "source": [
314 | "matrix = [[9, 8, 7], [6, 5, 4], [3, 2, 1]]\n",
315 | "[[element * 2 for element in row] for row in matrix]"
316 | ]
317 | },
318 | {
319 | "cell_type": "markdown",
320 | "metadata": {},
321 | "source": [
322 | "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",
323 | "\n",
324 | "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."
325 | ]
326 | },
327 | {
328 | "cell_type": "markdown",
329 | "metadata": {},
330 | "source": [
331 | "## Dictionary Comprehensions\n",
332 | "\n",
333 | "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",
334 | "\n",
335 | "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",
336 | "\n",
337 | "You can write a dictionary comprehension like this:"
338 | ]
339 | },
340 | {
341 | "cell_type": "code",
342 | "execution_count": 15,
343 | "metadata": {},
344 | "outputs": [
345 | {
346 | "data": {
347 | "text/plain": [
348 | "{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}"
349 | ]
350 | },
351 | "execution_count": 15,
352 | "metadata": {},
353 | "output_type": "execute_result"
354 | }
355 | ],
356 | "source": [
357 | "{key: value for key, value in enumerate('abcde')}"
358 | ]
359 | },
360 | {
361 | "cell_type": "markdown",
362 | "metadata": {},
363 | "source": [
364 | "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",
365 | "\n",
366 | "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."
367 | ]
368 | },
369 | {
370 | "cell_type": "markdown",
371 | "metadata": {},
372 | "source": [
373 | "## Set Comprehensions\n",
374 | "\n",
375 | "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",
376 | "\n",
377 | "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",
378 | "\n",
379 | "Let's take a look:"
380 | ]
381 | },
382 | {
383 | "cell_type": "code",
384 | "execution_count": 16,
385 | "metadata": {},
386 | "outputs": [
387 | {
388 | "data": {
389 | "text/plain": [
390 | "['a', 'a', 'a', 'b', 'b', 'c', 'd', 'e']"
391 | ]
392 | },
393 | "execution_count": 16,
394 | "metadata": {},
395 | "output_type": "execute_result"
396 | }
397 | ],
398 | "source": [
399 | "my_list = list('aaabbcde')\n",
400 | "my_list"
401 | ]
402 | },
403 | {
404 | "cell_type": "code",
405 | "execution_count": 17,
406 | "metadata": {},
407 | "outputs": [
408 | {
409 | "data": {
410 | "text/plain": [
411 | "{'a', 'b', 'c', 'd', 'e'}"
412 | ]
413 | },
414 | "execution_count": 17,
415 | "metadata": {},
416 | "output_type": "execute_result"
417 | }
418 | ],
419 | "source": [
420 | "my_set = {item for item in my_list}\n",
421 | "my_set"
422 | ]
423 | },
424 | {
425 | "cell_type": "markdown",
426 | "metadata": {},
427 | "source": [
428 | "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."
429 | ]
430 | },
431 | {
432 | "cell_type": "code",
433 | "execution_count": null,
434 | "metadata": {},
435 | "outputs": [],
436 | "source": []
437 | }
438 | ],
439 | "metadata": {
440 | "kernelspec": {
441 | "display_name": "Python 3",
442 | "language": "python",
443 | "name": "python3"
444 | },
445 | "language_info": {
446 | "codemirror_mode": {
447 | "name": "ipython",
448 | "version": 3
449 | },
450 | "file_extension": ".py",
451 | "mimetype": "text/x-python",
452 | "name": "python",
453 | "nbconvert_exporter": "python",
454 | "pygments_lexer": "ipython3",
455 | "version": "3.6.4"
456 | }
457 | },
458 | "nbformat": 4,
459 | "nbformat_minor": 2
460 | }
461 |
--------------------------------------------------------------------------------
/chapter14_files/example.txt:
--------------------------------------------------------------------------------
1 | This is an example text file
2 | with multiple lines
3 | for reading by Python
--------------------------------------------------------------------------------
/chapter14_files/read_file.py:
--------------------------------------------------------------------------------
1 | file_handler = open('example.txt')
2 | for line in file_handler:
3 | print(line)
4 | file_handler.close()
--------------------------------------------------------------------------------
/chapter14_files/read_file_with.py:
--------------------------------------------------------------------------------
1 | with open('example.txt') as file_handler:
2 | for line in file_handler:
3 | print(line)
--------------------------------------------------------------------------------
/chapter18_classes/__pycache__/ball.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/driscollis/python101code/47fbb3b296d9a07409764ea83759b9afa03fece1/chapter18_classes/__pycache__/ball.cpython-38.pyc
--------------------------------------------------------------------------------
/chapter18_classes/ball.py:
--------------------------------------------------------------------------------
1 | # ball.py
2 |
3 | class Ball:
4 |
5 | def __init__(self, color: str, size: float, weight: float,
6 | ball_type: str) -> None:
7 | self.color = color
8 | self.size = size
9 | self.weight = weight
10 | self.ball_type = ball_type
11 |
12 | def bounce(self):
13 | if self.ball_type.lower() == 'bowling':
14 | print("Bowling balls can't bounce!")
15 | else:
16 | print(f"The {self.ball_type} ball is bouncing!")
17 |
18 |
19 | if __name__ == "__main__":
20 | ball_one = Ball('black', 6, 12, 'bowling')
21 | ball_two = Ball('red', 12, 1, 'beach')
22 |
23 | ball_one.bounce()
24 | ball_two.bounce()
--------------------------------------------------------------------------------
/chapter18_classes/ball_printable.py:
--------------------------------------------------------------------------------
1 | # ball_printable.py
2 |
3 | class Ball:
4 |
5 | def __init__(self, color: str, size: float, weight: float,
6 | ball_type: str) -> None:
7 | self.color = color
8 | self.size = size
9 | self.weight = weight
10 | self.ball_type = ball_type
11 |
12 | def bounce(self):
13 | if self.ball_type.lower() == 'bowling':
14 | print("Bowling balls can't bounce!")
15 | else:
16 | print(f'The {self.ball_type} ball is bouncing!')
17 |
18 | def __repr__(self):
19 | return f''
20 |
21 |
22 | if __name__ == "__main__":
23 | ball_one = Ball('black', 6, 12, 'bowling')
24 | ball_two = Ball('red', 12, 1, 'beach')
25 |
26 | print(ball_one)
27 | print(ball_two)
--------------------------------------------------------------------------------
/chapter18_classes/ball_printable_str.py:
--------------------------------------------------------------------------------
1 | # ball_printable.py
2 |
3 | class Ball:
4 |
5 | def __init__(self, color: str, size: float, weight: float,
6 | ball_type: str) -> None:
7 | self.color = color
8 | self.size = size
9 | self.weight = weight
10 | self.ball_type = ball_type
11 |
12 | def bounce(self):
13 | if self.ball_type.lower() == 'bowling':
14 | print("Bowling balls can't bounce!")
15 | else:
16 | print(f'The {self.ball_type} ball is bouncing!')
17 |
18 | def __repr__(self):
19 | return f''
20 |
21 | def __str__(self):
22 | return f'{self.color} {self.ball_type} ball'
23 |
24 |
25 | if __name__ == "__main__":
26 | ball_one = Ball('black', 6, 12, 'bowling')
27 | ball_two = Ball('red', 12, 1, 'beach')
28 |
29 | print(ball_one)
30 | print(ball_two)
31 |
32 | print(f'{ball_one.__repr__()}')
33 | print(f'{ball_one.__str__()}')
--------------------------------------------------------------------------------
/chapter18_classes/bowling_ball.py:
--------------------------------------------------------------------------------
1 | # bowling_ball.py
2 | import ball
3 |
4 | class BowlingBall(ball.Ball):
5 |
6 | def roll(self):
7 | print(f'You are rolling the {self.ball_type} ball')
8 |
9 | if __name__ == '__main__':
10 | ball = BowlingBall('green', 10, 15, 'bowling')
11 | ball.roll()
12 |
13 |
--------------------------------------------------------------------------------
/chapter18_classes/simple_ball.py:
--------------------------------------------------------------------------------
1 | class Ball:
2 |
3 | def __init__(self, color, size, weight):
4 | """Constructor"""
5 | self.color = color
6 | self.size = size
7 | self.weight = weight
--------------------------------------------------------------------------------
/chapter18_classes/simple_ball_type_hints.py:
--------------------------------------------------------------------------------
1 | class Ball:
2 |
3 | def __init__(self, color: str, size: float, weight: float) -> None:
4 | self.color = color
5 | self.size = size
6 | self.weight = weight
--------------------------------------------------------------------------------
/chapter22_type_hints/bad_type_hinting.py:
--------------------------------------------------------------------------------
1 | # bad_type_hinting.py
2 |
3 | def my_function(a: str, b: str) -> None:
4 | return a.keys() + b.keys()
5 |
--------------------------------------------------------------------------------
/chapter22_type_hints/bad_type_hinting2.py:
--------------------------------------------------------------------------------
1 | # bad_type_hinting2.py
2 |
3 | def my_function(a: str, b: str) -> str:
4 | return a + b
5 |
--------------------------------------------------------------------------------
/chapter22_type_hints/good_type_hinting.py:
--------------------------------------------------------------------------------
1 | # good_type_hinting.py
2 |
3 | def my_function(a: str, b: str) -> str:
4 | return a + b
5 |
--------------------------------------------------------------------------------
/chapter23_threading/worker_thread_subclass.py:
--------------------------------------------------------------------------------
1 | # worker_thread_subclass.py
2 |
3 | import random
4 | import threading
5 | import time
6 |
7 | class WorkerThread(threading.Thread):
8 |
9 | def __init__(self, name):
10 | threading.Thread.__init__(self)
11 | self.name = name
12 | self.id = id(self)
13 |
14 | def run(self):
15 | """
16 | Run the thread
17 | """
18 | worker(self.name, self.id)
19 |
20 | def worker(name: str, instance_id: int) -> None:
21 | print(f'Started worker {name} - {instance_id}')
22 | worker_time = random.choice(range(1, 5))
23 | time.sleep(worker_time)
24 | print(f'{name} - {instance_id} worker finished in '
25 | f'{worker_time} seconds')
26 |
27 | if __name__ == '__main__':
28 | for i in range(5):
29 | thread = WorkerThread(name=f'computer_{i}')
30 | thread.start()
31 |
--------------------------------------------------------------------------------
/chapter23_threading/worker_threads.py:
--------------------------------------------------------------------------------
1 | # worker_threads.py
2 |
3 | import random
4 | import threading
5 | import time
6 |
7 |
8 | def worker(name: str) -> None:
9 | print(f'Started worker {name}')
10 | worker_time = random.choice(range(1, 5))
11 | time.sleep(worker_time)
12 | print(f'{name} worker finished in {worker_time} seconds')
13 |
14 | if __name__ == '__main__':
15 | for i in range(5):
16 | thread = threading.Thread(target=worker,
17 | args=(f'computer_{i}',))
18 | thread.start()
19 |
--------------------------------------------------------------------------------
/chapter23_threading/writing_thread.py:
--------------------------------------------------------------------------------
1 | # writing_thread.py
2 |
3 | import random
4 | import time
5 | from threading import Thread
6 |
7 |
8 | class WritingThread(Thread):
9 |
10 | def __init__(self, filename: str, number_of_lines: int,
11 | work_time: int = 1) -> None:
12 | Thread.__init__(self)
13 | self.filename = filename
14 | self.number_of_lines = number_of_lines
15 | self.work_time = work_time
16 |
17 | def run(self) -> None:
18 | """
19 | Run the thread
20 | """
21 | print(f'Writing {self.number_of_lines} lines of text to '
22 | f'{self.filename}')
23 | with open(self.filename, 'w') as f:
24 | for line in range(self.number_of_lines):
25 | text = f'This is line {line+1}\n'
26 | f.write(text)
27 | time.sleep(self.work_time)
28 | print(f'Finished writing {self.filename}')
29 |
30 | if __name__ == '__main__':
31 | files = [f'test{x}.txt' for x in range(1, 6)]
32 | for filename in files:
33 | work_time = random.choice(range(1, 3))
34 | number_of_lines = random.choice(range(5, 20))
35 | thread = WritingThread(filename, number_of_lines, work_time)
36 | thread.start()
--------------------------------------------------------------------------------
/chapter24_multiprocessing/process_pool.py:
--------------------------------------------------------------------------------
1 | import random
2 | import time
3 |
4 | from multiprocessing import Pool
5 |
6 |
7 | def worker(name: str) -> None:
8 | print(f'Started worker {name}')
9 | worker_time = random.choice(range(1, 5))
10 | time.sleep(worker_time)
11 | print(f'{name} worker finished in {worker_time} seconds')
12 |
13 | if __name__ == '__main__':
14 | process_names = [f'computer_{i}' for i in range(15)]
15 | pool = Pool(processes=5)
16 | pool.map(worker, process_names)
17 | #pool.terminate()
--------------------------------------------------------------------------------
/chapter24_multiprocessing/worker_process_subclass.py:
--------------------------------------------------------------------------------
1 | # worker_thread_subclass.py
2 |
3 | import random
4 | import multiprocessing
5 | import time
6 |
7 | class WorkerProcess(multiprocessing.Process):
8 |
9 | def __init__(self, name):
10 | multiprocessing.Process.__init__(self)
11 | self.name = name
12 |
13 | def run(self):
14 | """
15 | Run the thread
16 | """
17 | worker(self.name)
18 |
19 | def worker(name: str) -> None:
20 | print(f'Started worker {name}')
21 | worker_time = random.choice(range(1, 5))
22 | time.sleep(worker_time)
23 | print(f'{name} worker finished in {worker_time} seconds')
24 |
25 | if __name__ == '__main__':
26 | processes = []
27 | for i in range(5):
28 | process = WorkerProcess(name=f'computer_{i}')
29 | processes.append(process)
30 | process.start()
31 |
32 | for process in processes:
33 | process.join()
34 |
--------------------------------------------------------------------------------
/chapter24_multiprocessing/worker_processes.py:
--------------------------------------------------------------------------------
1 | import multiprocessing
2 | import random
3 | import time
4 |
5 |
6 | def worker(name: str) -> None:
7 | print(f'Started worker {name}')
8 | worker_time = random.choice(range(1, 5))
9 | time.sleep(worker_time)
10 | print(f'{name} worker finished in {worker_time} seconds')
11 |
12 | if __name__ == '__main__':
13 | processes = []
14 | for i in range(5):
15 | process = multiprocessing.Process(target=worker,
16 | args=(f'computer_{i}',))
17 | processes.append(process)
18 | process.start()
19 |
20 | for proc in processes:
21 | proc.join()
--------------------------------------------------------------------------------
/chapter26_debugging/debug_code.py:
--------------------------------------------------------------------------------
1 | # debug_code.py
2 |
3 | def log(number):
4 | print(f'Processing {number}')
5 | print(f'Adding 2 to number: {number + 2}')
6 |
7 |
8 | def looper(number):
9 | for i in range(number):
10 | log(i)
11 |
12 | if __name__ == '__main__':
13 | looper(5)
--------------------------------------------------------------------------------
/chapter26_debugging/debug_code_with_breakpoint.py:
--------------------------------------------------------------------------------
1 | # debug_code_with_breakpoint.py
2 |
3 | def log(number):
4 | print(f'Processing {number}')
5 | print(f'Adding 2 to number: {number + 2}')
6 |
7 |
8 | def looper(number):
9 | for i in range(number):
10 | breakpoint()
11 | log(i)
12 |
13 | if __name__ == '__main__':
14 | looper(5)
--------------------------------------------------------------------------------
/chapter26_debugging/debug_code_with_settrace.py:
--------------------------------------------------------------------------------
1 | # debug_code_with_settrace.py
2 |
3 | def log(number):
4 | print(f'Processing {number}')
5 | print(f'Adding 2 to number: {number + 2}')
6 |
7 |
8 | def looper(number):
9 | for i in range(number):
10 | import pdb; pdb.set_trace()
11 | log(i)
12 |
13 | if __name__ == '__main__':
14 | looper(5)
--------------------------------------------------------------------------------
/chapter27_decorators/amount_with_properties.py:
--------------------------------------------------------------------------------
1 | class Amount:
2 |
3 | def __init__(self):
4 | # private attribute
5 | self._amount = None
6 |
7 | def get_amount(self):
8 | return self._amount
9 |
10 | def set_amount(self, value):
11 | if isinstance(value, int) or isinstance(value, float):
12 | self._amount = value
13 | else:
14 | print(f'Value must be an int or float')
15 |
16 | amount = property(get_amount, set_amount)
17 |
18 | if __name__ == '__main__':
19 | amt = Amount()
20 | print(f'The current amount is {amt.amount}')
21 | amt.amount = 'the'
22 | print(f'The current amount is {amt.amount}')
23 | amt.amount = 5.5
24 | print(f'The current amount is {amt.amount}')
25 |
--------------------------------------------------------------------------------
/chapter27_decorators/amount_with_property_decorator.py:
--------------------------------------------------------------------------------
1 | class Amount:
2 |
3 | def __init__(self):
4 | # private attribute
5 | self._amount = None
6 |
7 | @property
8 | def amount(self):
9 | return self._amount
10 |
11 | @amount.setter
12 | def amount(self, value):
13 | if isinstance(value, int) or isinstance(value, float):
14 | self._amount = value
15 | else:
16 | print(f'Value must be an int or float')
17 |
18 |
19 | if __name__ == '__main__':
20 | amt = Amount()
21 | print(f'The current amount is {amt.amount}')
22 | amt.amount = 'the'
23 | print(f'The current amount is {amt.amount}')
24 | amt.amount = 5.5
25 | print(f'The current amount is {amt.amount}')
26 |
--------------------------------------------------------------------------------
/chapter27_decorators/amount_without_properties.py:
--------------------------------------------------------------------------------
1 | class Amount:
2 |
3 | def __init__(self):
4 | # private attribute
5 | self._amount = None
6 |
7 | def get_amount(self):
8 | return self._amount
9 |
10 | def set_amount(self, value):
11 | if isinstance(value, int) or isinstance(value, float):
12 | self._amount = value
13 | else:
14 | print(f'Value must be an int or float')
15 |
16 | if __name__ == '__main__':
17 | amt = Amount()
18 | print(f'The current amount is {amt.get_amount()}')
19 | amt.set_amount('the')
20 | print(f'The current amount is {amt.get_amount()}')
21 | amt.set_amount(5.5)
22 | print(f'The current amount is {amt.get_amount()}')
23 |
--------------------------------------------------------------------------------
/chapter27_decorators/classmethod_example.py:
--------------------------------------------------------------------------------
1 | class Time:
2 | """an example 24-hour time class"""
3 |
4 | def __init__(self, hour, minute):
5 | self.hour = hour
6 | self.minute = minute
7 |
8 | def __repr__(self):
9 | return "Time(%d, %d)" % (self.hour, self.minute)
10 |
11 | @classmethod
12 | def from_float(cls, moment):
13 | """2.5 == 2 hours, 30 minutes, 0 seconds, 0 microseconds"""
14 | hours = int(moment)
15 | if hours:
16 | moment = moment % hours
17 | minutes = int(moment * 60)
18 | return cls(hours, minutes)
19 |
20 | def to_float(self):
21 | """return self as a floating point number"""
22 | return self.hour + self.minute / 60
23 |
24 | Time(7, 30)
25 | Time.from_float(5.75)
26 | t = Time(10, 15)
27 | t.to_float()
--------------------------------------------------------------------------------
/chapter27_decorators/decorator_class.py:
--------------------------------------------------------------------------------
1 | # decorator_class.py
2 |
3 | class info:
4 |
5 | def __init__(self, arg1, arg2):
6 | print('running __init__')
7 | self.arg1 = arg1
8 | self.arg2 = arg2
9 | print('Decorator args: {}, {}'.format(arg1, arg2))
10 |
11 | def __call__(self, function):
12 | print('in __call__')
13 |
14 | def wrapper(*args, **kwargs):
15 | print('in wrapper()')
16 | return function(*args, **kwargs)
17 |
18 | return wrapper
19 |
20 | @info(3, 'Python')
21 | def treble(number):
22 | return number * 3
23 |
24 | print(treble(5))
--------------------------------------------------------------------------------
/chapter27_decorators/decorator_syntax.py:
--------------------------------------------------------------------------------
1 | # decorator_syntax.py
2 |
3 | def func_info(func):
4 | def wrapper(*args):
5 | print('Function name: ' + func.__name__)
6 | print('Function docstring: ' + str(func.__doc__))
7 | result = func(*args)
8 | return result
9 | return wrapper
10 |
11 | @func_info
12 | def treble(a: int) -> int:
13 | """A function that triples its input"""
14 | return a * 3
15 |
16 | print(treble(5))
17 |
--------------------------------------------------------------------------------
/chapter27_decorators/decorator_syntax_with_arguments.py:
--------------------------------------------------------------------------------
1 | # decorator_syntax_with_arguments.py
2 |
3 | def func_info(arg1, arg2):
4 | print('Decorator arg1 = ' + str(arg1))
5 | print('Decorator arg2 = ' + str(arg2))
6 |
7 | def the_real_decorator(function):
8 |
9 | def wrapper(*args, **kwargs):
10 | print('Function {} args: {} kwargs: {}'
11 | .format(
12 | function.__name__,
13 | str(args),
14 | str(kwargs)))
15 | return function(*args, **kwargs)
16 | return wrapper
17 |
18 | return the_real_decorator
19 |
20 | @func_info(3, 'Python')
21 | def treble(number):
22 | return number * 3
23 |
24 | print(treble(5))
25 |
--------------------------------------------------------------------------------
/chapter27_decorators/first_decorator.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | def func_info(func):
4 | def wrapper():
5 | print('Function name: ' + func.__name__)
6 | print('Function docstring: ' + str(func.__doc__))
7 | result = func()
8 | return result
9 | return wrapper
10 |
11 |
12 | def treble():
13 | return 3 * 3
14 |
15 | decorator = func_info(treble)
16 | print(decorator())
17 |
--------------------------------------------------------------------------------
/chapter27_decorators/first_decorator_updated.py:
--------------------------------------------------------------------------------
1 | # first_decorator_updated.py
2 |
3 | def func_info(func):
4 | def wrapper(*args):
5 | print('Function name: ' + func.__name__)
6 | print('Function docstring: ' + str(func.__doc__))
7 | result = func(*args)
8 | return result
9 | return wrapper
10 |
11 |
12 | def treble(a: int) -> int:
13 | """A function that triples its input"""
14 | return a * 3
15 |
16 |
17 | my_decorator = func_info(treble)
18 | print(my_decorator(5))
19 |
--------------------------------------------------------------------------------
/chapter27_decorators/logging_decorator.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | def logging_formatter(logger, name):
4 | """
5 | Format logger and add file handler
6 | """
7 | fh = logging.FileHandler(f"{name}.log")
8 | fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
9 | formatter = logging.Formatter(fmt)
10 | fh.setFormatter(formatter)
11 | logger.addHandler(fh)
12 |
13 | def log(func):
14 | """
15 | Log what function is called
16 | """
17 | def wrapper(*args, **kwargs):
18 | name = func.__name__
19 | logger = logging.getLogger(name)
20 | logger.setLevel(logging.INFO)
21 |
22 | # add logging formatter and file handler
23 | logging_formatter(logger, name)
24 |
25 | logger.info(f"Running function: {name}")
26 | logger.info(f"{args=}, {kwargs=}")
27 | result = func(*args, **kwargs)
28 | logger.info("Result: %s" % result)
29 | return func
30 | return wrapper
31 |
32 | @log
33 | def treble(a):
34 | return a * 3
35 |
36 | if __name__ == '__main__':
37 | treble(5)
38 |
--------------------------------------------------------------------------------
/chapter27_decorators/stacked_decorator_tracing.py:
--------------------------------------------------------------------------------
1 | def bold(func):
2 | print(f'You are wrapping {func.__name__} in bold')
3 | def bold_wrapper():
4 | return "" + func() + ""
5 | return bold_wrapper
6 |
7 | def italic(func):
8 | print(f'You are wrapping {func.__name__} in italic')
9 | def italic_wrapper():
10 | return "" + func() + ""
11 | return italic_wrapper
12 |
13 | @bold
14 | @italic
15 | def formatted_text():
16 | return 'Python rocks!'
17 |
18 | print(formatted_text())
--------------------------------------------------------------------------------
/chapter27_decorators/stacked_decorators.py:
--------------------------------------------------------------------------------
1 | def bold(func):
2 | def wrapper():
3 | return "" + func() + ""
4 | return wrapper
5 |
6 | def italic(func):
7 | def wrapper():
8 | return "" + func() + ""
9 | return wrapper
10 |
11 | @bold
12 | @italic
13 | def formatted_text():
14 | return 'Python rocks!'
15 |
16 | print(formatted_text())
--------------------------------------------------------------------------------
/chapter27_decorators/treble.log:
--------------------------------------------------------------------------------
1 | 2020-05-04 16:22:02,781 - treble - INFO - Running function: treble
2 | 2020-05-04 16:22:02,781 - treble - INFO - args=(5,), kwargs={}
3 | 2020-05-04 16:22:02,781 - treble - INFO - Result: 15
4 |
--------------------------------------------------------------------------------
/chapter29_profiling/callee_stats.py:
--------------------------------------------------------------------------------
1 | import pstats
2 |
3 | def formatted_stats_output(path):
4 | p = pstats.Stats(path)
5 | stripped_dirs = p.strip_dirs()
6 | sorted_stats = stripped_dirs.sort_stats('filename')
7 | sorted_stats.print_callers('\(main')
8 | sorted_stats.print_callees('\(main')
9 |
10 | if __name__ =='__main__':
11 | path = 'profile_output.txt'
12 | formatted_stats_output(path)
--------------------------------------------------------------------------------
/chapter29_profiling/filtered_stats.py:
--------------------------------------------------------------------------------
1 | import pstats
2 |
3 | def formatted_stats_output(path):
4 | p = pstats.Stats(path)
5 | stripped_dirs = p.strip_dirs()
6 | sorted_stats = stripped_dirs.sort_stats('filename')
7 | sorted_stats.print_stats('\(main')
8 |
9 | if __name__ =='__main__':
10 | path = 'profile_output.txt'
11 | formatted_stats_output(path)
--------------------------------------------------------------------------------
/chapter29_profiling/formatted_output.py:
--------------------------------------------------------------------------------
1 | import pstats
2 |
3 | def formatted_stats_output(path):
4 | p = pstats.Stats(path)
5 | stripped_dirs = p.strip_dirs()
6 | sorted_stats = stripped_dirs.sort_stats('filename')
7 | sorted_stats.print_stats()
8 |
9 | if __name__ =='__main__':
10 | path = 'profile_output.txt'
11 | formatted_stats_output(path)
--------------------------------------------------------------------------------
/chapter29_profiling/profile_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/driscollis/python101code/47fbb3b296d9a07409764ea83759b9afa03fece1/chapter29_profiling/profile_output.txt
--------------------------------------------------------------------------------
/chapter29_profiling/profile_test.py:
--------------------------------------------------------------------------------
1 | # profile_test.py
2 |
3 | import time
4 |
5 | def quick():
6 | print('Running quick')
7 | return 1 + 1
8 |
9 | def average():
10 | print('Running average')
11 | time.sleep(0.5)
12 |
13 | def super_slow():
14 | print('Running super slowly')
15 | time.sleep(2)
16 |
17 | def main():
18 | quick()
19 | super_slow()
20 | quick()
21 | average()
22 |
23 | if __name__ == '__main__':
24 | main()
--------------------------------------------------------------------------------
/chapter30_testing/add_doctest.py:
--------------------------------------------------------------------------------
1 | # add_doctest.py
2 |
3 | def add(a: int, b: int) -> int:
4 | """
5 | >>> add(1, 2)
6 | 3
7 | >>> add(4, 5)
8 | 9
9 | """
10 | a + b
--------------------------------------------------------------------------------
/chapter30_testing/add_doctest_working.py:
--------------------------------------------------------------------------------
1 | # add_doctest.py
2 |
3 | def add(a: int, b: int) -> int:
4 | """
5 | >>> add(1, 2)
6 | 3
7 | >>> add(4, 5)
8 | 9
9 | """
10 | return a + b
--------------------------------------------------------------------------------
/chapter30_testing/add_test_in_code.py:
--------------------------------------------------------------------------------
1 | # add_test_in_code.py
2 |
3 | def add(a: int, b: int) -> int:
4 | """
5 | >>> add(1, 2)
6 | 3
7 | >>> add(4, 5)
8 | 9
9 | """
10 | return a + b
11 |
12 | if __name__ == '__main__':
13 | import doctest
14 | doctest.testmod(verbose=True)
--------------------------------------------------------------------------------
/chapter30_testing/doctest_external.py:
--------------------------------------------------------------------------------
1 | # doctest_external.py
2 |
3 | def add(a: int, b: int) -> int:
4 | return a + b
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_buzz_test/fizzbuzz.py:
--------------------------------------------------------------------------------
1 | def process(number):
2 | if number % 3 == 0:
3 | return 'Fizz'
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_buzz_test/test_fizzbuzz.py:
--------------------------------------------------------------------------------
1 | import fizzbuzz
2 | import unittest
3 |
4 | class TestFizzBuzz(unittest.TestCase):
5 |
6 | def test_multiple_of_three(self):
7 | self.assertEqual(fizzbuzz.process(6), 'Fizz')
8 |
9 | def test_multiple_of_five(self):
10 | self.assertEqual(fizzbuzz.process(20), 'Buzz')
11 |
12 | if __name__ == '__main__':
13 | unittest.main()
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_buzz_test_passing/fizzbuzz.py:
--------------------------------------------------------------------------------
1 | def process(number):
2 | if number % 3 == 0:
3 | return 'Fizz'
4 | elif number % 5 == 0:
5 | return 'Buzz'
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_buzz_test_passing/test_fizzbuzz.py:
--------------------------------------------------------------------------------
1 | import fizzbuzz
2 | import unittest
3 |
4 | class TestFizzBuzz(unittest.TestCase):
5 |
6 | def test_multiple_of_three(self):
7 | self.assertEqual(fizzbuzz.process(6), 'Fizz')
8 |
9 | def test_multiple_of_five(self):
10 | self.assertEqual(fizzbuzz.process(20), 'Buzz')
11 |
12 | if __name__ == '__main__':
13 | unittest.main()
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_final_test/fizzbuzz.py:
--------------------------------------------------------------------------------
1 | def process(number):
2 | if number % 3 == 0 and number % 5 == 0:
3 | return 'FizzBuzz'
4 | elif number % 3 == 0:
5 | return 'Fizz'
6 | elif number % 5 == 0:
7 | return 'Buzz'
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_final_test/test_fizzbuzz.py:
--------------------------------------------------------------------------------
1 | import fizzbuzz
2 | import unittest
3 |
4 | class TestFizzBuzz(unittest.TestCase):
5 |
6 | def test_multiple_of_three(self):
7 | self.assertEqual(fizzbuzz.process(6), 'Fizz')
8 |
9 | def test_multiple_of_five(self):
10 | self.assertEqual(fizzbuzz.process(20), 'Buzz')
11 |
12 | def test_fizzbuzz(self):
13 | self.assertEqual(fizzbuzz.process(15), 'FizzBuzz')
14 |
15 | def test_regular_numbers(self):
16 | self.assertEqual(fizzbuzz.process(2), 2)
17 | self.assertEqual(fizzbuzz.process(98), 98)
18 |
19 | if __name__ == '__main__':
20 | unittest.main()
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_final_test_passing/fizzbuzz.py:
--------------------------------------------------------------------------------
1 | def process(number):
2 | if number % 3 == 0 and number % 5 == 0:
3 | return 'FizzBuzz'
4 | elif number % 3 == 0:
5 | return 'Fizz'
6 | elif number % 5 == 0:
7 | return 'Buzz'
8 | else:
9 | return number
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_final_test_passing/test_fizzbuzz.py:
--------------------------------------------------------------------------------
1 | import fizzbuzz
2 | import unittest
3 |
4 | class TestFizzBuzz(unittest.TestCase):
5 |
6 | def test_multiple_of_three(self):
7 | self.assertEqual(fizzbuzz.process(6), 'Fizz')
8 |
9 | def test_multiple_of_five(self):
10 | self.assertEqual(fizzbuzz.process(20), 'Buzz')
11 |
12 | def test_fizzbuzz(self):
13 | self.assertEqual(fizzbuzz.process(15), 'FizzBuzz')
14 |
15 | def test_regular_numbers(self):
16 | self.assertEqual(fizzbuzz.process(2), 2)
17 | self.assertEqual(fizzbuzz.process(98), 98)
18 |
19 | if __name__ == '__main__':
20 | unittest.main()
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_fizz_test/fizzbuzz.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_fizz_test/test_fizzbuzz.py:
--------------------------------------------------------------------------------
1 | import fizzbuzz
2 | import unittest
3 |
4 | class TestFizzBuzz(unittest.TestCase):
5 |
6 | def test_multiple_of_three(self):
7 | self.assertEqual(fizzbuzz.process(6), 'Fizz')
8 |
9 | if __name__ == '__main__':
10 | unittest.main()
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_fizz_test_passing/fizzbuzz.py:
--------------------------------------------------------------------------------
1 | def process(number):
2 | if number % 3 == 0:
3 | return 'Fizz'
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_fizz_test_passing/test_fizzbuzz.py:
--------------------------------------------------------------------------------
1 | import fizzbuzz
2 | import unittest
3 |
4 | class TestFizzBuzz(unittest.TestCase):
5 |
6 | def test_multiple_of_three(self):
7 | self.assertEqual(fizzbuzz.process(6), 'Fizz')
8 |
9 | if __name__ == '__main__':
10 | unittest.main()
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_fizzbuzz_test/fizzbuzz.py:
--------------------------------------------------------------------------------
1 | def process(number):
2 | if number % 3 == 0:
3 | return 'Fizz'
4 | elif number % 5 == 0:
5 | return 'Buzz'
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_fizzbuzz_test/test_fizzbuzz.py:
--------------------------------------------------------------------------------
1 | import fizzbuzz
2 | import unittest
3 |
4 | class TestFizzBuzz(unittest.TestCase):
5 |
6 | def test_multiple_of_three(self):
7 | self.assertEqual(fizzbuzz.process(6), 'Fizz')
8 |
9 | def test_multiple_of_five(self):
10 | self.assertEqual(fizzbuzz.process(20), 'Buzz')
11 |
12 | def test_fizzbuzz(self):
13 | self.assertEqual(fizzbuzz.process(15), 'FizzBuzz')
14 |
15 | if __name__ == '__main__':
16 | unittest.main()
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_fizzbuzz_test_passing/fizzbuzz.py:
--------------------------------------------------------------------------------
1 | def process(number):
2 | if number % 3 == 0 and number % 5 == 0:
3 | return 'FizzBuzz'
4 | elif number % 3 == 0:
5 | return 'Fizz'
6 | elif number % 5 == 0:
7 | return 'Buzz'
--------------------------------------------------------------------------------
/chapter30_testing/fizzbuzz_fizzbuzz_test_passing/test_fizzbuzz.py:
--------------------------------------------------------------------------------
1 | import fizzbuzz
2 | import unittest
3 |
4 | class TestFizzBuzz(unittest.TestCase):
5 |
6 | def test_multiple_of_three(self):
7 | self.assertEqual(fizzbuzz.process(6), 'Fizz')
8 |
9 | def test_multiple_of_five(self):
10 | self.assertEqual(fizzbuzz.process(20), 'Buzz')
11 |
12 | def test_fizzbuzz(self):
13 | self.assertEqual(fizzbuzz.process(15), 'FizzBuzz')
14 |
15 | if __name__ == '__main__':
16 | unittest.main()
--------------------------------------------------------------------------------
/chapter30_testing/test.txt:
--------------------------------------------------------------------------------
1 | The following are tests for doctest_external
2 |
3 | >>> from doctest_external import add
4 | >>> add(1, 2)
5 | 3
6 | >>> add(4, 5)
7 | 9
--------------------------------------------------------------------------------
/chapter31_jupyter/Hello World.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "This is an example of printing in Python: `print('Hello')`\n",
8 | "\n",
9 | "Code block:\n",
10 | "\n",
11 | "```python\n",
12 | "print('hello world')\n",
13 | "```"
14 | ]
15 | },
16 | {
17 | "cell_type": "code",
18 | "execution_count": null,
19 | "metadata": {},
20 | "outputs": [],
21 | "source": []
22 | }
23 | ],
24 | "metadata": {
25 | "kernelspec": {
26 | "display_name": "Python 3",
27 | "language": "python",
28 | "name": "python3"
29 | },
30 | "language_info": {
31 | "codemirror_mode": {
32 | "name": "ipython",
33 | "version": 3
34 | },
35 | "file_extension": ".py",
36 | "mimetype": "text/x-python",
37 | "name": "python",
38 | "nbconvert_exporter": "python",
39 | "pygments_lexer": "ipython3",
40 | "version": "3.6.4"
41 | }
42 | },
43 | "nbformat": 4,
44 | "nbformat_minor": 2
45 | }
46 |
--------------------------------------------------------------------------------
/chapter32_argparse/file_parser.py:
--------------------------------------------------------------------------------
1 | # file_parser.py
2 |
3 | import argparse
4 |
5 | def file_parser(input_file, output_file=''):
6 | print(f'Processing {input_file}')
7 | print('Finished processing')
8 | if output_file:
9 | print(f'Creating {output_file}')
10 |
11 | def main():
12 | parser = argparse.ArgumentParser('File parser')
13 | parser.add_argument('--infile', help='Input file')
14 | parser.add_argument('--out', help='Output file')
15 | args = parser.parse_args()
16 | if args.infile:
17 | file_parser(args.infile, args.out)
18 |
19 | if __name__ == '__main__':
20 | main()
21 |
--------------------------------------------------------------------------------
/chapter32_argparse/file_parser_aliases.py:
--------------------------------------------------------------------------------
1 | # file_parser_aliases.py
2 |
3 | import argparse
4 |
5 | def file_parser(input_file, output_file=''):
6 | print(f'Processing {input_file}')
7 | print('Finished processing')
8 | if output_file:
9 | print(f'Creating {output_file}')
10 |
11 | def main():
12 | parser = argparse.ArgumentParser('File parser',
13 | description='PyParse - The File Processor',
14 | epilog='Thank you for choosing PyParse!',
15 | add_help=False)
16 | parser.add_argument('-i', '--infile', help='Input file for conversion')
17 | parser.add_argument('-o', '--out', help='Converted output file')
18 | args = parser.parse_args()
19 | if args.infile:
20 | file_parser(args.infile, args.out)
21 |
22 | if __name__ == '__main__':
23 | main()
--------------------------------------------------------------------------------
/chapter32_argparse/file_parser_aliases2.py:
--------------------------------------------------------------------------------
1 | # file_parser_aliases2.py
2 |
3 | import argparse
4 |
5 | def file_parser(input_file, output_file=''):
6 | print(f'Processing {input_file}')
7 | print('Finished processing')
8 | if output_file:
9 | print(f'Creating {output_file}')
10 |
11 | def main():
12 | parser = argparse.ArgumentParser('File parser',
13 | description='PyParse - The File Processor',
14 | epilog='Thank you for choosing PyParse!',
15 | add_help=False)
16 | parser.add_argument('-i', '--infile', help='Input file for conversion')
17 | parser.add_argument('-o', '--out', help='Converted output file')
18 | args = parser.parse_args()
19 | if args.infile:
20 | file_parser(args.infile, args.out)
21 |
22 | if __name__ == '__main__':
23 | main()
--------------------------------------------------------------------------------
/chapter32_argparse/file_parser_exclusive.py:
--------------------------------------------------------------------------------
1 | # file_parser_exclusive.py
2 |
3 | import argparse
4 |
5 | def file_parser(input_file, output_file=''):
6 | print(f'Processing {input_file}')
7 | print('Finished processing')
8 | if output_file:
9 | print(f'Creating {output_file}')
10 |
11 | def main():
12 | parser = argparse.ArgumentParser('File parser',
13 | description='PyParse - The File Processor',
14 | epilog='Thank you for choosing PyParse!',
15 | add_help=False)
16 | group = parser.add_mutually_exclusive_group()
17 | group.add_argument('-i', '--infile', help='Input file for conversion')
18 | group.add_argument('-o', '--out', help='Converted output file')
19 | args = parser.parse_args()
20 | if args.infile:
21 | file_parser(args.infile, args.out)
22 |
23 | if __name__ == '__main__':
24 | main()
--------------------------------------------------------------------------------
/chapter32_argparse/file_parser_no_help.py:
--------------------------------------------------------------------------------
1 | # file_parser_no_help.py
2 |
3 | import argparse
4 |
5 | def file_parser(input_file, output_file=''):
6 | print(f'Processing {input_file}')
7 | print('Finished processing')
8 | if output_file:
9 | print(f'Creating {output_file}')
10 |
11 | def main():
12 | parser = argparse.ArgumentParser('File parser',
13 | description='PyParse - The File Processor',
14 | epilog='Thank you for choosing PyParse!',
15 | add_help=False)
16 | parser.add_argument('--infile', help='Input file for conversion')
17 | parser.add_argument('--out', help='Converted output file')
18 | args = parser.parse_args()
19 | if args.infile:
20 | file_parser(args.infile, args.out)
21 |
22 | if __name__ == '__main__':
23 | main()
--------------------------------------------------------------------------------
/chapter32_argparse/file_parser_with_description.py:
--------------------------------------------------------------------------------
1 | # file_parser_with_description.py
2 |
3 | import argparse
4 |
5 | def file_parser(input_file, output_file=''):
6 | print(f'Processing {input_file}')
7 | print('Finished processing')
8 | if output_file:
9 | print(f'Creating {output_file}')
10 |
11 | def main():
12 | parser = argparse.ArgumentParser('File parser',
13 | description='PyParse - The File Processor',
14 | epilog='Thank you for choosing PyParse!')
15 | parser.add_argument('--infile', help='Input file for conversion')
16 | parser.add_argument('--out', help='Converted output file')
17 | args = parser.parse_args()
18 | if args.infile:
19 | file_parser(args.infile, args.out)
20 |
21 | if __name__ == '__main__':
22 | main()
--------------------------------------------------------------------------------
/chapter32_argparse/pysearch.py:
--------------------------------------------------------------------------------
1 | # pysearch.py
2 |
3 | import argparse
4 | import pathlib
5 |
6 |
7 | def search_folder(path, extension, file_size=None):
8 | """
9 | Search folder for files
10 | """
11 | folder = pathlib.Path(path)
12 | files = list(folder.rglob(f'*.{extension}'))
13 |
14 | if not files:
15 | print(f'No files found with {extension=}')
16 | return
17 |
18 | if file_size is not None:
19 | files = [f for f in files
20 | if f.stat().st_size > file_size]
21 |
22 | print(f'{len(files)} *.{extension} files found:')
23 | for file_path in files:
24 | print(file_path)
25 |
26 |
27 | def main():
28 | parser = argparse.ArgumentParser(
29 | 'PySearch',
30 | description='PySearch - The Python Powered File Searcher')
31 | parser.add_argument('-p', '--path',
32 | help='The path to search for files',
33 | required=True,
34 | dest='path')
35 | parser.add_argument('-e', '--ext',
36 | help='The extension to search for',
37 | required=True,
38 | dest='extension')
39 | parser.add_argument('-s', '--size',
40 | help='The file size to filter on in bytes',
41 | type=int,
42 | dest='size',
43 | default=None)
44 |
45 | args = parser.parse_args()
46 | search_folder(args.path, args.extension, args.size)
47 |
48 | if __name__ == '__main__':
49 | main()
--------------------------------------------------------------------------------
/chapter32_argparse/sys_args.py:
--------------------------------------------------------------------------------
1 | # sys_args.py
2 |
3 | import sys
4 |
5 | def main():
6 | print('You passed the following arguments:')
7 | print(sys.argv)
8 |
9 | if __name__ == '__main__':
10 | main()
--------------------------------------------------------------------------------
/chapter33_xml/appts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1181251680
5 | 040000008200E000
6 | 1181572063
7 |
8 |
9 | 1800
10 | Bring pizza home
11 |
12 |
13 | 1181253977
14 | sdlkjlkadhdakhdfd
15 | 1181588888
16 | TX
17 | Dallas
18 | 1800
19 | Bring pizza home
20 |
21 |
--------------------------------------------------------------------------------
/chapter33_xml/create_xml.py:
--------------------------------------------------------------------------------
1 | # create_xml.py
2 |
3 | import xml.etree.ElementTree as ET
4 |
5 |
6 | def create_xml(xml_file):
7 | root_element = ET.Element('note_taker')
8 | note_element = ET.Element('note')
9 | root_element.append(note_element)
10 |
11 | # add note sub-elements
12 | to_element = ET.SubElement(note_element, 'to')
13 | to_element.text = 'Mike'
14 | from_element = ET.SubElement(note_element, 'from')
15 | from_element.text = 'Nick'
16 | heading_element = ET.SubElement(note_element, 'heading')
17 | heading_element.text = 'Appointment'
18 | body_element = ET.SubElement(note_element, 'body')
19 | body_element.text = 'blah blah'
20 |
21 | tree = ET.ElementTree(root_element)
22 | with open(xml_file, "wb") as fh:
23 | tree.write(fh)
24 |
25 | if __name__ == '__main__':
26 | create_xml('test_create.xml')
--------------------------------------------------------------------------------
/chapter33_xml/edit_xml.py:
--------------------------------------------------------------------------------
1 | # edit_xml.py
2 |
3 |
4 | import xml.etree.cElementTree as ET
5 |
6 | def edit_xml(xml_file, output_file, from_person):
7 | tree = ET.ElementTree(file=xml_file)
8 | root = tree.getroot()
9 |
10 | for from_element in tree.iter(tag='from'):
11 | from_element.text = from_person
12 |
13 | tree = ET.ElementTree(root)
14 | with open(output_file, "wb") as f:
15 | tree.write(f)
16 |
17 | if __name__ == '__main__':
18 | edit_xml('note.xml', 'output.xml', 'Guido')
--------------------------------------------------------------------------------
/chapter33_xml/lxml_output.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Guido
4 | Nadine
5 | Reminder
6 | Don't forget the milk
7 | I'm new!
8 |
9 |
10 | Nicole
11 | Nadine
12 | Appointment
13 | Eye doctor
14 |
15 |
16 |
--------------------------------------------------------------------------------
/chapter33_xml/note.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mike
5 | Nadine
6 | Reminder
7 | Don't forget the milk
8 |
9 |
10 | Nicole
11 | Nadine
12 | Appointment
13 | Eye doctor
14 |
15 |
--------------------------------------------------------------------------------
/chapter33_xml/output.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Mike
4 | Guido
5 | Reminder
6 | Don't forget the milk
7 |
8 |
9 | Nicole
10 | Guido
11 | Appointment
12 | Eye doctor
13 |
14 |
--------------------------------------------------------------------------------
/chapter33_xml/parse_xml.py:
--------------------------------------------------------------------------------
1 | # parse_xml.py
2 |
3 | from xml.etree.ElementTree import ElementTree
4 |
5 | def parse_xml(xml_file):
6 | tree = ElementTree(file=xml_file)
7 | root_element = tree.getroot()
8 | print(f"The root element's tag is '{root_element.tag}'")
9 |
10 | for child_element in root_element:
11 | print(f'{child_element.tag=}, {child_element.text=}')
12 | if child_element.tag == 'note':
13 | for note_element in child_element:
14 | print(f'{note_element.tag=}, {note_element.text=}')
15 |
16 |
17 | if __name__ == '__main__':
18 | parse_xml('note.xml')
19 |
20 |
--------------------------------------------------------------------------------
/chapter33_xml/parse_xml_with_lxml.py:
--------------------------------------------------------------------------------
1 | # parse_xml_with_lxml.py
2 |
3 | from lxml import etree, objectify
4 |
5 | def parse_xml(xml_file):
6 | with open(xml_file) as f:
7 | xml = f.read()
8 |
9 | root = objectify.fromstring(xml)
10 |
11 | # Get an element
12 | to = root.note.to
13 | print(f'The {to=}')
14 |
15 | # print out all the note element's tags and text values
16 | for note in root.getchildren():
17 | for note_element in note.getchildren():
18 | print(f'{note_element.tag=}, {note_element.text=}')
19 | print()
20 |
21 | # modify a text value
22 | print(f'Original: {root.note.to=}')
23 | root.note.to = 'Guido'
24 | print(f'Modified: {root.note.to=}')
25 |
26 | # add a new element
27 | root.note.new_element = "I'm new!"
28 |
29 | # cleanup the XML before writing to disk
30 | objectify.deannotate(root)
31 | etree.cleanup_namespaces(root)
32 | obj_xml = etree.tostring(root, pretty_print=True)
33 |
34 | # save your xml
35 | with open("lxml_output.xml", "wb") as f:
36 | f.write(obj_xml)
37 |
38 | if __name__ == '__main__':
39 | parse_xml('note.xml')
--------------------------------------------------------------------------------
/chapter33_xml/test_create.xml:
--------------------------------------------------------------------------------
1 |
2 | MikeNickAppointmentblah blah
--------------------------------------------------------------------------------
/chapter33_xml/xml_tree_iterator.py:
--------------------------------------------------------------------------------
1 | # xml_tree_iterator.py
2 |
3 | from xml.etree.cElementTree import ElementTree
4 |
5 | def parse_xml(xml_file):
6 | tree = ElementTree(file=xml_file)
7 | print("Iterating using a tree iterator")
8 | for elem in tree.iter():
9 | print(f'{elem.tag=}, {elem.text=}')
10 |
11 |
12 | if __name__ == '__main__':
13 | parse_xml('note.xml')
14 |
--------------------------------------------------------------------------------
/chapter34_json/create_json_file.py:
--------------------------------------------------------------------------------
1 | # create_json_file.py
2 |
3 | import json
4 |
5 | def create_json_file(path, obj):
6 | with open(path, 'w') as fh:
7 | json.dump(obj, fh)
8 |
9 | if __name__ == '__main__':
10 | j = {"menu": {
11 | "id": "file",
12 | "value": "File",
13 | "popup": {
14 | "menuitem": [
15 | {"value": "New", "onclick": "CreateNewDoc()"},
16 | {"value": "Open", "onclick": "OpenDoc()"},
17 | {"value": "Close", "onclick": "CloseDoc()"}
18 | ]
19 | }
20 | }}
21 | create_json_file('test.json', j)
--------------------------------------------------------------------------------
/chapter34_json/example.json:
--------------------------------------------------------------------------------
1 | {"menu": {"id": "file", "value": "File", "popup": {"menuitem": [{"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"}]}}}
--------------------------------------------------------------------------------
/chapter34_json/load_json_file.py:
--------------------------------------------------------------------------------
1 | # load_json_file.py
2 |
3 | import json
4 |
5 | def load_json_file(path):
6 | with open(path) as fh:
7 | j_obj = json.load(fh)
8 | print(type(j_obj))
9 |
10 |
11 | if __name__ == '__main__':
12 | load_json_file('example.json')
--------------------------------------------------------------------------------
/chapter35_scrape_website/downloading_files.py:
--------------------------------------------------------------------------------
1 | import urllib.request
2 |
3 | def download_file(url):
4 | urllib.request.urlretrieve(url, "code.zip")
5 |
6 | def alternate_download(url):
7 | with urllib.request.urlopen(url) as response:
8 | data = response.read()
9 |
10 | with open("code2.zip", "wb") as code:
11 | code.write(data)
12 |
13 | if __name__ == '__main__':
14 | url = 'http://www.blog.pythonlibrary.org/wp-content/uploads/2012/06/wxDbViewer.zip'
15 | download_file(url)
--------------------------------------------------------------------------------
/chapter35_scrape_website/scraper.py:
--------------------------------------------------------------------------------
1 | # scraper.py
2 |
3 | import urllib.request
4 |
5 | from bs4 import BeautifulSoup
6 |
7 |
8 | def download_html(url):
9 | with urllib.request.urlopen(url) as response:
10 | html = response.read()
11 | return html
12 |
13 | def scraper(url):
14 | html = download_html(url)
15 | soup = BeautifulSoup(html, 'html.parser')
16 |
17 | title_links = soup.findAll('h1')
18 | articles = {}
19 | for link in title_links:
20 | if link.a:
21 | articles[link.a['href']] = link.text.strip()
22 |
23 | for article in articles:
24 | print(f'{articles[article]} - {article}')
25 |
26 |
27 | if __name__ == '__main__':
28 | url = 'https://www.blog.pythonlibrary.org'
29 | scraper(url)
--------------------------------------------------------------------------------
/chapter36_csv/books.csv:
--------------------------------------------------------------------------------
1 | book_title,author,publisher,pub_date,isbn
2 | Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
3 | wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
4 | Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081
--------------------------------------------------------------------------------
/chapter36_csv/csv_dict_reader.py:
--------------------------------------------------------------------------------
1 | # csv_dict_reader.py
2 |
3 | import csv
4 |
5 | def process_csv_dict_reader(file_obj):
6 | reader = csv.DictReader(file_obj)
7 | for line in reader:
8 | print(f'{line["book_title"]} by {line["author"]}')
9 |
10 | if __name__ == '__main__':
11 | with open('books.csv', newline='') as csvfile:
12 | process_csv_dict_reader(csvfile)
--------------------------------------------------------------------------------
/chapter36_csv/csv_dict_writer.py:
--------------------------------------------------------------------------------
1 | # csv_dict_writer.py
2 |
3 | import csv
4 |
5 | def csv_dict_writer(path, headers, data):
6 | with open(path, 'w', newline='') as csvfile:
7 | writer = csv.DictWriter(csvfile, delimiter=',',
8 | fieldnames=headers)
9 | writer.writeheader()
10 | for record in data:
11 | writer.writerow(record)
12 |
13 | if __name__ == '__main__':
14 | data = '''book_title,author,publisher,pub_date,isbn
15 | Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
16 | wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
17 | Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081'''
18 | records = []
19 | for line in data.splitlines():
20 | records.append(line.strip().split(','))
21 | headers = records.pop(0)
22 |
23 | list_of_dicts = []
24 | for row in records:
25 | my_dict = dict(zip(headers, row))
26 | list_of_dicts.append(my_dict)
27 |
28 | csv_dict_writer('output_dict.csv', headers, list_of_dicts)
--------------------------------------------------------------------------------
/chapter36_csv/csv_reader.py:
--------------------------------------------------------------------------------
1 | # csv_reader.py
2 |
3 | import csv
4 |
5 | def process_csv(path):
6 | with open(path, newline='') as csvfile:
7 | reader = csv.reader(csvfile)
8 | for row in reader:
9 | print(row)
10 |
11 | if __name__ == '__main__':
12 | process_csv('books.csv')
--------------------------------------------------------------------------------
/chapter36_csv/csv_reader_no_header.py:
--------------------------------------------------------------------------------
1 | # csv_reader_no_header.py
2 |
3 | import csv
4 |
5 | def process_csv(path):
6 | with open(path, newline='') as csvfile:
7 | reader = csv.reader(csvfile)
8 | # Skip the header
9 | next(reader, None)
10 | for row in reader:
11 | print(row)
12 |
13 | if __name__ == '__main__':
14 | process_csv('books.csv')
--------------------------------------------------------------------------------
/chapter36_csv/csv_writer.py:
--------------------------------------------------------------------------------
1 | # csv_writer.py
2 |
3 | import csv
4 |
5 | def csv_writer(path, data):
6 | with open(path, 'w', newline='') as csvfile:
7 | writer = csv.writer(csvfile, delimiter=',')
8 | for row in data:
9 | writer.writerow(row)
10 |
11 | if __name__ == '__main__':
12 | data = '''book_title,author,publisher,pub_date,isbn
13 | Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
14 | wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
15 | Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081'''
16 | records = []
17 | for line in data.splitlines():
18 | records.append(line.strip().split(','))
19 | csv_writer('output.csv', records)
--------------------------------------------------------------------------------
/chapter36_csv/csv_writer_rows.py:
--------------------------------------------------------------------------------
1 | # csv_writer_rows.py
2 |
3 | import csv
4 |
5 | def csv_writer(path, data):
6 | with open(path, 'w', newline='') as csvfile:
7 | writer = csv.writer(csvfile, delimiter=',')
8 | writer.writerows(data)
9 |
10 | if __name__ == '__main__':
11 | data = '''book_title,author,publisher,pub_date,isbn
12 | Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
13 | wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
14 | Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081'''
15 | records = []
16 | for line in data.splitlines():
17 | records.append(line.strip().split(','))
18 | csv_writer('output2.csv', records)
--------------------------------------------------------------------------------
/chapter36_csv/output.csv:
--------------------------------------------------------------------------------
1 | book_title,author,publisher,pub_date,isbn
2 | Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
3 | wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
4 | Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081
5 |
--------------------------------------------------------------------------------
/chapter36_csv/output_dict.csv:
--------------------------------------------------------------------------------
1 | book_title,author,publisher,pub_date,isbn
2 | Python 101,Mike Driscoll, Mike Driscoll,2020,123456789
3 | wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8
4 | Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081
5 |
--------------------------------------------------------------------------------
/chapter37_sqlite/add_data.py:
--------------------------------------------------------------------------------
1 | # add_data.py
2 |
3 | import sqlite3
4 |
5 | conn = sqlite3.connect("books.db")
6 | cursor = conn.cursor()
7 |
8 | # insert a record into the database
9 | cursor.execute("""INSERT INTO books
10 | VALUES ('Python 101', 'Mike Driscoll', '9/01/2020',
11 | 'Mouse Vs Python', 'epub')"""
12 | )
13 |
14 | # save data to database
15 | conn.commit()
16 |
17 | # insert multiple records using the more secure "?" method
18 | books = [('Python Interviews', 'Mike Driscoll',
19 | '2/1/2018', 'Packt Publishing', 'softcover'),
20 | ('Automate the Boring Stuff with Python',
21 | 'Al Sweigart', '', 'No Starch Press', 'PDF'),
22 | ('The Well-Grounded Python Developer',
23 | 'Doug Farrell', '2020', 'Manning', 'Kindle')]
24 | cursor.executemany("INSERT INTO books VALUES (?,?,?,?,?)", books)
25 | conn.commit()
--------------------------------------------------------------------------------
/chapter37_sqlite/create_database.py:
--------------------------------------------------------------------------------
1 | # create_database.py
2 |
3 | import sqlite3
4 |
5 | conn = sqlite3.connect("books.db")
6 |
7 | cursor = conn.cursor()
8 |
9 | # create a table
10 | cursor.execute("""CREATE TABLE books
11 | (title text, author text, release_date text,
12 | publisher text, book_type text)
13 | """)
--------------------------------------------------------------------------------
/chapter37_sqlite/delete_record.py:
--------------------------------------------------------------------------------
1 | # delete_record.py
2 |
3 | import sqlite3
4 |
5 | def delete_author(author):
6 | conn = sqlite3.connect("books.db")
7 | cursor = conn.cursor()
8 |
9 | sql = f"""
10 | DELETE FROM books
11 | WHERE author = '{author}'
12 | """
13 | cursor.execute(sql)
14 | conn.commit()
15 |
16 | if __name__ == '__main__':
17 | delete_author(author='Al Sweigart')
--------------------------------------------------------------------------------
/chapter37_sqlite/queries.py:
--------------------------------------------------------------------------------
1 | # queries.py
2 |
3 | import sqlite3
4 |
5 | def get_cursor():
6 | conn = sqlite3.connect("books.db")
7 | return conn.cursor()
8 |
9 | def select_all_records_by_author(cursor, author):
10 | sql = "SELECT * FROM books WHERE author=?"
11 | cursor.execute(sql, [author])
12 | print(cursor.fetchall()) # or use fetchone()
13 | print("\nHere is a listing of the rows in the table\n")
14 | for row in cursor.execute("SELECT rowid, * FROM books ORDER BY author"):
15 | print(row)
16 |
17 | def select_using_like(cursor, text):
18 | print("\nLIKE query results:\n")
19 | sql = f"""
20 | SELECT * FROM books
21 | WHERE title LIKE '{text}%'"""
22 | cursor.execute(sql)
23 | print(cursor.fetchall())
24 |
25 | if __name__ == '__main__':
26 | cursor = get_cursor()
27 | select_all_records_by_author(cursor,
28 | author='Mike Driscoll')
29 | select_using_like(cursor, text='Python')
--------------------------------------------------------------------------------
/chapter37_sqlite/update_record.py:
--------------------------------------------------------------------------------
1 | # update_record.py
2 |
3 | import sqlite3
4 |
5 |
6 | def update_author(old_name, new_name):
7 | conn = sqlite3.connect("books.db")
8 | cursor = conn.cursor()
9 | sql = f"""
10 | UPDATE books
11 | SET author = '{new_name}'
12 | WHERE author = '{old_name}'
13 | """
14 | cursor.execute(sql)
15 | conn.commit()
16 |
17 | if __name__ == '__main__':
18 | update_author(old_name='Mike Driscoll',
19 | new_name='Michael Driscoll')
--------------------------------------------------------------------------------
/chapter38_excel/books.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/driscollis/python101code/47fbb3b296d9a07409764ea83759b9afa03fece1/chapter38_excel/books.xlsx
--------------------------------------------------------------------------------
/chapter38_excel/creating_sheets.py:
--------------------------------------------------------------------------------
1 | # creating_sheets.py
2 |
3 | import openpyxl
4 |
5 | def create_worksheets(path):
6 | workbook = openpyxl.Workbook()
7 | print(workbook.sheetnames)
8 | # Add a new worksheet
9 | workbook.create_sheet()
10 | print(workbook.sheetnames)
11 | # Insert a worksheet
12 | workbook.create_sheet(index=1,
13 | title='Second sheet')
14 | print(workbook.sheetnames)
15 | workbook.save(path)
16 |
17 | if __name__ == '__main__':
18 | create_worksheets('sheets.xlsx')
--------------------------------------------------------------------------------
/chapter38_excel/delete_demo.py:
--------------------------------------------------------------------------------
1 | # delete_demo.py
2 |
3 | from openpyxl import Workbook
4 |
5 | def deleting_cols_rows(path):
6 | workbook = Workbook()
7 | sheet = workbook.active
8 | sheet['A1'] = 'Hello'
9 | sheet['B1'] = 'from'
10 | sheet['C1'] = 'OpenPyXL'
11 | sheet['A2'] = 'row 2'
12 | sheet['A3'] = 'row 3'
13 | sheet['A4'] = 'row 4'
14 | # Delete column A
15 | sheet.delete_cols(idx=1)
16 | # delete 2 rows starting on the second row
17 | sheet.delete_rows(idx=2, amount=2)
18 | workbook.save(path)
19 |
20 | if __name__ == '__main__':
21 | deleting_cols_rows('deleting.xlsx')
--------------------------------------------------------------------------------
/chapter38_excel/delete_sheets.py:
--------------------------------------------------------------------------------
1 | # delete_sheets.py
2 |
3 | import openpyxl
4 |
5 | def create_worksheets(path):
6 | workbook = openpyxl.Workbook()
7 | workbook.create_sheet()
8 | # Insert a worksheet
9 | workbook.create_sheet(index=1,
10 | title='Second sheet')
11 | print(workbook.sheetnames)
12 | del workbook['Second sheet']
13 | print(workbook.sheetnames)
14 | workbook.save(path)
15 |
16 | if __name__ == '__main__':
17 | create_worksheets('del_sheets.xlsx')
--------------------------------------------------------------------------------
/chapter38_excel/insert_demo.py:
--------------------------------------------------------------------------------
1 | # insert_demo.py
2 |
3 | from openpyxl import Workbook
4 |
5 | def inserting_cols_rows(path):
6 | workbook = Workbook()
7 | sheet = workbook.active
8 | sheet['A1'] = 'Hello'
9 | sheet['A2'] = 'from'
10 | sheet['A3'] = 'OpenPyXL'
11 | # insert a column before A
12 | sheet.insert_cols(idx=1)
13 | # insert 2 rows starting on the second row
14 | sheet.insert_rows(idx=2, amount=2)
15 | workbook.save(path)
16 |
17 | if __name__ == '__main__':
18 | inserting_cols_rows('inserting.xlsx')
--------------------------------------------------------------------------------
/chapter38_excel/iterating_over_cell_values.py:
--------------------------------------------------------------------------------
1 | # iterating_over_cell_values.py
2 |
3 | from openpyxl import load_workbook
4 |
5 | def iterating_over_values(path):
6 | workbook = load_workbook(filename=path)
7 | sheet = workbook.active
8 | for value in sheet.iter_rows(min_row=1, max_row=3,
9 | min_col=1, max_col=3,
10 | values_only=True):
11 | print(value)
12 |
13 | if __name__ == '__main__':
14 | iterating_over_values('books.xlsx')
--------------------------------------------------------------------------------
/chapter38_excel/iterating_over_cells.py:
--------------------------------------------------------------------------------
1 | # iterating_over_cells.py
2 |
3 | from openpyxl import load_workbook
4 |
5 | def iterating_range(path):
6 | workbook = load_workbook(filename=path)
7 | sheet = workbook.active
8 | for cell in sheet['A']:
9 | print(cell)
10 |
11 | if __name__ == '__main__':
12 | iterating_range('books.xlsx')
--------------------------------------------------------------------------------
/chapter38_excel/open_workbook.py:
--------------------------------------------------------------------------------
1 | # open_workbook.py
2 |
3 | from openpyxl import load_workbook
4 |
5 | def open_workbook(path):
6 | workbook = load_workbook(filename=path)
7 | print(f'Worksheet names: {workbook.sheetnames}')
8 | sheet = workbook.active
9 | print(sheet)
10 | print(f'The title of the Worksheet is: {sheet.title}')
11 |
12 | if __name__ == '__main__':
13 | open_workbook('books.xlsx')
--------------------------------------------------------------------------------
/chapter38_excel/remove_sheets.py:
--------------------------------------------------------------------------------
1 | # remove_sheets.py
2 |
3 | import openpyxl
4 |
5 | def create_worksheets(path):
6 | workbook = openpyxl.Workbook()
7 | sheet1 = workbook.create_sheet()
8 | # Insert a worksheet
9 | workbook.create_sheet(index=1,
10 | title='Second sheet')
11 | print(workbook.sheetnames)
12 | workbook.remove(workbook['Second sheet'])
13 | print(workbook.sheetnames)
14 | workbook.save(path)
15 |
16 | if __name__ == '__main__':
17 | create_worksheets('remove_sheets.xlsx')
--------------------------------------------------------------------------------
/chapter38_excel/workbook_cells.py:
--------------------------------------------------------------------------------
1 | # workbook_cells.py
2 |
3 | from openpyxl import load_workbook
4 |
5 | def get_cell_info(path):
6 | workbook = load_workbook(filename=path)
7 | sheet = workbook.active
8 | print(sheet)
9 | print(f'The title of the Worksheet is: {sheet.title}')
10 | print(f'The value of {sheet["A2"].value=}')
11 | print(f'The value of {sheet["A3"].value=}')
12 | cell = sheet['B3']
13 | print(f'{cell.value=}')
14 |
15 | def get_info_by_coord(path):
16 | workbook = load_workbook(filename=path)
17 | sheet = workbook.active
18 | cell = sheet['A2']
19 | print(f'Row {cell.row}, Col {cell.column} = {cell.value}')
20 | print(f'{cell.value=} is at {cell.coordinate=}')
21 |
22 | if __name__ == '__main__':
23 | get_cell_info('books.xlsx')
24 | get_info_by_coord('books.xlsx')
--------------------------------------------------------------------------------
/chapter38_excel/writing_hello.py:
--------------------------------------------------------------------------------
1 | # writing_hello.py
2 |
3 | from openpyxl import Workbook
4 |
5 | def create_workbook(path):
6 | workbook = Workbook()
7 | sheet = workbook.active
8 | sheet['A1'] = 'Hello'
9 | sheet['A2'] = 'from'
10 | sheet['A3'] = 'OpenPyXL'
11 | workbook.save(path)
12 |
13 | if __name__ == '__main__':
14 | create_workbook('hello.xlsx')
--------------------------------------------------------------------------------
/chapter39_reportlab/canvas_form.py:
--------------------------------------------------------------------------------
1 | # canvas_form.py
2 |
3 | from reportlab.lib.pagesizes import letter
4 | from reportlab.pdfgen import canvas
5 |
6 | def form(path):
7 | my_canvas = canvas.Canvas(path, pagesize=letter)
8 | my_canvas.setLineWidth(.3)
9 | my_canvas.setFont('Helvetica', 12)
10 | my_canvas.drawString(30, 750, 'OFFICIAL COMMUNIQUE')
11 | my_canvas.drawString(30, 735, 'OF ACME INDUSTRIES')
12 | my_canvas.drawString(500, 750, "12/12/2010")
13 | my_canvas.line(480, 747, 580, 747)
14 | my_canvas.drawString(275, 725, 'AMOUNT OWED:')
15 | my_canvas.drawString(500, 725, "$1,000.00")
16 | my_canvas.line(378, 723, 580, 723)
17 | my_canvas.drawString(30, 703, 'RECEIVED BY:')
18 | my_canvas.line(120, 700, 580, 700)
19 | my_canvas.drawString(120, 703, "JOHN DOE")
20 | my_canvas.save()
21 |
22 | if __name__ == '__main__':
23 | form('canvas_form.pdf')
--------------------------------------------------------------------------------
/chapter39_reportlab/drawing_polygons.py:
--------------------------------------------------------------------------------
1 | # drawing_polygons.py
2 |
3 | from reportlab.lib.pagesizes import letter
4 | from reportlab.pdfgen import canvas
5 |
6 | def draw_shapes():
7 | my_canvas = canvas.Canvas("drawing_polygons.pdf")
8 | my_canvas.setStrokeColorRGB(0.2, 0.5, 0.3)
9 | my_canvas.rect(10, 740, 100, 80, stroke=1, fill=0)
10 | my_canvas.ellipse(10, 680, 100, 630, stroke=1, fill=1)
11 | my_canvas.wedge(10, 600, 100, 550, 45, 90, stroke=1, fill=0)
12 | my_canvas.circle(300, 600, 50)
13 | my_canvas.save()
14 |
15 | if __name__ == '__main__':
16 | draw_shapes()
--------------------------------------------------------------------------------
/chapter39_reportlab/hello_platypus.py:
--------------------------------------------------------------------------------
1 | # hello_platypus.py
2 |
3 | from reportlab.lib.pagesizes import letter
4 | from reportlab.platypus import SimpleDocTemplate, Paragraph
5 | from reportlab.lib.styles import getSampleStyleSheet
6 |
7 | def hello():
8 | doc = SimpleDocTemplate("hello_platypus.pdf",
9 | pagesize=letter,
10 | rightMargin=72,
11 | leftMargin=72,
12 | topMargin=72,
13 | bottomMargin=18)
14 | styles = getSampleStyleSheet()
15 |
16 | flowables = []
17 |
18 | text = "Hello, I'm a Paragraph"
19 | para = Paragraph(text, style=styles["Normal"])
20 | flowables.append(para)
21 |
22 | doc.build(flowables)
23 |
24 | if __name__ == '__main__':
25 | hello()
--------------------------------------------------------------------------------
/chapter39_reportlab/hello_reportlab.py:
--------------------------------------------------------------------------------
1 | # hello_reportlab.py
2 |
3 | from reportlab.pdfgen import canvas
4 |
5 | my_canvas = canvas.Canvas("hello.pdf")
6 | my_canvas.drawString(100, 750, "Welcome to Reportlab!")
7 | my_canvas.save()
--------------------------------------------------------------------------------
/chapter39_reportlab/image_on_canvas.py:
--------------------------------------------------------------------------------
1 | # image_on_canvas.py
2 |
3 | from reportlab.lib.pagesizes import letter
4 | from reportlab.pdfgen import canvas
5 |
6 |
7 | def add_image(image_path):
8 | my_canvas = canvas.Canvas("canvas_image.pdf",
9 | pagesize=letter)
10 | my_canvas.drawImage(image_path, 30, 600,
11 | width=100, height=100)
12 | my_canvas.save()
13 |
14 | if __name__ == '__main__':
15 | image_path = 'snakehead.jpg'
16 | add_image(image_path)
--------------------------------------------------------------------------------
/chapter39_reportlab/platypus_multipage.py:
--------------------------------------------------------------------------------
1 | # platypus_multipage.py
2 |
3 | from reportlab.lib.pagesizes import letter
4 | from reportlab.lib.styles import getSampleStyleSheet
5 | from reportlab.lib.units import inch
6 | from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
7 |
8 |
9 | def create_document():
10 | doc = SimpleDocTemplate("platypus_multipage.pdf",
11 | pagesize=letter)
12 | styles = getSampleStyleSheet()
13 | flowables = []
14 | spacer = Spacer(1, 0.25*inch)
15 |
16 | # Create a lot of content to make a multipage PDF
17 | for i in range(50):
18 | text = 'Paragraph #{}'.format(i)
19 | para = Paragraph(text, styles["Normal"])
20 | flowables.append(para)
21 | flowables.append(spacer)
22 |
23 | doc.build(flowables)
24 |
25 | if __name__ == '__main__':
26 | create_document()
--------------------------------------------------------------------------------
/chapter39_reportlab/simple_table.py:
--------------------------------------------------------------------------------
1 | # simple_table.py
2 |
3 | from reportlab.lib.pagesizes import letter
4 | from reportlab.platypus import SimpleDocTemplate, Table
5 |
6 | def simple_table():
7 | doc = SimpleDocTemplate("simple_table.pdf", pagesize=letter)
8 | flowables = []
9 |
10 | data = [['col_{}'.format(x) for x in range(1, 6)],
11 | [str(x) for x in range(1, 6)],
12 | ['a', 'b', 'c', 'd', 'e']
13 | ]
14 |
15 | tbl = Table(data)
16 | flowables.append(tbl)
17 |
18 | doc.build(flowables)
19 |
20 | if __name__ == '__main__':
21 | simple_table()
--------------------------------------------------------------------------------
/chapter39_reportlab/simple_table_with_style.py:
--------------------------------------------------------------------------------
1 | # simple_table_with_style.py
2 |
3 | from reportlab.lib import colors
4 | from reportlab.lib.pagesizes import letter
5 | from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
6 |
7 | def simple_table_with_style():
8 | doc = SimpleDocTemplate("simple_table_with_style.pdf",
9 | pagesize=letter)
10 | flowables = []
11 |
12 | data = [['col_{}'.format(x) for x in range(1, 6)],
13 | [str(x) for x in range(1, 6)],
14 | ['a', 'b', 'c', 'd', 'e']
15 | ]
16 |
17 | tblstyle = TableStyle(
18 | [('BACKGROUND', (0, 0), (-1, 0), colors.red),
19 | ('TEXTCOLOR', (0, 1), (-1, 1), colors.blue)
20 | ])
21 |
22 | tbl = Table(data)
23 | tbl.setStyle(tblstyle)
24 | flowables.append(tbl)
25 |
26 | doc.build(flowables)
27 |
28 | if __name__ == '__main__':
29 | simple_table_with_style()
--------------------------------------------------------------------------------
/chapter39_reportlab/snakehead.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/driscollis/python101code/47fbb3b296d9a07409764ea83759b9afa03fece1/chapter39_reportlab/snakehead.jpg
--------------------------------------------------------------------------------
/chapter40_graphs/bar_chart.py:
--------------------------------------------------------------------------------
1 | # bar_chart.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | def bar_chart(numbers, labels, pos):
6 | plt.bar(pos, numbers, color='blue')
7 | plt.xticks(ticks=pos, labels=labels)
8 | plt.show()
9 |
10 | if __name__ == '__main__':
11 | numbers = [2, 1, 4, 6]
12 | labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
13 | pos = list(range(4))
14 | bar_chart(numbers, labels, pos)
--------------------------------------------------------------------------------
/chapter40_graphs/bar_chart.title.py:
--------------------------------------------------------------------------------
1 | # bar_chart_title.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | def bar_chart(numbers, labels, pos):
6 | plt.bar(pos, [4, 5, 6, 3], color='green')
7 | plt.bar(pos, numbers, color='blue')
8 | plt.xticks(ticks=pos, labels=labels)
9 | plt.title('Gas Used in Various Vehicles')
10 | plt.xlabel('Vehicle Types')
11 | plt.ylabel('Number of Vehicles')
12 | plt.show()
13 |
14 | if __name__ == '__main__':
15 | numbers = [2, 1, 4, 6]
16 | labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
17 | pos = list(range(4))
18 | bar_chart(numbers, labels, pos)
--------------------------------------------------------------------------------
/chapter40_graphs/bar_chart_labels.py:
--------------------------------------------------------------------------------
1 | # bar_chart_labels.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | def bar_chart(numbers, labels, pos):
6 | plt.bar(pos, numbers, color='blue')
7 | plt.xticks(ticks=pos, labels=labels)
8 | plt.xlabel('Vehicle Types')
9 | plt.ylabel('Number of Vehicles')
10 | plt.show()
11 |
12 | if __name__ == '__main__':
13 | numbers = [2, 1, 4, 6]
14 | labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
15 | pos = list(range(4))
16 | bar_chart(numbers, labels, pos)
--------------------------------------------------------------------------------
/chapter40_graphs/bar_chart_legend.py:
--------------------------------------------------------------------------------
1 | # bar_chart_legend.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | def bar_chart(numbers, labels, pos):
6 | plt.bar(pos, [4, 5, 6, 3], color='green')
7 | plt.bar(pos, numbers, color='blue')
8 | plt.xticks(ticks=pos, labels=labels)
9 | plt.xlabel('Vehicle Types')
10 | plt.ylabel('Number of Vehicles')
11 | plt.title('Gas Used in Various Vehicles')
12 | plt.legend(['First Label', 'Second Label'],
13 | loc='upper left')
14 | plt.show()
15 |
16 | if __name__ == '__main__':
17 | numbers = [2, 1, 4, 6]
18 | labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
19 | pos = list(range(4))
20 | bar_chart(numbers, labels, pos)
--------------------------------------------------------------------------------
/chapter40_graphs/bar_charth.py:
--------------------------------------------------------------------------------
1 | # bar_charth.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | def bar_charth(numbers, labels, pos):
6 | plt.barh(pos, numbers, color='blue')
7 | plt.yticks(ticks=pos, labels=labels)
8 | plt.show()
9 |
10 | if __name__ == '__main__':
11 | numbers = [2, 1, 4, 6]
12 | labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
13 | pos = list(range(4))
14 | bar_charth(numbers, labels, pos)
--------------------------------------------------------------------------------
/chapter40_graphs/line_plot.py:
--------------------------------------------------------------------------------
1 | # line_plot.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | def line_plot(numbers):
6 | plt.plot(numbers)
7 | plt.ylabel('Random numbers')
8 | plt.show()
9 |
10 | if __name__ == '__main__':
11 | numbers = [2, 4, 1, 6]
12 | line_plot(numbers)
--------------------------------------------------------------------------------
/chapter40_graphs/multiple_figures.py:
--------------------------------------------------------------------------------
1 | # multiple_figures.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | def line_plot(numbers, numbers2):
6 | first_plot = plt.figure(1)
7 | plt.plot(numbers)
8 |
9 | second_plot = plt.figure(2)
10 | plt.plot(numbers2)
11 | plt.show()
12 |
13 | if __name__ == '__main__':
14 | numbers = [2, 4, 1, 6]
15 | more_numbers = [5, 1, 10, 3]
16 | line_plot(numbers, more_numbers)
--------------------------------------------------------------------------------
/chapter40_graphs/multiple_plots.py:
--------------------------------------------------------------------------------
1 | # multiple_plots.py
2 |
3 | import matplotlib.pyplot as plt
4 | import numpy as np
5 |
6 | def multiple_plots():
7 | # Some example data to display
8 | x = np.linspace(0, 2 * np.pi, 400)
9 | y = np.sin(x ** 2)
10 |
11 | fig, axs = plt.subplots(2)
12 | fig.suptitle('Vertically stacked subplots')
13 | axs[0].plot(x, y)
14 | axs[1].plot(x, -y)
15 | plt.show()
16 |
17 | if __name__ == '__main__':
18 | multiple_plots()
--------------------------------------------------------------------------------
/chapter40_graphs/multiple_plots2.py:
--------------------------------------------------------------------------------
1 | # multiple_plots2.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | def multiple_plots():
6 | numbers = [2, 4, 1, 6]
7 | more_numbers = [5, 1, 10, 3]
8 | fig, axs = plt.subplots(2)
9 | fig.suptitle('Vertically stacked subplots')
10 | axs[0].plot(numbers)
11 | axs[1].plot(more_numbers)
12 | plt.show()
13 |
14 | if __name__ == '__main__':
15 | multiple_plots()
--------------------------------------------------------------------------------
/chapter40_graphs/pie_chart_fancy.py:
--------------------------------------------------------------------------------
1 | # pie_chart.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | def pie_chart():
6 | numbers = [40, 35, 15, 10]
7 | labels = ['Python', 'Ruby', 'C++', 'PHP']
8 | # Explode the first slice (Python)
9 | explode = (0.1, 0, 0, 0)
10 |
11 | fig1, ax1 = plt.subplots()
12 | ax1.pie(numbers, explode=explode, labels=labels,
13 | shadow=True, startangle=90,
14 | autopct='%1.1f%%')
15 | ax1.axis('equal')
16 | plt.show()
17 |
18 | if __name__ == '__main__':
19 | pie_chart()
--------------------------------------------------------------------------------
/chapter40_graphs/pie_chart_plain.py:
--------------------------------------------------------------------------------
1 | # pie_chart_plain.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | def pie_chart():
6 | numbers = [40, 35, 15, 10]
7 | labels = ['Python', 'Ruby', 'C++', 'PHP']
8 |
9 | fig1, ax1 = plt.subplots()
10 | ax1.pie(numbers, labels=labels)
11 | plt.show()
12 |
13 | if __name__ == '__main__':
14 | pie_chart()
--------------------------------------------------------------------------------
/chapter41_images/blur.py:
--------------------------------------------------------------------------------
1 | # blur.py
2 |
3 | from PIL import Image
4 | from PIL import ImageFilter
5 |
6 |
7 | def blur(path, modified_photo):
8 | image = Image.open(path)
9 | blurred_image = image.filter(ImageFilter.BLUR)
10 | blurred_image.save(modified_photo)
11 |
12 | if __name__ == '__main__':
13 | blur('butterfly.jpg', 'butterfly_blurred.jpg')
--------------------------------------------------------------------------------
/chapter41_images/border.py:
--------------------------------------------------------------------------------
1 | # border.py
2 |
3 | from PIL import Image, ImageOps
4 |
5 |
6 | def add_border(input_image, output_image, border):
7 | img = Image.open(input_image)
8 |
9 | if isinstance(border, int) or isinstance(border, tuple):
10 | bimg = ImageOps.expand(img, border=border)
11 | else:
12 | raise RuntimeError('Border is not an integer or tuple!')
13 |
14 | bimg.save(output_image)
15 |
16 | if __name__ == '__main__':
17 | in_img = 'butterfly_grey.jpg'
18 |
19 | add_border(in_img, output_image='butterfly_border.jpg',
20 | border=100)
21 |
--------------------------------------------------------------------------------
/chapter41_images/border2.py:
--------------------------------------------------------------------------------
1 | # border2.py
2 |
3 | from PIL import Image, ImageOps
4 |
5 |
6 | def add_border(input_image, output_image, border):
7 | img = Image.open(input_image)
8 |
9 | if isinstance(border, int) or isinstance(border, tuple):
10 | bimg = ImageOps.expand(img, border=border)
11 | else:
12 | raise RuntimeError('Border is not an integer or tuple!')
13 |
14 | bimg.save(output_image)
15 |
16 | if __name__ == '__main__':
17 | in_img = 'butterfly_grey.jpg'
18 |
19 | add_border(in_img, output_image='butterfly_border2.jpg',
20 | border=(10, 50))
21 |
--------------------------------------------------------------------------------
/chapter41_images/butterfly.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/driscollis/python101code/47fbb3b296d9a07409764ea83759b9afa03fece1/chapter41_images/butterfly.jpg
--------------------------------------------------------------------------------
/chapter41_images/butterfly_grey.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/driscollis/python101code/47fbb3b296d9a07409764ea83759b9afa03fece1/chapter41_images/butterfly_grey.jpg
--------------------------------------------------------------------------------
/chapter41_images/colored_border.py:
--------------------------------------------------------------------------------
1 | # colored_border.py
2 |
3 | from PIL import Image, ImageOps
4 |
5 | def add_border(input_image, output_image, border, color=0):
6 | img = Image.open(input_image)
7 |
8 | if isinstance(border, int) or isinstance(
9 | border, tuple):
10 | bimg = ImageOps.expand(img,
11 | border=border,
12 | fill=color)
13 | else:
14 | msg = 'Border is not an integer or tuple!'
15 | raise RuntimeError(msg)
16 |
17 | bimg.save(output_image)
18 |
19 | if __name__ == '__main__':
20 | in_img = 'butterfly_grey.jpg'
21 |
22 | add_border(in_img,
23 | output_image='butterfly_border_red.jpg',
24 | border=100,
25 | color='indianred')
--------------------------------------------------------------------------------
/chapter41_images/cropping.py:
--------------------------------------------------------------------------------
1 | # cropping.py
2 |
3 | from PIL import Image
4 |
5 |
6 | def crop_image(path, cropped_path):
7 | image = Image.open(path)
8 | cropped = image.crop((40, 590, 979, 1500))
9 | cropped.save(cropped_path)
10 |
11 | if __name__ == '__main__':
12 | crop_image('ducks.jpg', 'ducks_cropped.jpg')
--------------------------------------------------------------------------------
/chapter41_images/ducks.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/driscollis/python101code/47fbb3b296d9a07409764ea83759b9afa03fece1/chapter41_images/ducks.jpg
--------------------------------------------------------------------------------
/chapter41_images/get_histogram.py:
--------------------------------------------------------------------------------
1 | # get_histrogram.py
2 |
3 | import matplotlib.pyplot as plt
4 |
5 | from PIL import Image
6 |
7 |
8 | def get_image_histrogram(path):
9 | image = Image.open(path)
10 | histogram = image.histogram()
11 | plt.hist(histogram, bins=len(histogram))
12 | plt.xlabel('Histogram')
13 | plt.show()
14 |
15 | if __name__ == '__main__':
16 | get_image_histrogram('butterfly.jpg')
--------------------------------------------------------------------------------
/chapter41_images/get_image_info.py:
--------------------------------------------------------------------------------
1 | # get_image_info.py
2 |
3 | from PIL import Image
4 |
5 | def get_image_info(path):
6 | image = Image.open(path)
7 | print(f'This image is {image.width} x {image.height}')
8 | exif = image._getexif()
9 | print(exif)
10 |
11 | if __name__ == '__main__':
12 | get_image_info('ducks.jpg')
--------------------------------------------------------------------------------
/chapter41_images/jellyfish.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/driscollis/python101code/47fbb3b296d9a07409764ea83759b9afa03fece1/chapter41_images/jellyfish.jpg
--------------------------------------------------------------------------------
/chapter41_images/lizard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/driscollis/python101code/47fbb3b296d9a07409764ea83759b9afa03fece1/chapter41_images/lizard.jpg
--------------------------------------------------------------------------------
/chapter41_images/open_image.py:
--------------------------------------------------------------------------------
1 | # open_image.py
2 |
3 | from PIL import Image
4 |
5 | image = Image.open('jellyfish.jpg')
6 | image.show()
--------------------------------------------------------------------------------
/chapter41_images/resize_image.py:
--------------------------------------------------------------------------------
1 | # resize_image.py
2 |
3 | from PIL import Image
4 |
5 | def resize_image(input_image_path,
6 | output_image_path,
7 | size):
8 | original_image = Image.open(input_image_path)
9 | width, height = original_image.size
10 | print(f'The original image size is {width} wide x {height} '
11 | f'high')
12 |
13 | resized_image = original_image.resize(size)
14 | width, height = resized_image.size
15 | print(f'The resized image size is {width} wide x {height} '
16 | f'high')
17 | resized_image.show()
18 | resized_image.save(output_image_path)
19 |
20 | if __name__ == '__main__':
21 | resize_image(input_image_path='lizard.jpg',
22 | output_image_path='lizard_small.jpg',
23 | size=(800, 400))
--------------------------------------------------------------------------------
/chapter41_images/scale_image.py:
--------------------------------------------------------------------------------
1 | # scale_image.py
2 |
3 | from PIL import Image
4 |
5 | def scale_image(input_image_path,
6 | output_image_path,
7 | width=None,
8 | height=None
9 | ):
10 | original_image = Image.open(input_image_path)
11 | w, h = original_image.size
12 | print(f'The original image size is {w} wide x {h} '
13 | 'high')
14 |
15 | if width and height:
16 | max_size = (width, height)
17 | elif width:
18 | max_size = (width, h)
19 | elif height:
20 | max_size = (w, height)
21 | else:
22 | # No width or height specified
23 | raise ValueError('Width or height required!')
24 |
25 | original_image.thumbnail(max_size, Image.ANTIALIAS)
26 | original_image.save(output_image_path)
27 |
28 | scaled_image = Image.open(output_image_path)
29 | width, height = scaled_image.size
30 | print(f'The scaled image size is {width} wide x {height} '
31 | 'high')
32 |
33 |
34 | if __name__ == '__main__':
35 | scale_image(input_image_path='lizard.jpg',
36 | output_image_path='lizard_scaled.jpg',
37 | width=800)
--------------------------------------------------------------------------------
/chapter41_images/sharpen.py:
--------------------------------------------------------------------------------
1 | # sharpen.py
2 |
3 | from PIL import Image
4 | from PIL import ImageFilter
5 |
6 |
7 | def sharpen(path, modified_photo):
8 | image = Image.open(path)
9 | sharpened_image = image.filter(ImageFilter.SHARPEN)
10 | sharpened_image.save(modified_photo)
11 |
12 | if __name__ == '__main__':
13 | sharpen('butterfly.jpg', 'butterfly_sharper.jpg')
--------------------------------------------------------------------------------
/chapter42_gui/button_events.py:
--------------------------------------------------------------------------------
1 | # button_events.py
2 |
3 | import wx
4 |
5 |
6 | class MyPanel(wx.Panel):
7 |
8 | def __init__(self, parent):
9 | super().__init__(parent)
10 |
11 | button = wx.Button(self, label='Press Me')
12 | button.Bind(wx.EVT_BUTTON, self.on_button1)
13 | button2 = wx.Button(self, label='Second button')
14 | button2.Bind(wx.EVT_BUTTON, self.on_button2)
15 |
16 | main_sizer = wx.BoxSizer(wx.HORIZONTAL)
17 | main_sizer.Add(button, proportion=1,
18 | flag=wx.ALL | wx.CENTER | wx.EXPAND,
19 | border=5)
20 | main_sizer.Add(button2, 0, wx.ALL, 5)
21 | self.SetSizer(main_sizer)
22 |
23 | def on_button1(self, event):
24 | print('You clicked the first button')
25 |
26 | def on_button2(self, event):
27 | print('You clicked the second button')
28 |
29 |
30 | class MyFrame(wx.Frame):
31 |
32 | def __init__(self):
33 | super().__init__(None, title='Hello World')
34 | panel = MyPanel(self)
35 | self.Show()
36 |
37 |
38 | if __name__ == '__main__':
39 | app = wx.App(redirect=False)
40 | frame = MyFrame()
41 | app.MainLoop()
--------------------------------------------------------------------------------
/chapter42_gui/hello_with_panel.py:
--------------------------------------------------------------------------------
1 | # hello_with_panel.py
2 |
3 | import wx
4 |
5 |
6 | class MyPanel(wx.Panel):
7 |
8 | def __init__(self, parent):
9 | super().__init__(parent)
10 | button = wx.Button(self, label='Press Me')
11 |
12 | class MyFrame(wx.Frame):
13 |
14 | def __init__(self):
15 | super().__init__(None, title='Hello World')
16 | panel = MyPanel(self)
17 | self.Show()
18 |
19 |
20 | if __name__ == '__main__':
21 | app = wx.App(redirect=False)
22 | frame = MyFrame()
23 | app.MainLoop()
--------------------------------------------------------------------------------
/chapter42_gui/hello_wx.py:
--------------------------------------------------------------------------------
1 | # hello_wx.py
2 |
3 | import wx
4 |
5 | app = wx.App(False)
6 | frame = wx.Frame(parent=None, title='Hello World')
7 | frame.Show()
8 | app.MainLoop()
9 |
--------------------------------------------------------------------------------
/chapter42_gui/hello_wx_class.py:
--------------------------------------------------------------------------------
1 | # hello_wx_class.py
2 |
3 | import wx
4 |
5 | class MyFrame(wx.Frame):
6 |
7 | def __init__(self):
8 | super().__init__(None, title='Hello World')
9 | self.Show()
10 |
11 | if __name__ == '__main__':
12 | app = wx.App(False)
13 | frame = MyFrame()
14 | frame.Show()
15 | app.MainLoop()
16 |
--------------------------------------------------------------------------------
/chapter42_gui/image_viewer.py:
--------------------------------------------------------------------------------
1 | # image_viewer.py
2 |
3 | import wx
4 |
5 | class ImagePanel(wx.Panel):
6 |
7 | def __init__(self, parent, image_size):
8 | super().__init__(parent)
9 |
10 | img = wx.Image(*image_size)
11 | self.image_ctrl = wx.StaticBitmap(self,
12 | bitmap=wx.Bitmap(img))
13 | browse_btn = wx.Button(self, label='Browse')
14 |
15 | main_sizer = wx.BoxSizer(wx.VERTICAL)
16 | main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
17 | main_sizer.Add(browse_btn)
18 | self.SetSizer(main_sizer)
19 | main_sizer.Fit(parent)
20 | self.Layout()
21 |
22 |
23 | class MainFrame(wx.Frame):
24 |
25 | def __init__(self):
26 | super().__init__(None, title='Image Viewer')
27 | panel = ImagePanel(self, image_size=(240,240))
28 | self.Show()
29 |
30 |
31 | if __name__ == '__main__':
32 | app = wx.App(redirect=False)
33 | frame = MainFrame()
34 | app.MainLoop()
--------------------------------------------------------------------------------
/chapter42_gui/image_viewer_working.py:
--------------------------------------------------------------------------------
1 | # image_viewer_working.py
2 |
3 | import wx
4 |
5 | class ImagePanel(wx.Panel):
6 |
7 | def __init__(self, parent, image_size):
8 | super().__init__(parent)
9 | self.max_size = 240
10 |
11 | img = wx.Image(*image_size)
12 | self.image_ctrl = wx.StaticBitmap(self,
13 | bitmap=wx.Bitmap(img))
14 |
15 | browse_btn = wx.Button(self, label='Browse')
16 | browse_btn.Bind(wx.EVT_BUTTON, self.on_browse)
17 |
18 | self.photo_txt = wx.TextCtrl(self, size=(200, -1))
19 |
20 | main_sizer = wx.BoxSizer(wx.VERTICAL)
21 | hsizer = wx.BoxSizer(wx.HORIZONTAL)
22 |
23 | main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
24 | hsizer.Add(browse_btn, 0, wx.ALL, 5)
25 | hsizer.Add(self.photo_txt, 0, wx.ALL, 5)
26 | main_sizer.Add(hsizer, 0, wx.ALL, 5)
27 |
28 | self.SetSizer(main_sizer)
29 | main_sizer.Fit(parent)
30 | self.Layout()
31 |
32 | def on_browse(self, event):
33 | """
34 | Browse for an image file
35 | @param event: The event object
36 | """
37 | wildcard = "JPEG files (*.jpg)|*.jpg"
38 | with wx.FileDialog(None, "Choose a file",
39 | wildcard=wildcard,
40 | style=wx.ID_OPEN) as dialog:
41 | if dialog.ShowModal() == wx.ID_OK:
42 | self.photo_txt.SetValue(dialog.GetPaths()[0])
43 | self.load_image()
44 |
45 | def load_image(self):
46 | """
47 | Load the image and display it to the user
48 | """
49 | filepath = self.photo_txt.GetValue()
50 | img = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
51 |
52 | # scale the image, preserving the aspect ratio
53 | W = img.GetWidth()
54 | H = img.GetHeight()
55 | if W > H:
56 | NewW = self.max_size
57 | NewH = self.max_size * H / W
58 | else:
59 | NewH = self.max_size
60 | NewW = self.max_size * W / H
61 | img = img.Scale(NewW,NewH)
62 |
63 | self.image_ctrl.SetBitmap(wx.Bitmap(img))
64 | self.Refresh()
65 |
66 |
67 | class MainFrame(wx.Frame):
68 |
69 | def __init__(self):
70 | super().__init__(None, title='Image Viewer')
71 | panel = ImagePanel(self, image_size=(240,240))
72 | self.Show()
73 |
74 |
75 | if __name__ == '__main__':
76 | app = wx.App(redirect=False)
77 | frame = MainFrame()
78 | app.MainLoop()
--------------------------------------------------------------------------------
/chapter42_gui/sizer_with_two_widgets.py:
--------------------------------------------------------------------------------
1 | # sizer_with_two_widgets.py
2 |
3 | import wx
4 |
5 |
6 | class MyPanel(wx.Panel):
7 |
8 | def __init__(self, parent):
9 | super().__init__(parent)
10 |
11 | button = wx.Button(self, label='Press Me')
12 | button2 = wx.Button(self, label='Second button')
13 |
14 | main_sizer = wx.BoxSizer(wx.HORIZONTAL)
15 | main_sizer.Add(button, proportion=1,
16 | flag=wx.ALL | wx.CENTER | wx.EXPAND,
17 | border=5)
18 | main_sizer.Add(button2, 0, wx.ALL, 5)
19 | self.SetSizer(main_sizer)
20 |
21 |
22 | class MyFrame(wx.Frame):
23 |
24 | def __init__(self):
25 | super().__init__(None, title='Hello World')
26 | panel = MyPanel(self)
27 | self.Show()
28 |
29 |
30 | if __name__ == '__main__':
31 | app = wx.App(redirect=False)
32 | frame = MyFrame()
33 | app.MainLoop()
--------------------------------------------------------------------------------
/chapter42_gui/stacked_buttons.py:
--------------------------------------------------------------------------------
1 | # stacked_buttons.py
2 |
3 | import wx
4 |
5 |
6 | class MyPanel(wx.Panel):
7 |
8 | def __init__(self, parent):
9 | super().__init__(parent)
10 | button = wx.Button(self, label='Press Me')
11 | button2 = wx.Button(self, label='Press Me too')
12 | button3 = wx.Button(self, label='Another button')
13 |
14 | class MyFrame(wx.Frame):
15 |
16 | def __init__(self):
17 | super().__init__(None, title='Hello World')
18 | panel = MyPanel(self)
19 | self.Show()
20 |
21 |
22 | if __name__ == '__main__':
23 | app = wx.App(redirect=False)
24 | frame = MyFrame()
25 | app.MainLoop()
--------------------------------------------------------------------------------
/chapter43_packages/arithmetic/__init__.py:
--------------------------------------------------------------------------------
1 | # __init__.py
2 | from . import add
--------------------------------------------------------------------------------
/chapter43_packages/arithmetic/add.py:
--------------------------------------------------------------------------------
1 | # add.py
2 |
3 | def add(x, y):
4 | return x + y
--------------------------------------------------------------------------------
/chapter43_packages/arithmetic/divide.py:
--------------------------------------------------------------------------------
1 | # divide.py
2 |
3 | def divide(x, y):
4 | return x / y
--------------------------------------------------------------------------------
/chapter43_packages/arithmetic/multiply.py:
--------------------------------------------------------------------------------
1 | # multiply.py
2 |
3 | def multiply(x, y):
4 | return x * y
--------------------------------------------------------------------------------
/chapter43_packages/arithmetic/subtract.py:
--------------------------------------------------------------------------------
1 | # subtract.py
2 |
3 | def subtract(x, y):
4 | return x - y
--------------------------------------------------------------------------------
/chapter43_packages/module/arithmetic.py:
--------------------------------------------------------------------------------
1 | # arithmetic.py
2 |
3 | def add(x, y):
4 | return x + y
5 |
6 | def divide(x, y):
7 | return x / y
8 |
9 | def multiply(x, y):
10 | return x * y
11 |
12 | def subtract(x, y):
13 | return x - y
14 |
--------------------------------------------------------------------------------
/chapter43_packages/module/test_arithmetic.py:
--------------------------------------------------------------------------------
1 | # test_arithmetic.py
2 |
3 | import arithmetic
4 | import unittest
5 |
6 | class TestArithmetic(unittest.TestCase):
7 |
8 | def test_addition(self):
9 | self.assertEqual(arithmetic.add(1, 2), 3)
10 |
11 | def test_subtraction(self):
12 | self.assertEqual(arithmetic.subtract(2, 1), 1)
13 |
14 | def test_multiplication(self):
15 | self.assertEqual(arithmetic.multiply(5, 5), 25)
16 |
17 | def test_division(self):
18 | self.assertEqual(arithmetic.divide(8, 2), 4)
19 |
20 |
21 | if __name__ == '__main__':
22 | unittest.main()
--------------------------------------------------------------------------------
/chapter43_packages/my_package/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
--------------------------------------------------------------------------------
/chapter43_packages/my_package/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/driscollis/python101code/47fbb3b296d9a07409764ea83759b9afa03fece1/chapter43_packages/my_package/README.md
--------------------------------------------------------------------------------
/chapter43_packages/my_package/arithmetic/__init__.py:
--------------------------------------------------------------------------------
1 | # __init__.py
2 | from . import add
--------------------------------------------------------------------------------
/chapter43_packages/my_package/arithmetic/add.py:
--------------------------------------------------------------------------------
1 | # add.py
2 |
3 | def add(x, y):
4 | return x + y
--------------------------------------------------------------------------------
/chapter43_packages/my_package/arithmetic/divide.py:
--------------------------------------------------------------------------------
1 | # divide.py
2 |
3 | def divide(x, y):
4 | return x / y
--------------------------------------------------------------------------------
/chapter43_packages/my_package/arithmetic/multiply.py:
--------------------------------------------------------------------------------
1 | # multiply.py
2 |
3 | def multiply(x, y):
4 | return x * y
--------------------------------------------------------------------------------
/chapter43_packages/my_package/arithmetic/subtract.py:
--------------------------------------------------------------------------------
1 | # subtract.py
2 |
3 | def subtract(x, y):
4 | return x - y
--------------------------------------------------------------------------------
/chapter43_packages/my_package/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 |
3 | with open("README.md", "r") as fh:
4 | long_description = fh.read()
5 |
6 | setuptools.setup(
7 | name="arithmetic-YOUR-USERNAME-HERE", # Replace with your own username
8 | version="0.0.1",
9 | author="Mike Driscoll",
10 | author_email="driscoll@example.com",
11 | description="A simple arithmetic package",
12 | long_description=long_description,
13 | long_description_content_type="text/markdown",
14 | url="https://github.com/driscollis/arithmetic",
15 | packages=setuptools.find_packages(),
16 | classifiers=[
17 | "Programming Language :: Python :: 3",
18 | "License :: OSI Approved :: MIT License",
19 | "Operating System :: OS Independent",
20 | ],
21 | python_requires='>=3.6',
22 | )
--------------------------------------------------------------------------------
/chapter44_pyinstaller/image_viewer.py:
--------------------------------------------------------------------------------
1 | # image_viewer_working.py
2 |
3 | import wx
4 |
5 | class ImagePanel(wx.Panel):
6 |
7 | def __init__(self, parent, image_size):
8 | super().__init__(parent)
9 | self.max_size = 240
10 |
11 | img = wx.Image(*image_size)
12 | self.image_ctrl = wx.StaticBitmap(self,
13 | bitmap=wx.Bitmap(img))
14 |
15 | browse_btn = wx.Button(self, label='Browse')
16 | browse_btn.Bind(wx.EVT_BUTTON, self.on_browse)
17 |
18 | self.photo_txt = wx.TextCtrl(self, size=(200, -1))
19 |
20 | main_sizer = wx.BoxSizer(wx.VERTICAL)
21 | hsizer = wx.BoxSizer(wx.HORIZONTAL)
22 |
23 | main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
24 | hsizer.Add(browse_btn, 0, wx.ALL, 5)
25 | hsizer.Add(self.photo_txt, 0, wx.ALL, 5)
26 | main_sizer.Add(hsizer, 0, wx.ALL, 5)
27 |
28 | self.SetSizer(main_sizer)
29 | main_sizer.Fit(parent)
30 | self.Layout()
31 |
32 | def on_browse(self, event):
33 | """
34 | Browse for an image file
35 | @param event: The event object
36 | """
37 | wildcard = "JPEG files (*.jpg)|*.jpg"
38 | with wx.FileDialog(None, "Choose a file",
39 | wildcard=wildcard,
40 | style=wx.ID_OPEN) as dialog:
41 | if dialog.ShowModal() == wx.ID_OK:
42 | self.photo_txt.SetValue(dialog.GetPath())
43 | self.load_image()
44 |
45 | def load_image(self):
46 | """
47 | Load the image and display it to the user
48 | """
49 | filepath = self.photo_txt.GetValue()
50 | img = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
51 |
52 | # scale the image, preserving the aspect ratio
53 | W = img.GetWidth()
54 | H = img.GetHeight()
55 | if W > H:
56 | NewW = self.max_size
57 | NewH = self.max_size * H / W
58 | else:
59 | NewH = self.max_size
60 | NewW = self.max_size * W / H
61 | img = img.Scale(NewW,NewH)
62 |
63 | self.image_ctrl.SetBitmap(wx.Bitmap(img))
64 | self.Refresh()
65 |
66 |
67 | class MainFrame(wx.Frame):
68 |
69 | def __init__(self):
70 | super().__init__(None, title='Image Viewer')
71 | panel = ImagePanel(self, image_size=(240,240))
72 | self.Show()
73 |
74 |
75 | if __name__ == '__main__':
76 | app = wx.App(redirect=False)
77 | frame = MainFrame()
78 | app.MainLoop()
--------------------------------------------------------------------------------
/chapter44_pyinstaller/pysearch.py:
--------------------------------------------------------------------------------
1 | # pysearch.py
2 |
3 | import argparse
4 | import pathlib
5 |
6 |
7 | def search_folder(path, extension, file_size=None):
8 | """
9 | Search folder for files
10 | """
11 | folder = pathlib.Path(path)
12 | files = list(folder.rglob(f'*.{extension}'))
13 |
14 | if not files:
15 | print(f'No files found with {extension=}')
16 | return
17 |
18 | if file_size is not None:
19 | files = [f for f in files
20 | if f.stat().st_size > file_size]
21 |
22 | print(f'{len(files)} *.{extension} files found:')
23 | for file_path in files:
24 | print(file_path)
25 |
26 |
27 | def main():
28 | parser = argparse.ArgumentParser(
29 | 'PySearch',
30 | description='PySearch - The Python Powered File Searcher')
31 | parser.add_argument('-p', '--path',
32 | help='The path to search for files',
33 | required=True,
34 | dest='path')
35 | parser.add_argument('-e', '--ext',
36 | help='The extension to search for',
37 | required=True,
38 | dest='extension')
39 | parser.add_argument('-s', '--size',
40 | help='The file size to filter on in bytes',
41 | type=int,
42 | dest='size',
43 | default=None)
44 |
45 | args = parser.parse_args()
46 | search_folder(args.path, args.extension, args.size)
47 |
48 | if __name__ == '__main__':
49 | main()
--------------------------------------------------------------------------------
/chapter46_mac/image_viewer.py:
--------------------------------------------------------------------------------
1 | # image_viewer_working.py
2 |
3 | import wx
4 |
5 | class ImagePanel(wx.Panel):
6 |
7 | def __init__(self, parent, image_size):
8 | super().__init__(parent)
9 | self.max_size = 240
10 |
11 | img = wx.Image(*image_size)
12 | self.image_ctrl = wx.StaticBitmap(self,
13 | bitmap=wx.Bitmap(img))
14 |
15 | browse_btn = wx.Button(self, label='Browse')
16 | browse_btn.Bind(wx.EVT_BUTTON, self.on_browse)
17 |
18 | self.photo_txt = wx.TextCtrl(self, size=(200, -1))
19 |
20 | main_sizer = wx.BoxSizer(wx.VERTICAL)
21 | hsizer = wx.BoxSizer(wx.HORIZONTAL)
22 |
23 | main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
24 | hsizer.Add(browse_btn, 0, wx.ALL, 5)
25 | hsizer.Add(self.photo_txt, 0, wx.ALL, 5)
26 | main_sizer.Add(hsizer, 0, wx.ALL, 5)
27 |
28 | self.SetSizer(main_sizer)
29 | main_sizer.Fit(parent)
30 | self.Layout()
31 |
32 | def on_browse(self, event):
33 | """
34 | Browse for an image file
35 | @param event: The event object
36 | """
37 | wildcard = "JPEG files (*.jpg)|*.jpg"
38 | with wx.FileDialog(None, "Choose a file",
39 | wildcard=wildcard,
40 | style=wx.ID_OPEN) as dialog:
41 | if dialog.ShowModal() == wx.ID_OK:
42 | self.photo_txt.SetValue(dialog.GetPath())
43 | self.load_image()
44 |
45 | def load_image(self):
46 | """
47 | Load the image and display it to the user
48 | """
49 | filepath = self.photo_txt.GetValue()
50 | img = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
51 |
52 | # scale the image, preserving the aspect ratio
53 | W = img.GetWidth()
54 | H = img.GetHeight()
55 | if W > H:
56 | NewW = self.max_size
57 | NewH = self.max_size * H / W
58 | else:
59 | NewH = self.max_size
60 | NewW = self.max_size * W / H
61 | img = img.Scale(NewW,NewH)
62 |
63 | self.image_ctrl.SetBitmap(wx.Bitmap(img))
64 | self.Refresh()
65 |
66 |
67 | class MainFrame(wx.Frame):
68 |
69 | def __init__(self):
70 | super().__init__(None, title='Image Viewer')
71 | panel = ImagePanel(self, image_size=(240,240))
72 | self.Show()
73 |
74 |
75 | if __name__ == '__main__':
76 | app = wx.App(redirect=False)
77 | frame = MainFrame()
78 | app.MainLoop()
--------------------------------------------------------------------------------
/contributors.txt:
--------------------------------------------------------------------------------
1 | Mike Driscoll
2 |
--------------------------------------------------------------------------------