diff --git a/00_intro_00_lecture.ipynb b/00_intro_00_lecture.ipynb index e53b008..a0ea14b 100644 --- a/00_intro_00_lecture.ipynb +++ b/00_intro_00_lecture.ipynb @@ -1,5 +1,53 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A **video presentation** of the contents in this chapter is shown below. A playlist with *all* chapters as videos is linked [here](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChALCAgOCggIDRYNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxgVERUWFxcYExMYGBgVFRgWFRYWGBcVGxIaEhMXFRoYGBISFRcVFRUVFRUVFRUVGBUSFxIVFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAgIDAQEAAAAAAAAAAAAABgcFCAIDBAEJ/8QAURAAAQQBAgMBCQgRAgUEAgMAAQACAwQRBRIGEyExBxQYIjJBVZTVCBUXUVJhk9QjMzVCU1RxcnN0dYGSsbKz05G0FiQ2YrU0gqGiY3YlQ0X/xAAcAQEAAgMBAQEAAAAAAAAAAAAAAgQBAwUHBgj/xAA9EQABAwIDBQUGBAYBBQEAAAABAAIRAyEEEjEFQVFhcRMVU4GRBiIyocHwFjRysRQ1QlLR4fEjM0NigpL/2gAMAwEAAhEDEQA/ANMkREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXF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hodQ0EBkkco21dQ8qJ4e0HOodmWhZBgrB0X6DItAPDV4q9H8P+q6j7RTw1eKvR/D/quo+0VhZW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/682q/aJ/0Mn9DloT4avFXo/h/1XUfaK4WPdo8UvY9hoaBh7XNOKuo5w4EHGdR7eqItaURERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERf/2Q==\n", + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo(\"YTU8jaG27Xk\", width=\"60%\")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -113,7 +161,7 @@ "cell_type": "markdown", "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "slide" } }, "source": [ @@ -307,7 +355,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "slideshow": { "slide_type": "slide" @@ -339,7 +387,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "skip" @@ -350,7 +398,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Python 3.7.6\n" + "Python 3.7.4\n" ] } ], @@ -483,7 +531,7 @@ "cell_type": "markdown", "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "slide" } }, "source": [ @@ -651,7 +699,7 @@ "cell_type": "markdown", "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "source": [ @@ -831,13 +879,13 @@ "**Part B: Managing Data and Memory**\n", "\n", "- How is data stored in memory?\n", - " - *Chapter 5*: [Bits & Numbers](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb)\n", - " - *Chapter 6*: [Bytes & Text](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb)\n", + " - *Chapter 5*: [Numbers & Bits](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb)\n", + " - *Chapter 6*: [Text & Bytes](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb)\n", " - *Chapter 7*: [Sequential Data](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb)\n", - " - *Chapter 8*: [Mappings & Sets](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb)\n", - " - *Chapter 9*: Arrays & Dataframes\n", + " - *Chapter 8*: [Map, Filter, & Reduce](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_lecture.ipynb)\n", + " - *Chapter 9*: [Mappings & Sets](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb)\n", "- How can we create custom data types?\n", - " - *Chapter 10*: Object-Orientation" + " - *Chapter 10*: [Classes & Instances](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/10_classes_00_lecture.ipynb)" ] }, { @@ -864,7 +912,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "slideshow": { "slide_type": "skip" @@ -885,6 +933,64 @@ "source": [ "" ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "## Further Resources" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A video tutorial on how to use Jupyter Lab is shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChALCAgOCggIDRYNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxgVERUWFxcYExMYGBgVFRgWFRYWGBcVGxIaEhMXFRoYGBISFRcVFRUVFRUVFRUVGBUSFxIVFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAgIDAQEAAAAAAAAAAAAABgcFCAIDBAEJ/8QAURAAAQQBAgMBCQgRAgUEAgMAAQACAwQRBRIGEyExBxQYIjJBVZTVCBUXUVJhk9QjMzVCU1RxcnN0dYGSsbKz05G0FiQ2YrU0gqGiY3YlQ0X/xAAcAQEAAgMBAQEAAAAAAAAAAAAAAgQBAwUHBgj/xAA9EQABAwIDBQUGBAYBBQEAAAABAAIRAyEEEjEFQVFhcRMVU4GRBiIyocHwFjRysRQ1QlLR4fEjM0NigpL/2gAMAwEAAhEDEQA/ANMkREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXF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hodQ0EBkkco21dQ8qJ4e0HOodmWhZBgrB0X6DItAPDV4q9H8P+q6j7RTw1eKvR/D/quo+0VhZW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/682q/aJ/0Mn9DloT4avFXo/h/1XUfaK4WPdo8UvY9hoaBh7XNOKuo5w4EHGdR7eqItaURERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERf/2Q==\n", + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "YouTubeVideo(\"5GGyKq1F_5c\", width=\"60%\")" + ] } ], "metadata": { @@ -903,7 +1009,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.4" }, "livereveal": { "auto_select": "code", diff --git a/00_intro_01_review.ipynb b/00_intro_01_review.ipynb index 325fc74..6542d71 100644 --- a/00_intro_01_review.ipynb +++ b/00_intro_01_review.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Chapter 0: Start up" + "# Chapter 0: Introduction" ] }, { @@ -18,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb) of the book. Then, work through the questions below." + "The questions below assume that you have read [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb) in the book.\n", + "\n", + "Be concise in your answers! Most questions can be answered in *one* sentence." ] }, { @@ -28,13 +30,6 @@ "### Essay Questions " ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Answer the following questions *briefly*!" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -46,7 +41,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -60,7 +55,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -74,7 +69,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -88,7 +83,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -116,7 +111,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -130,7 +125,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -144,7 +139,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -158,21 +153,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q9**: Python is *free software*. That means it does not cost anything." + "**Q9**: Python is **free software**. That means it does not cost anything." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -186,7 +181,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] } ], @@ -206,7 +201,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.4" }, "toc": { "base_numbering": 1, diff --git a/00_intro_02_exercises.ipynb b/00_intro_02_exercises.ipynb index b0f53db..db84599 100644 --- a/00_intro_02_exercises.ipynb +++ b/00_intro_02_exercises.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Chapter 0: Start up" + "# Chapter 0: Introduction" ] }, { @@ -18,7 +18,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb) of the book. Then, work through the exercises below." + "The exercises below assume that you have read [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_introduction_00_lecture.ipynb) in the book." ] }, { @@ -94,7 +94,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.4" }, "toc": { "base_numbering": 1, diff --git a/01_elements_00_lecture.ipynb b/01_elements_00_lecture.ipynb index 89beede..91c7411 100644 --- a/01_elements_00_lecture.ipynb +++ b/01_elements_00_lecture.ipynb @@ -1,5 +1,53 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A **video presentation** of the contents in this chapter is shown below. A playlist with *all* chapters as videos is linked [here](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChALCAgOCggIDRYNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxgVERUWFxcYExMYGBgVFRgWFRYWGBcVGxIaEhMXFRoYGBISFRcVFRUVFRUVFRUVGBUSFxIVFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAgIDAQEAAAAAAAAAAAAABgcFCAIDBAEJ/8QAURAAAQQBAgMBCQgRAgUEAgMAAQACAwQRBRIGEyExBxQYIjJBVZTVCBUXUVJhk9QjMzVCU1RxcnN0dYGSsbKz05G0FiQ2YrU0gqGiY3YlQ0X/xAAcAQEAAgMBAQEAAAAAAAAAAAAAAgQBAwUHBgj/xAA9EQABAwIDBQUGBAYBBQEAAAABAAIRAyEEEjEFQVFhcRMVU4GRBiIyocHwFjRysRQ1QlLR4fEjM0NigpL/2gAMAwEAAhEDEQA/ANMkREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXF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hodQ0EBkkco21dQ8qJ4e0HOodmWhZBgrB0X6DItAPDV4q9H8P+q6j7RTw1eKvR/D/quo+0VhZW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/682q/aJ/0Mn9DloT4avFXo/h/1XUfaK4WPdo8UvY9hoaBh7XNOKuo5w4EHGdR7eqItaURERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERf/2Q==\n", + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo(\"v0lk1Qfaw8Y\", width=\"60%\")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -55,7 +103,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "scrolled": true, "slideshow": { @@ -80,7 +128,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" @@ -93,7 +141,7 @@ "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -125,7 +173,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "slideshow": { "slide_type": "slide" @@ -157,7 +205,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "slideshow": { "slide_type": "fragment" @@ -170,7 +218,7 @@ "7.0" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -205,7 +253,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "slideshow": { "slide_type": "slide" @@ -218,7 +266,7 @@ "'I am feeling great :-)'" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -230,7 +278,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "slideshow": { "slide_type": "skip" @@ -254,7 +302,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "slideshow": { "slide_type": "fragment" @@ -288,7 +336,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "slideshow": { "slide_type": "skip" @@ -338,7 +386,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "slideshow": { "slide_type": "slide" @@ -351,7 +399,7 @@ "90" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -362,7 +410,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": { "slideshow": { "slide_type": "fragment" @@ -375,7 +423,7 @@ "8" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -397,7 +445,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": { "slideshow": { "slide_type": "fragment" @@ -410,7 +458,7 @@ "-1" ] }, - "execution_count": 11, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -432,7 +480,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": { "slideshow": { "slide_type": "fragment" @@ -445,7 +493,7 @@ "42" ] }, - "execution_count": 12, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -456,7 +504,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": { "slideshow": { "slide_type": "slide" @@ -469,7 +517,7 @@ "42.0" ] }, - "execution_count": 13, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -489,30 +537,6 @@ "The so-called **floor division operator** `//` always \"rounds\" to an integer and is thus also called **integer division operator**. It is an example of an arithmetic operator we commonly do not know from high school mathematics." ] }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "42" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "84 // 2" - ] - }, { "cell_type": "code", "execution_count": 15, @@ -533,6 +557,30 @@ "output_type": "execute_result" } ], + "source": [ + "84 // 2" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "42" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "85 // 2" ] @@ -550,7 +598,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": { "slideshow": { "slide_type": "fragment" @@ -563,7 +611,7 @@ "-43" ] }, - "execution_count": 16, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -585,7 +633,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": { "slideshow": { "slide_type": "slide" @@ -598,7 +646,7 @@ "1" ] }, - "execution_count": 17, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -624,7 +672,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "metadata": { "slideshow": { "slide_type": "fragment" @@ -637,7 +685,7 @@ "0" ] }, - "execution_count": 18, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -659,7 +707,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "metadata": { "slideshow": { "slide_type": "fragment" @@ -672,7 +720,7 @@ "9" ] }, - "execution_count": 19, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -683,7 +731,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "metadata": { "slideshow": { "slide_type": "fragment" @@ -696,7 +744,7 @@ "89" ] }, - "execution_count": 20, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -718,7 +766,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": { "slideshow": { "slide_type": "skip" @@ -731,7 +779,7 @@ "(4, 2)" ] }, - "execution_count": 21, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -753,7 +801,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": { "slideshow": { "slide_type": "slide" @@ -766,7 +814,7 @@ "8" ] }, - "execution_count": 22, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -786,41 +834,6 @@ "The standard [order of precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence) from mathematics applies (i.e., [PEMDAS](http://mathworld.wolfram.com/PEMDAS.html) rule) when several operators are combined." ] }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "18" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "3 ** 2 * 2 " - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Parentheses help avoid confusion and take the role of a **delimiter** here." - ] - }, { "cell_type": "code", "execution_count": 24, @@ -842,7 +855,18 @@ } ], "source": [ - "(3 ** 2) * 2" + "3 ** 2 * 2 " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Parentheses help avoid confusion and take the role of a **delimiter** here." ] }, { @@ -857,7 +881,7 @@ { "data": { "text/plain": [ - "81" + "18" ] }, "execution_count": 25, @@ -865,6 +889,30 @@ "output_type": "execute_result" } ], + "source": [ + "(3 ** 2) * 2" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "81" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "3 ** (2 * 2)" ] @@ -882,7 +930,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": { "slideshow": { "slide_type": "skip" @@ -895,7 +943,7 @@ "18" ] }, - "execution_count": 26, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -915,6 +963,101 @@ "There exist many non-mathematical operators that are introduced throughout this book, together with the concepts they implement. They often come in a form different from the unary and binary ones mentioned above." ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Operator Overloading" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Python **overloads** certain operators. For example, you may not only \"add\" numbers but also strings: This is called **string concatenation**." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "greeting = \"Hi \"\n", + "audience = \"class\"" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Hi class'" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "greeting + audience" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Duplicate strings using multiplication." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi '" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "10 * greeting" + ] + }, { "cell_type": "markdown", "metadata": { @@ -943,7 +1086,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 31, "metadata": { "slideshow": { "slide_type": "slide" @@ -980,7 +1123,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 32, "metadata": { "slideshow": { "slide_type": "slide" @@ -990,10 +1133,10 @@ { "data": { "text/plain": [ - "139627575613392" + "94551559411776" ] }, - "execution_count": 28, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -1004,7 +1147,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 33, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1014,10 +1157,10 @@ { "data": { "text/plain": [ - "140361812063056" + "139795753996464" ] }, - "execution_count": 29, + "execution_count": 33, "metadata": {}, "output_type": "execute_result" } @@ -1028,20 +1171,20 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 34, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ - "139627575358192" + "139795753985072" ] }, - "execution_count": 30, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } @@ -1065,7 +1208,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 35, "metadata": { "slideshow": { "slide_type": "slide" @@ -1078,7 +1221,7 @@ "True" ] }, - "execution_count": 31, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } @@ -1100,7 +1243,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 36, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1113,7 +1256,7 @@ "False" ] }, - "execution_count": 32, + "execution_count": 36, "metadata": {}, "output_type": "execute_result" } @@ -1135,7 +1278,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 37, "metadata": { "slideshow": { "slide_type": "skip" @@ -1148,7 +1291,7 @@ "True" ] }, - "execution_count": 33, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } @@ -1181,7 +1324,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 38, "metadata": { "slideshow": { "slide_type": "slide" @@ -1194,7 +1337,7 @@ "int" ] }, - "execution_count": 34, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } @@ -1205,7 +1348,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 39, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1218,7 +1361,7 @@ "float" ] }, - "execution_count": 35, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -1242,7 +1385,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 40, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1255,7 +1398,7 @@ "True" ] }, - "execution_count": 36, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" } @@ -1277,7 +1420,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 41, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1291,7 +1434,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'int' object has no attribute 'is_integer'" ] } @@ -1313,7 +1456,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 42, "metadata": { "slideshow": { "slide_type": "slide" @@ -1326,7 +1469,7 @@ "str" ] }, - "execution_count": 38, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" } @@ -1337,7 +1480,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 43, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1350,7 +1493,7 @@ "'python rocks'" ] }, - "execution_count": 39, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } @@ -1361,7 +1504,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 44, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1374,7 +1517,7 @@ "'PYTHON ROCKS'" ] }, - "execution_count": 40, + "execution_count": 44, "metadata": {}, "output_type": "execute_result" } @@ -1409,7 +1552,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 45, "metadata": { "slideshow": { "slide_type": "slide" @@ -1422,7 +1565,7 @@ "42" ] }, - "execution_count": 42, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } @@ -1433,7 +1576,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 46, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1446,7 +1589,7 @@ "42.0" ] }, - "execution_count": 43, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } @@ -1468,10 +1611,10 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 47, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1481,7 +1624,7 @@ "'Python rocks'" ] }, - "execution_count": 44, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -1540,7 +1683,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 48, "metadata": { "slideshow": { "slide_type": "slide" @@ -1549,10 +1692,10 @@ "outputs": [ { "ename": "SyntaxError", - "evalue": "invalid syntax (, line 1)", + "evalue": "invalid syntax (, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 3.99 $ + 10.40 $\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 3.99 $ + 10.40 $\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" ] } ], @@ -1573,7 +1716,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 49, "metadata": { "slideshow": { "slide_type": "slide" @@ -1582,10 +1725,10 @@ "outputs": [ { "ename": "SyntaxError", - "evalue": "invalid syntax (, line 1)", + "evalue": "invalid syntax (, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m for number in numbers\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m for number in numbers\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" ] } ], @@ -1607,7 +1750,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 50, "metadata": { "slideshow": { "slide_type": "slide" @@ -1616,10 +1759,10 @@ "outputs": [ { "ename": "IndentationError", - "evalue": "expected an indented block (, line 2)", + "evalue": "expected an indented block (, line 2)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m print(number)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mIndentationError\u001b[0m\u001b[0;31m:\u001b[0m expected an indented block\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m print(number)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mIndentationError\u001b[0m\u001b[0;31m:\u001b[0m expected an indented block\n" ] } ], @@ -1656,7 +1799,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 51, "metadata": { "slideshow": { "slide_type": "slide" @@ -1670,7 +1813,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;36m1\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;36m1\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero" ] } @@ -1705,7 +1848,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 52, "metadata": { "code_folding": [], "slideshow": { @@ -1727,10 +1870,10 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 53, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1740,7 +1883,7 @@ "3.5" ] }, - "execution_count": 50, + "execution_count": 53, "metadata": {}, "output_type": "execute_result" } @@ -1786,7 +1929,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 54, "metadata": { "slideshow": { "slide_type": "skip" @@ -1808,16 +1951,15 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 51, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from IPython.display import YouTubeVideo\n", "YouTubeVideo(\"Hwckt4J96dI\", width=\"60%\")" ] }, @@ -1829,12 +1971,12 @@ } }, "source": [ - "For example, while the above code to calculate the average of the even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` is correct, a Pythonista would rewrite it in a more \"Pythonic\" way and use the built-in [sum()](https://docs.python.org/3/library/functions.html#sum) and [len()](https://docs.python.org/3/library/functions.html#len) functions (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Built-in-Functions)) as well as a so-called **list comprehension** (cf., [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#List-Comprehensions)). Pythonic code runs faster in many cases and is less error-prone." + "For example, while the above code to calculate the average of the even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` is correct, a Pythonista would rewrite it in a more \"Pythonic\" way and use the built-in [sum()](https://docs.python.org/3/library/functions.html#sum) and [len()](https://docs.python.org/3/library/functions.html#len) functions (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Built-in-Functions)) as well as a so-called **list comprehension** (cf., [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_lecture.ipynb#List-Comprehensions)). Pythonic code runs faster in many cases and is less error-prone." ] }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 55, "metadata": { "slideshow": { "slide_type": "slide" @@ -1847,10 +1989,10 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 56, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -1860,10 +2002,10 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 57, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1873,7 +2015,7 @@ "[8, 12, 2, 6, 10, 4]" ] }, - "execution_count": 54, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } @@ -1884,10 +2026,10 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 58, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -1897,10 +2039,10 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 59, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1910,7 +2052,7 @@ "7.0" ] }, - "execution_count": 56, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" } @@ -1932,10 +2074,10 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 60, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -2060,7 +2202,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 61, "metadata": { "slideshow": { "slide_type": "slide" @@ -2084,7 +2226,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 62, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2097,7 +2239,7 @@ "20.0" ] }, - "execution_count": 59, + "execution_count": 62, "metadata": {}, "output_type": "execute_result" } @@ -2119,7 +2261,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 63, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2132,7 +2274,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 64, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2145,7 +2287,7 @@ "20" ] }, - "execution_count": 61, + "execution_count": 64, "metadata": {}, "output_type": "execute_result" } @@ -2167,7 +2309,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 65, "metadata": { "slideshow": { "slide_type": "slide" @@ -2180,10 +2322,10 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 66, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2193,7 +2335,7 @@ "80" ] }, - "execution_count": 63, + "execution_count": 66, "metadata": {}, "output_type": "execute_result" } @@ -2204,7 +2346,7 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 67, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2217,10 +2359,10 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 68, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2230,7 +2372,7 @@ "40" ] }, - "execution_count": 65, + "execution_count": 68, "metadata": {}, "output_type": "execute_result" } @@ -2241,7 +2383,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 69, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2254,10 +2396,10 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 70, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2267,7 +2409,7 @@ "42" ] }, - "execution_count": 67, + "execution_count": 70, "metadata": {}, "output_type": "execute_result" } @@ -2289,7 +2431,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 71, "metadata": { "slideshow": { "slide_type": "slide" @@ -2302,7 +2444,7 @@ "42" ] }, - "execution_count": 68, + "execution_count": 71, "metadata": {}, "output_type": "execute_result" } @@ -2313,7 +2455,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 72, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2337,7 +2479,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 73, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2351,7 +2493,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mvariable\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mvariable\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'variable' is not defined" ] } @@ -2373,7 +2515,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 74, "metadata": { "slideshow": { "slide_type": "skip" @@ -2386,7 +2528,7 @@ "'__main__'" ] }, - "execution_count": 71, + "execution_count": 74, "metadata": {}, "output_type": "execute_result" } @@ -2408,7 +2550,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 75, "metadata": { "slideshow": { "slide_type": "skip" @@ -2422,6 +2564,7 @@ " 'Out',\n", " 'YouTubeVideo',\n", " '_',\n", + " '_1',\n", " '_10',\n", " '_11',\n", " '_12',\n", @@ -2432,7 +2575,6 @@ " '_17',\n", " '_18',\n", " '_19',\n", - " '_2',\n", " '_20',\n", " '_21',\n", " '_22',\n", @@ -2440,36 +2582,38 @@ " '_24',\n", " '_25',\n", " '_26',\n", - " '_28',\n", + " '_27',\n", " '_29',\n", + " '_3',\n", " '_30',\n", - " '_31',\n", " '_32',\n", " '_33',\n", " '_34',\n", " '_35',\n", " '_36',\n", + " '_37',\n", " '_38',\n", " '_39',\n", - " '_4',\n", " '_40',\n", - " '_41',\n", " '_42',\n", " '_43',\n", " '_44',\n", + " '_45',\n", + " '_46',\n", + " '_47',\n", " '_5',\n", - " '_50',\n", - " '_51',\n", + " '_53',\n", " '_54',\n", - " '_56',\n", + " '_57',\n", " '_59',\n", - " '_61',\n", - " '_63',\n", - " '_65',\n", - " '_67',\n", + " '_6',\n", + " '_62',\n", + " '_64',\n", + " '_66',\n", " '_68',\n", + " '_70',\n", " '_71',\n", - " '_9',\n", + " '_74',\n", " '__',\n", " '___',\n", " '__builtin__',\n", @@ -2551,6 +2695,9 @@ " '_i70',\n", " '_i71',\n", " '_i72',\n", + " '_i73',\n", + " '_i74',\n", + " '_i75',\n", " '_i8',\n", " '_i9',\n", " '_ih',\n", @@ -2558,6 +2705,7 @@ " '_iii',\n", " '_oh',\n", " 'a',\n", + " 'audience',\n", " 'average',\n", " 'b',\n", " 'c',\n", @@ -2565,6 +2713,7 @@ " 'evens',\n", " 'exit',\n", " 'get_ipython',\n", + " 'greeting',\n", " 'number',\n", " 'numbers',\n", " 'quit',\n", @@ -2572,398 +2721,13 @@ " 'total']" ] }, - "execution_count": 72, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dir()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Who am I? And how many?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "It is *crucial* to understand that *several* variables may reference the *same* object in memory. Not having this in mind may lead to many hard to track down bugs.\n", - "\n", - "Let's make `b` reference whatever object `a` is referencing." - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "a = 42" - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "b = a" - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "42" - ] - }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "b" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "For \"simple\" types like `int` or `float` this never causes troubles.\n", - "\n", - "Let's \"change the value\" of `a`. To be precise, let's create a *new* `87` object and make `a` reference it." - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "a = 87" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "87" - ] - }, - "execution_count": 77, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "`b` \"is still the same\" as before. To be precise, `b` still references the *same object* as before." - ] - }, - { - "cell_type": "code", - "execution_count": 78, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "42" - ] - }, - "execution_count": 78, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "b" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "However, if a variable references an object of a more \"complex\" type (e.g., `list`), predicting the outcome of a code snippet may be unintuitive for a beginner." - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "x = [1, 2, 3]" - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "list" - ] - }, - "execution_count": 80, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(x)" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "y = x" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2, 3]" - ] - }, - "execution_count": 82, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Let's change the first element of `x`.\n", - "\n", - "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#The-list-Type) discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of references to other objects and treat the brackets `[]` attached to it as yet another operator, namely the **indexing operator**. So, `x[0]` instructs Python to first follow the reference from the global list of all names to the `x` object. Then, it follows the first reference it finds there to the `1` object we put in the list. The indexing operator must be an operator as we merely *read* the first element and do not change anything in memory permanently.\n", - "\n", - "Python **begins counting at 0**. This is not the case for many other languages, for example, [MATLAB](https://en.wikipedia.org/wiki/MATLAB), [R](https://en.wikipedia.org/wiki/R_%28programming_language%29), or [Stata](https://en.wikipedia.org/wiki/Stata). To understand why this makes sense, see this short [note](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) by one of the all-time greats in computer science, the late [Edsger Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra)." - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 83, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "To change the first entry in the list, we use the assignment statement `=` again. Here, this does *not* create a *new* variable, nor overwrite an existing one, but only changes the object referenced as the first element in `x`. As we only change parts of the `x` object, we say that we **mutate** its **state**. To use the bag analogy from above, we keep the same bag but \"flip\" some of the $0$s into $1$s and some of the $1$s into $0$s." - ] - }, - { - "cell_type": "code", - "execution_count": 84, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "x[0] = 99" - ] - }, - { - "cell_type": "code", - "execution_count": 85, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[99, 2, 3]" - ] - }, - "execution_count": 85, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The changes made to the object `x` is referencing can also be seen through the `y` variable!" - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[99, 2, 3]" - ] - }, - "execution_count": 86, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The difference in behavior illustrated in this sub-section has to do with the fact that `int` and `float` objects are **immutable** types while `list` objects are **mutable**.\n", - "\n", - "In the first case, an object cannot be changed \"in place\" once it is created in memory. When we assigned `87` to the already existing `a`, we did *not* change the $0$s and $1$s in the object `a` referenced before the assignment but created a new `int` object and made `a` reference it while the `b` variable is *not* affected.\n", - "\n", - "In the second case, `x[0] = 99` creates a *new* `int` object `99` and merely changes the first reference in the `x` list.\n", - "\n", - "In general, the assignment statement creates a new name and makes it reference whatever object is on the right-hand side *iff* the left-hand side is a *pure* name (i.e., it contains no operators like the indexing operator in the example). Otherwise, it *mutates* an already existing object. And, we must always expect that the latter may have more than one variable referencing it.\n", - "\n", - "Visualizing what is going on in memory with a tool like [PythonTutor](http://pythontutor.com/visualize.html#code=x%20%3D%20%5B1,%202,%203%5D%0Ay%20%3D%20x%0Ax%5B0%5D%20%3D%2099%0Aprint%28y%5B0%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) may be helpful for a beginner." + "dir()" ] }, { @@ -3018,7 +2782,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 76, "metadata": { "slideshow": { "slide_type": "slide" @@ -3031,10 +2795,10 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 77, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -3044,10 +2808,10 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 78, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -3057,10 +2821,10 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 79, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -3081,7 +2845,7 @@ }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 80, "metadata": { "slideshow": { "slide_type": "skip" @@ -3094,7 +2858,7 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": 81, "metadata": { "slideshow": { "slide_type": "skip" @@ -3107,7 +2871,7 @@ }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 82, "metadata": { "slideshow": { "slide_type": "skip" @@ -3120,7 +2884,7 @@ }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 83, "metadata": { "slideshow": { "slide_type": "skip" @@ -3129,10 +2893,10 @@ "outputs": [ { "ename": "SyntaxError", - "evalue": "can't assign to operator (, line 1)", + "evalue": "can't assign to operator (, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m address@work = \"WHU, Burgplatz 2, Vallendar\"\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m can't assign to operator\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m address@work = \"WHU, Burgplatz 2, Vallendar\"\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m can't assign to operator\n" ] } ], @@ -3153,7 +2917,7 @@ }, { "cell_type": "code", - "execution_count": 95, + "execution_count": 84, "metadata": { "slideshow": { "slide_type": "skip" @@ -3177,7 +2941,7 @@ }, { "cell_type": "code", - "execution_count": 96, + "execution_count": 85, "metadata": { "slideshow": { "slide_type": "skip" @@ -3190,7 +2954,7 @@ "'__main__'" ] }, - "execution_count": 96, + "execution_count": 85, "metadata": {}, "output_type": "execute_result" } @@ -3199,6 +2963,391 @@ "__name__" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Who am I? And how many?" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "It is *crucial* to understand that *several* variables may reference the *same* object in memory. Not having this in mind may lead to many hard to track down bugs.\n", + "\n", + "Let's make `b` reference whatever object `a` is referencing." + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "a = 42" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "b = a" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "42" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "For \"simple\" types like `int` or `float` this never causes troubles.\n", + "\n", + "Let's \"change the value\" of `a`. To be precise, let's create a *new* `87` object and make `a` reference it." + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "a = 87" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "87" + ] + }, + "execution_count": 90, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "`b` \"is still the same\" as before. To be precise, `b` still references the *same object* as before." + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "42" + ] + }, + "execution_count": 91, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "However, if a variable references an object of a more \"complex\" type (e.g., `list`), predicting the outcome of a code snippet may be unintuitive for a beginner." + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "x = [1, 2, 3]" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "list" + ] + }, + "execution_count": 93, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "y = x" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3]" + ] + }, + "execution_count": 95, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Let's change the first element of `x`.\n", + "\n", + "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#The-list-Type) discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of references to other objects and treat the brackets `[]` attached to it as yet another operator, namely the **indexing operator**. So, `x[0]` instructs Python to first follow the reference from the global list of all names to the `x` object. Then, it follows the first reference it finds there to the `1` object we put in the list. The indexing operator must be an operator as we merely *read* the first element and do not change anything in memory permanently.\n", + "\n", + "Python **begins counting at 0**. This is not the case for many other languages, for example, [MATLAB](https://en.wikipedia.org/wiki/MATLAB), [R](https://en.wikipedia.org/wiki/R_%28programming_language%29), or [Stata](https://en.wikipedia.org/wiki/Stata). To understand why this makes sense, see this short [note](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) by one of the all-time greats in computer science, the late [Edsger Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra)." + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "To change the first entry in the list, we use the assignment statement `=` again. Here, this does *not* create a *new* variable, nor overwrite an existing one, but only changes the object referenced as the first element in `x`. As we only change parts of the `x` object, we say that we **mutate** its **state**. To use the bag analogy from above, we keep the same bag but \"flip\" some of the $0$s into $1$s and some of the $1$s into $0$s." + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "x[0] = 99" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[99, 2, 3]" + ] + }, + "execution_count": 98, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The changes made to the object `x` is referencing can also be seen through the `y` variable!" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[99, 2, 3]" + ] + }, + "execution_count": 99, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The difference in behavior illustrated in this sub-section has to do with the fact that `int` and `float` objects are **immutable** types while `list` objects are **mutable**.\n", + "\n", + "In the first case, an object cannot be changed \"in place\" once it is created in memory. When we assigned `87` to the already existing `a`, we did *not* change the $0$s and $1$s in the object `a` referenced before the assignment but created a new `int` object and made `a` reference it while the `b` variable is *not* affected.\n", + "\n", + "In the second case, `x[0] = 99` creates a *new* `int` object `99` and merely changes the first reference in the `x` list.\n", + "\n", + "In general, the assignment statement creates a new name and makes it reference whatever object is on the right-hand side *iff* the left-hand side is a *pure* name (i.e., it contains no operators like the indexing operator in the example). Otherwise, it *mutates* an already existing object. And, we must always expect that the latter may have more than one variable referencing it.\n", + "\n", + "Visualizing what is going on in memory with a tool like [PythonTutor](http://pythontutor.com/visualize.html#code=x%20%3D%20%5B1,%202,%203%5D%0Ay%20%3D%20x%0Ax%5B0%5D%20%3D%2099%0Aprint%28y%5B0%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) may be helpful for a beginner." + ] + }, { "cell_type": "markdown", "metadata": { @@ -3229,7 +3378,7 @@ }, { "cell_type": "code", - "execution_count": 97, + "execution_count": 100, "metadata": { "slideshow": { "slide_type": "slide" @@ -3242,7 +3391,7 @@ "87" ] }, - "execution_count": 97, + "execution_count": 100, "metadata": {}, "output_type": "execute_result" } @@ -3253,7 +3402,7 @@ }, { "cell_type": "code", - "execution_count": 98, + "execution_count": 101, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3266,7 +3415,7 @@ "42" ] }, - "execution_count": 98, + "execution_count": 101, "metadata": {}, "output_type": "execute_result" } @@ -3288,7 +3437,7 @@ }, { "cell_type": "code", - "execution_count": 99, + "execution_count": 102, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3301,7 +3450,7 @@ "45" ] }, - "execution_count": 99, + "execution_count": 102, "metadata": {}, "output_type": "execute_result" } @@ -3323,7 +3472,7 @@ }, { "cell_type": "code", - "execution_count": 100, + "execution_count": 103, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3336,7 +3485,7 @@ "5" ] }, - "execution_count": 100, + "execution_count": 103, "metadata": {}, "output_type": "execute_result" } @@ -3358,7 +3507,7 @@ }, { "cell_type": "code", - "execution_count": 101, + "execution_count": 104, "metadata": { "slideshow": { "slide_type": "skip" @@ -3371,7 +3520,7 @@ "3" ] }, - "execution_count": 101, + "execution_count": 104, "metadata": {}, "output_type": "execute_result" } @@ -3393,7 +3542,7 @@ }, { "cell_type": "code", - "execution_count": 102, + "execution_count": 105, "metadata": { "slideshow": { "slide_type": "skip" @@ -3406,108 +3555,13 @@ "104" ] }, - "execution_count": 102, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum(x)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Operator Overloading" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Python **overloads** certain operators. For example, you may not only \"add\" numbers but also strings: This is called **string concatenation**." - ] - }, - { - "cell_type": "code", - "execution_count": 103, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "greeting = \"Hi \"\n", - "audience = \"class\"" - ] - }, - { - "cell_type": "code", - "execution_count": 104, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'Hi class'" - ] - }, - "execution_count": 104, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "greeting + audience" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Duplicate strings using multiplication." - ] - }, - { - "cell_type": "code", - "execution_count": 105, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi '" - ] - }, "execution_count": 105, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "10 * greeting" + "sum(x)" ] }, { @@ -3552,7 +3606,7 @@ "execution_count": 107, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -3812,7 +3866,7 @@ " " ], "text/plain": [ - "" + "" ] }, "execution_count": 112, @@ -3841,7 +3895,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.4" }, "livereveal": { "auto_select": "code", diff --git a/01_elements_01_review.ipynb b/01_elements_01_review.ipynb index c17b487..9c398f7 100644 --- a/01_elements_01_review.ipynb +++ b/01_elements_01_review.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", "# Chapter 1: Elements of a Program" ] }, @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb) of the book. Then, work through the questions below." + "The questions below assume that you have read [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb) in the book.\n", + "\n", + "Be concise in your answers! Most questions can be answered in *one* sentence." ] }, { @@ -29,13 +30,6 @@ "### Essay Questions " ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Answer the following questions *briefly*!" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -47,7 +41,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -61,7 +55,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -75,7 +69,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -89,7 +83,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -103,7 +97,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -117,7 +111,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -145,7 +139,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -159,7 +153,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -173,7 +167,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -187,7 +181,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] } ], @@ -207,7 +201,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.4" }, "toc": { "base_numbering": 1, diff --git a/01_elements_02_exercises.ipynb b/01_elements_02_exercises.ipynb index 3f5026a..fb7bc75 100644 --- a/01_elements_02_exercises.ipynb +++ b/01_elements_02_exercises.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", "# Chapter 1: Elements of a Program" ] }, @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb) of the book. Then, work through the exercises below. The `...` indicate where you need to fill in your answers. You should not need to create any additional code cells." + "The exercises below assume that you have read [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb) in the book.\n", + "\n", + "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." ] }, { @@ -68,7 +69,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " ..." + " < your answer >" ] }, { @@ -100,7 +101,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " ..." + " < your answer >" ] }, { @@ -283,7 +284,7 @@ "source": [ "`for`-loops are extremely versatile in Python. That is different from many other programming languages.\n", "\n", - "As shown in the first example in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb), we can create a `list` like `numbers` and loop over the numbers in it on a one-by-one basis." + "As shown in the first example in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Example:-Averaging-all-even-Numbers-in-a-List), we can create a `list` like `numbers` and loop over the numbers in it on a one-by-one basis." ] }, { @@ -444,7 +445,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.4" }, "toc": { "base_numbering": 1, diff --git a/02_functions_00_lecture.ipynb b/02_functions_00_lecture.ipynb index c25b194..8950027 100644 --- a/02_functions_00_lecture.ipynb +++ b/02_functions_00_lecture.ipynb @@ -1,5 +1,53 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A **video presentation** of the contents in this chapter is shown below. A playlist with *all* chapters as videos is linked [here](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChALCAgOCggIDRYNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxgVERUWFxcYExMYGBgVFRgWFRYWGBcVGxIaEhMXFRoYGBISFRcVFRUVFRUVFRUVGBUSFxIVFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAgIDAQEAAAAAAAAAAAAABgcFCAIDBAEJ/8QAURAAAQQBAgMBCQgRAgUEAgMAAQACAwQRBRIGEyExBxQYIjJBVZTVCBUXUVJhk9QjMzVCU1RxcnN0dYGSsbKz05G0FiQ2YrU0gqGiY3YlQ0X/xAAcAQEAAgMBAQEAAAAAAAAAAAAAAgQBAwUHBgj/xAA9EQABAwIDBQUGBAYBBQEAAAABAAIRAyEEEjEFQVFhcRMVU4GRBiIyocHwFjRysRQ1QlLR4fEjM0NigpL/2gAMAwEAAhEDEQA/ANMkREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXF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hodQ0EBkkco21dQ8qJ4e0HOodmWhZBgrB0X6DItAPDV4q9H8P+q6j7RTw1eKvR/D/quo+0VhZW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/682q/aJ/0Mn9DloT4avFXo/h/1XUfaK4WPdo8UvY9hoaBh7XNOKuo5w4EHGdR7eqItaURERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERf/2Q==\n", + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo(\"j4Xn8QFysmc\", width=\"60%\")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -50,7 +98,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "slideshow": { "slide_type": "slide" @@ -63,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" @@ -76,7 +124,7 @@ "78" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -87,7 +135,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "slideshow": { "slide_type": "skip" @@ -100,7 +148,7 @@ "12" ] }, - "execution_count": 3, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -124,7 +172,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "slideshow": { "slide_type": "slide" @@ -134,10 +182,10 @@ { "data": { "text/plain": [ - "140451963172416" + "139687475209792" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -148,7 +196,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "slideshow": { "slide_type": "skip" @@ -158,10 +206,10 @@ { "data": { "text/plain": [ - "140451963171376" + "139687475208752" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -183,7 +231,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "slideshow": { "slide_type": "fragment" @@ -196,7 +244,7 @@ "builtin_function_or_method" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -207,7 +255,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "slideshow": { "slide_type": "skip" @@ -220,7 +268,7 @@ "builtin_function_or_method" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -240,30 +288,6 @@ "Python's object-oriented nature allows us to have functions work with themselves. While seemingly not useful from a beginner's point of view, that enables a lot of powerful programming styles later on." ] }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "140451963170976" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "id(id)" - ] - }, { "cell_type": "code", "execution_count": 9, @@ -276,7 +300,7 @@ { "data": { "text/plain": [ - "builtin_function_or_method" + "139687475208352" ] }, "execution_count": 9, @@ -285,7 +309,31 @@ } ], "source": [ - "type(id)" + "id(id)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "type" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(type)" ] }, { @@ -305,7 +353,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": { "slideshow": { "slide_type": "slide" @@ -318,7 +366,7 @@ "True" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -329,7 +377,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": { "slideshow": { "slide_type": "skip" @@ -342,7 +390,7 @@ "True" ] }, - "execution_count": 11, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -364,7 +412,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": { "slideshow": { "slide_type": "fragment" @@ -377,7 +425,7 @@ "False" ] }, - "execution_count": 12, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -414,7 +462,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": { "slideshow": { "slide_type": "slide" @@ -427,7 +475,7 @@ "7" ] }, - "execution_count": 13, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -438,7 +486,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": { "slideshow": { "slide_type": "fragment" @@ -451,7 +499,7 @@ "7" ] }, - "execution_count": 14, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -473,7 +521,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": { "slideshow": { "slide_type": "slide" @@ -486,7 +534,7 @@ "7" ] }, - "execution_count": 15, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -497,7 +545,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": { "slideshow": { "slide_type": "fragment" @@ -510,7 +558,7 @@ "8" ] }, - "execution_count": 16, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -532,7 +580,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": { "slideshow": { "slide_type": "skip" @@ -545,7 +593,7 @@ "-7" ] }, - "execution_count": 17, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -567,7 +615,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "metadata": { "slideshow": { "slide_type": "skip" @@ -581,7 +629,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"seven\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"seven\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: 'seven'" ] } @@ -603,7 +651,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "metadata": { "slideshow": { "slide_type": "slide" @@ -616,7 +664,7 @@ "7.0" ] }, - "execution_count": 19, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -627,7 +675,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "metadata": { "slideshow": { "slide_type": "fragment" @@ -640,7 +688,7 @@ "'7'" ] }, - "execution_count": 20, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -662,7 +710,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": { "slideshow": { "slide_type": "slide" @@ -672,10 +720,10 @@ { "data": { "text/plain": [ - "93979750270848" + "94868913087680" ] }, - "execution_count": 21, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -686,7 +734,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": { "slideshow": { "slide_type": "skip" @@ -696,10 +744,10 @@ { "data": { "text/plain": [ - "93979750256352" + "94868913091584" ] }, - "execution_count": 22, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -721,7 +769,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, "metadata": { "slideshow": { "slide_type": "fragment" @@ -734,7 +782,7 @@ "type" ] }, - "execution_count": 23, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -745,7 +793,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 25, "metadata": { "slideshow": { "slide_type": "skip" @@ -758,7 +806,7 @@ "type" ] }, - "execution_count": 24, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -780,7 +828,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": { "slideshow": { "slide_type": "fragment" @@ -793,7 +841,7 @@ "True" ] }, - "execution_count": 25, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -804,7 +852,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": { "slideshow": { "slide_type": "skip" @@ -817,7 +865,7 @@ "True" ] }, - "execution_count": 26, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -875,7 +923,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 28, "metadata": { "slideshow": { "slide_type": "slide" @@ -890,7 +938,7 @@ " integers (list of int's): whole numbers to be averaged\n", "\n", " Returns:\n", - " float: average\n", + " average (float)\n", " \"\"\"\n", " evens = [n for n in integers if n % 2 == 0]\n", " average = sum(evens) / len(evens)\n", @@ -910,7 +958,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 29, "metadata": { "slideshow": { "slide_type": "slide" @@ -923,7 +971,7 @@ "" ] }, - "execution_count": 28, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -945,7 +993,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 30, "metadata": { "slideshow": { "slide_type": "fragment" @@ -955,10 +1003,10 @@ { "data": { "text/plain": [ - "140451741882272" + "139687370296784" ] }, - "execution_count": 29, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -969,7 +1017,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 31, "metadata": { "slideshow": { "slide_type": "fragment" @@ -982,7 +1030,7 @@ "function" ] }, - "execution_count": 30, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -1006,7 +1054,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 32, "metadata": { "slideshow": { "slide_type": "skip" @@ -1015,10 +1063,10 @@ "outputs": [ { "ename": "SyntaxError", - "evalue": "invalid syntax (, line 1)", + "evalue": "invalid syntax (, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m \u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m \u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" ] } ], @@ -1039,7 +1087,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 33, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1052,7 +1100,7 @@ "True" ] }, - "execution_count": 32, + "execution_count": 33, "metadata": {}, "output_type": "execute_result" } @@ -1076,7 +1124,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 34, "metadata": { "slideshow": { "slide_type": "skip" @@ -1096,7 +1144,7 @@ " integers (list of int's): whole numbers to be averaged\n", " \n", " Returns:\n", - " float: average\n", + " average (float)\n", "\n" ] } @@ -1118,7 +1166,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 35, "metadata": { "slideshow": { "slide_type": "skip" @@ -1136,8 +1184,8 @@ " integers (list of int's): whole numbers to be averaged\n", "\n", "Returns:\n", - " float: average\n", - "\u001b[0;31mFile:\u001b[0m ~/repos/intro-to-python/\n", + " average (float)\n", + "\u001b[0;31mFile:\u001b[0m ~/repos/intro-to-python/\n", "\u001b[0;31mType:\u001b[0m function\n" ] }, @@ -1162,7 +1210,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 36, "metadata": { "slideshow": { "slide_type": "skip" @@ -1181,12 +1229,12 @@ "\u001b[0;34m integers (list of int's): whole numbers to be averaged\u001b[0m\n", "\u001b[0;34m\u001b[0m\n", "\u001b[0;34m Returns:\u001b[0m\n", - "\u001b[0;34m float: average\u001b[0m\n", + "\u001b[0;34m average (float)\u001b[0m\n", "\u001b[0;34m \"\"\"\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mevens\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mn\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mintegers\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;36m2\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0maverage\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mevens\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mevens\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0maverage\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mFile:\u001b[0m ~/repos/intro-to-python/\n", + "\u001b[0;31mFile:\u001b[0m ~/repos/intro-to-python/\n", "\u001b[0;31mType:\u001b[0m function\n" ] }, @@ -1211,7 +1259,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 37, "metadata": { "slideshow": { "slide_type": "skip" @@ -1262,7 +1310,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 38, "metadata": { "slideshow": { "slide_type": "slide" @@ -1275,7 +1323,7 @@ "7.0" ] }, - "execution_count": 37, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } @@ -1286,7 +1334,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 39, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1299,7 +1347,7 @@ "7.0" ] }, - "execution_count": 38, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -1321,7 +1369,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 40, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1334,10 +1382,10 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 41, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1347,7 +1395,7 @@ "7.0" ] }, - "execution_count": 40, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" } @@ -1391,7 +1439,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 42, "metadata": { "slideshow": { "slide_type": "slide" @@ -1405,7 +1453,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mintegers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mintegers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'integers' is not defined" ] } @@ -1416,10 +1464,10 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 43, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1430,7 +1478,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mevens\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mevens\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'evens' is not defined" ] } @@ -1441,7 +1489,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 44, "metadata": { "slideshow": { "slide_type": "skip" @@ -1455,7 +1503,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0maverage\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0maverage\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'average' is not defined" ] } @@ -1499,7 +1547,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 45, "metadata": { "slideshow": { "slide_type": "slide" @@ -1514,7 +1562,7 @@ " integers (list of int's): whole numbers to be averaged\n", "\n", " Returns:\n", - " float: average\n", + " average (float)\n", " \"\"\"\n", " evens = [n for n in numbers if n % 2 == 0]\n", " average = sum(evens) / len(evens)\n", @@ -1534,7 +1582,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 46, "metadata": { "slideshow": { "slide_type": "slide" @@ -1547,7 +1595,7 @@ "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" ] }, - "execution_count": 45, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } @@ -1569,7 +1617,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 47, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1582,7 +1630,7 @@ "7.0" ] }, - "execution_count": 46, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -1604,7 +1652,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 48, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1617,7 +1665,7 @@ "7.0" ] }, - "execution_count": 47, + "execution_count": 48, "metadata": {}, "output_type": "execute_result" } @@ -1665,7 +1713,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 49, "metadata": { "slideshow": { "slide_type": "slide" @@ -1681,7 +1729,7 @@ " if non-whole numbers are provided, they are rounded\n", "\n", " Returns:\n", - " float: average\n", + " average (float)\n", " \"\"\"\n", " numbers = [round(n) for n in integers]\n", " evens = [n for n in numbers if n % 2 == 0]\n", @@ -1702,7 +1750,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 50, "metadata": { "slideshow": { "slide_type": "slide" @@ -1715,7 +1763,7 @@ "42.0" ] }, - "execution_count": 49, + "execution_count": 50, "metadata": {}, "output_type": "execute_result" } @@ -1737,7 +1785,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 51, "metadata": { "slideshow": { "slide_type": "skip" @@ -1761,7 +1809,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 52, "metadata": { "slideshow": { "slide_type": "skip" @@ -1775,7 +1823,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0maverage_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m40.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m41.1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m42.2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m43.3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m44.4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m87.0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0maverage_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m40.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m41.1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m42.2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m43.3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m44.4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m87.0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m: " ] } @@ -1797,7 +1845,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 53, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1810,7 +1858,7 @@ "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" ] }, - "execution_count": 52, + "execution_count": 53, "metadata": {}, "output_type": "execute_result" } @@ -1832,7 +1880,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 54, "metadata": { "slideshow": { "slide_type": "skip" @@ -1845,7 +1893,7 @@ "7.0" ] }, - "execution_count": 53, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } @@ -1867,7 +1915,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 55, "metadata": { "slideshow": { "slide_type": "skip" @@ -1880,7 +1928,7 @@ "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" ] }, - "execution_count": 54, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } @@ -1910,7 +1958,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 56, "metadata": { "slideshow": { "slide_type": "slide" @@ -1925,7 +1973,7 @@ " numbers (list of int's): whole numbers to be averaged\n", "\n", " Returns:\n", - " float: average\n", + " average (float)\n", " \"\"\"\n", " evens = [n for n in numbers if n % 2 == 0]\n", " average = sum(evens) / len(evens)\n", @@ -1934,7 +1982,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 57, "metadata": { "slideshow": { "slide_type": "slide" @@ -1947,7 +1995,7 @@ "7.0" ] }, - "execution_count": 56, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } @@ -1958,7 +2006,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 58, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1971,7 +2019,7 @@ "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" ] }, - "execution_count": 57, + "execution_count": 58, "metadata": {}, "output_type": "execute_result" } @@ -2015,7 +2063,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 59, "metadata": { "slideshow": { "slide_type": "slide" @@ -2028,7 +2076,7 @@ "(4, 2)" ] }, - "execution_count": 58, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" } @@ -2039,7 +2087,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 60, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2052,7 +2100,7 @@ "(0, 10)" ] }, - "execution_count": 59, + "execution_count": 60, "metadata": {}, "output_type": "execute_result" } @@ -2074,7 +2122,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 61, "metadata": { "slideshow": { "slide_type": "slide" @@ -2091,7 +2139,7 @@ " scalar (float): multiplies the average\n", "\n", " Returns:\n", - " float: scaled average\n", + " scaled_average (float)\n", " \"\"\"\n", " numbers = [round(n) for n in numbers]\n", " evens = [n for n in numbers if n % 2 == 0]\n", @@ -2112,7 +2160,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 62, "metadata": { "slideshow": { "slide_type": "slide" @@ -2125,7 +2173,7 @@ "14.0" ] }, - "execution_count": 61, + "execution_count": 62, "metadata": {}, "output_type": "execute_result" } @@ -2147,41 +2195,6 @@ "Luckily, we may also pass in arguments *by name*. Then, we refer to them as **keyword arguments**." ] }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "14.0" - ] - }, - "execution_count": 62, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "scaled_average_evens(numbers=numbers, scalar=2)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "When passing all arguments by name, we may do so in any order." - ] - }, { "cell_type": "code", "execution_count": 63, @@ -2203,7 +2216,7 @@ } ], "source": [ - "scaled_average_evens(scalar=2, numbers=numbers)" + "scaled_average_evens(numbers=numbers, scalar=2)" ] }, { @@ -2214,7 +2227,7 @@ } }, "source": [ - "We may even combine positional and keyword arguments in the same function call." + "When passing all arguments by name, we may do so in any order." ] }, { @@ -2237,6 +2250,41 @@ "output_type": "execute_result" } ], + "source": [ + "scaled_average_evens(scalar=2, numbers=numbers)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "We may even combine positional and keyword arguments in the same function call." + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "14.0" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "scaled_average_evens(numbers, scalar=2)" ] @@ -2254,7 +2302,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 66, "metadata": { "slideshow": { "slide_type": "skip" @@ -2263,10 +2311,10 @@ "outputs": [ { "ename": "SyntaxError", - "evalue": "positional argument follows keyword argument (, line 1)", + "evalue": "positional argument follows keyword argument (, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m scaled_average_evens(numbers=numbers, 2)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m positional argument follows keyword argument\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m scaled_average_evens(numbers=numbers, 2)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m positional argument follows keyword argument\n" ] } ], @@ -2287,7 +2335,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 67, "metadata": { "slideshow": { "slide_type": "skip" @@ -2301,7 +2349,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mscaled_average_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnumbers\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mscaled_average_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnumbers\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: scaled_average_evens() missing 1 required positional argument: 'scalar'" ] } @@ -2312,7 +2360,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 68, "metadata": { "slideshow": { "slide_type": "skip" @@ -2326,7 +2374,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mscaled_average_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnumbers\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mscaled_average_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnumbers\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: scaled_average_evens() takes 2 positional arguments but 3 were given" ] } @@ -2361,7 +2409,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 69, "metadata": { "slideshow": { "slide_type": "slide" @@ -2379,7 +2427,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 70, "metadata": { "slideshow": { "slide_type": "-" @@ -2410,7 +2458,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 71, "metadata": { "slideshow": { "slide_type": "slide" @@ -2425,7 +2473,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 72, "metadata": { "slideshow": { "slide_type": "-" @@ -2454,7 +2502,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 73, "metadata": { "slideshow": { "slide_type": "skip" @@ -2467,7 +2515,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 74, "metadata": { "slideshow": { "slide_type": "skip" @@ -2502,7 +2550,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 75, "metadata": { "slideshow": { "slide_type": "slide" @@ -2519,7 +2567,7 @@ " scalar (float, optional): multiplies the average; defaults to 1\n", "\n", " Returns:\n", - " float: (scaled) average\n", + " scaled_average (float)\n", " \"\"\"\n", " numbers = [round(n) for n in numbers]\n", " evens = [n for n in numbers if n % 2 == 0]\n", @@ -2544,7 +2592,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 76, "metadata": { "slideshow": { "slide_type": "slide" @@ -2557,37 +2605,13 @@ "7.0" ] }, - "execution_count": 75, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "average_evens(numbers)" - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "14.0" - ] - }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "average_evens(numbers, 2)" + "average_evens(numbers)" ] }, { @@ -2610,6 +2634,30 @@ "output_type": "execute_result" } ], + "source": [ + "average_evens(numbers, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "14.0" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "average_evens(numbers, scalar=2)" ] @@ -2640,7 +2688,7 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 79, "metadata": { "slideshow": { "slide_type": "slide" @@ -2657,7 +2705,7 @@ " scalar (float, optional): multiplies the average; defaults to 1\n", "\n", " Returns:\n", - " float: (scaled) average\n", + " scaled_average (float)\n", " \"\"\"\n", " numbers = [round(n) for n in numbers]\n", " evens = [n for n in numbers if n % 2 == 0]\n", @@ -2678,7 +2726,7 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 80, "metadata": { "slideshow": { "slide_type": "slide" @@ -2691,7 +2739,7 @@ "7.0" ] }, - "execution_count": 79, + "execution_count": 80, "metadata": {}, "output_type": "execute_result" } @@ -2713,7 +2761,7 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 81, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2726,7 +2774,7 @@ "14.0" ] }, - "execution_count": 80, + "execution_count": 81, "metadata": {}, "output_type": "execute_result" } @@ -2748,7 +2796,7 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 82, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2762,7 +2810,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0maverage_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnumbers\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0maverage_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnumbers\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: average_evens() takes 1 positional argument but 2 were given" ] } @@ -2775,7 +2823,7 @@ "cell_type": "markdown", "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "source": [ @@ -2803,10 +2851,10 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 83, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -2816,7 +2864,7 @@ "(x)>" ] }, - "execution_count": 82, + "execution_count": 83, "metadata": {}, "output_type": "execute_result" } @@ -2842,10 +2890,10 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 84, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [], @@ -2866,10 +2914,10 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 85, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2879,7 +2927,7 @@ "function" ] }, - "execution_count": 84, + "execution_count": 85, "metadata": {}, "output_type": "execute_result" } @@ -2890,10 +2938,10 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 86, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2903,7 +2951,7 @@ "True" ] }, - "execution_count": 85, + "execution_count": 86, "metadata": {}, "output_type": "execute_result" } @@ -2923,41 +2971,6 @@ "Now we may call `add_three()` as if we defined it with the `def` statement." ] }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "42" - ] - }, - "execution_count": 86, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "add_three(39)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Alternatively, we could call an `function` object created with a `lambda` expression right away (i.e., without assigning it to a variable), which looks quite weird for now as we need *two* pairs of parentheses: The first one serves as a delimiter whereas the second represents the call operator." - ] - }, { "cell_type": "code", "execution_count": 87, @@ -2978,6 +2991,41 @@ "output_type": "execute_result" } ], + "source": [ + "add_three(39)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Alternatively, we could call an `function` object created with a `lambda` expression right away (i.e., without assigning it to a variable), which looks quite weird for now as we need *two* pairs of parentheses: The first one serves as a delimiter whereas the second represents the call operator." + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "42" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "(lambda x: x + 3)(39)" ] @@ -2992,7 +3040,7 @@ "source": [ "The main point of having functions without a reference to them is to use them in a situation where we know ahead of time that we use the function only *once*.\n", "\n", - "Popular applications of lambda expressions occur in combination with the **map-filter-reduce** paradigm (cf., [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Lambda-Expressions)) or when we do \"number crunching\" with **arrays** and **data frames** (cf., Chapter 9)." + "Popular applications of lambda expressions occur in combination with the **map-filter-reduce** paradigm (cf., [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_lecture.ipynb#Lambda-Expressions))." ] }, { @@ -3077,7 +3125,7 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 89, "metadata": { "slideshow": { "slide_type": "slide" @@ -3099,30 +3147,6 @@ "This creates the variable `math` that references a **[module object](https://docs.python.org/3/glossary.html#term-module)** (i.e., type `module`) in memory." ] }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 89, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "math" - ] - }, { "cell_type": "code", "execution_count": 90, @@ -3135,7 +3159,7 @@ { "data": { "text/plain": [ - "140451956463472" + "" ] }, "execution_count": 90, @@ -3144,7 +3168,7 @@ } ], "source": [ - "id(math)" + "math" ] }, { @@ -3159,7 +3183,7 @@ { "data": { "text/plain": [ - "module" + "139687472778032" ] }, "execution_count": 91, @@ -3167,6 +3191,30 @@ "output_type": "execute_result" } ], + "source": [ + "id(math)" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "module" + ] + }, + "execution_count": 92, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "type(math)" ] @@ -3188,7 +3236,7 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": 93, "metadata": { "slideshow": { "slide_type": "skip" @@ -3256,7 +3304,7 @@ " 'trunc']" ] }, - "execution_count": 92, + "execution_count": 93, "metadata": {}, "output_type": "execute_result" } @@ -3278,7 +3326,7 @@ }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 94, "metadata": { "slideshow": { "slide_type": "slide" @@ -3291,7 +3339,7 @@ "3.141592653589793" ] }, - "execution_count": 93, + "execution_count": 94, "metadata": {}, "output_type": "execute_result" } @@ -3302,7 +3350,7 @@ }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 95, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3315,7 +3363,7 @@ "2.718281828459045" ] }, - "execution_count": 94, + "execution_count": 95, "metadata": {}, "output_type": "execute_result" } @@ -3326,7 +3374,7 @@ }, { "cell_type": "code", - "execution_count": 95, + "execution_count": 96, "metadata": { "slideshow": { "slide_type": "slide" @@ -3339,7 +3387,7 @@ "" ] }, - "execution_count": 95, + "execution_count": 96, "metadata": {}, "output_type": "execute_result" } @@ -3350,7 +3398,7 @@ }, { "cell_type": "code", - "execution_count": 96, + "execution_count": 97, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3375,7 +3423,7 @@ }, { "cell_type": "code", - "execution_count": 97, + "execution_count": 98, "metadata": { "slideshow": { "slide_type": "slide" @@ -3388,7 +3436,7 @@ "1.4142135623730951" ] }, - "execution_count": 97, + "execution_count": 98, "metadata": {}, "output_type": "execute_result" } @@ -3414,7 +3462,7 @@ }, { "cell_type": "code", - "execution_count": 98, + "execution_count": 99, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3427,7 +3475,7 @@ "2.0" ] }, - "execution_count": 98, + "execution_count": 99, "metadata": {}, "output_type": "execute_result" } @@ -3449,7 +3497,7 @@ }, { "cell_type": "code", - "execution_count": 99, + "execution_count": 100, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3462,7 +3510,7 @@ "10.0" ] }, - "execution_count": 99, + "execution_count": 100, "metadata": {}, "output_type": "execute_result" } @@ -3486,7 +3534,7 @@ }, { "cell_type": "code", - "execution_count": 100, + "execution_count": 101, "metadata": { "slideshow": { "slide_type": "skip" @@ -3499,7 +3547,7 @@ }, { "cell_type": "code", - "execution_count": 101, + "execution_count": 102, "metadata": { "slideshow": { "slide_type": "skip" @@ -3512,7 +3560,7 @@ "4.0" ] }, - "execution_count": 101, + "execution_count": 102, "metadata": {}, "output_type": "execute_result" } @@ -3545,7 +3593,7 @@ }, { "cell_type": "code", - "execution_count": 102, + "execution_count": 103, "metadata": { "slideshow": { "slide_type": "slide" @@ -3558,7 +3606,7 @@ }, { "cell_type": "code", - "execution_count": 103, + "execution_count": 104, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3568,10 +3616,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 103, + "execution_count": 104, "metadata": {}, "output_type": "execute_result" } @@ -3593,7 +3641,7 @@ }, { "cell_type": "code", - "execution_count": 104, + "execution_count": 105, "metadata": { "slideshow": { "slide_type": "skip" @@ -3667,7 +3715,7 @@ " 'weibullvariate']" ] }, - "execution_count": 104, + "execution_count": 105, "metadata": {}, "output_type": "execute_result" } @@ -3689,7 +3737,7 @@ }, { "cell_type": "code", - "execution_count": 105, + "execution_count": 106, "metadata": { "slideshow": { "slide_type": "slide" @@ -3702,7 +3750,7 @@ "" ] }, - "execution_count": 105, + "execution_count": 106, "metadata": {}, "output_type": "execute_result" } @@ -3713,7 +3761,7 @@ }, { "cell_type": "code", - "execution_count": 106, + "execution_count": 107, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3738,7 +3786,7 @@ }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 108, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3748,10 +3796,10 @@ { "data": { "text/plain": [ - "0.09696128509713109" + "0.5217159553088394" ] }, - "execution_count": 107, + "execution_count": 108, "metadata": {}, "output_type": "execute_result" } @@ -3773,7 +3821,7 @@ }, { "cell_type": "code", - "execution_count": 108, + "execution_count": 109, "metadata": { "slideshow": { "slide_type": "slide" @@ -3783,10 +3831,10 @@ { "data": { "text/plain": [ - ">" + ">" ] }, - "execution_count": 108, + "execution_count": 109, "metadata": {}, "output_type": "execute_result" } @@ -3797,7 +3845,7 @@ }, { "cell_type": "code", - "execution_count": 109, + "execution_count": 110, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3822,7 +3870,7 @@ }, { "cell_type": "code", - "execution_count": 110, + "execution_count": 111, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3832,10 +3880,10 @@ { "data": { "text/plain": [ - "3" + "10" ] }, - "execution_count": 110, + "execution_count": 111, "metadata": {}, "output_type": "execute_result" } @@ -3859,7 +3907,7 @@ }, { "cell_type": "code", - "execution_count": 111, + "execution_count": 112, "metadata": { "slideshow": { "slide_type": "slide" @@ -3872,7 +3920,7 @@ }, { "cell_type": "code", - "execution_count": 112, + "execution_count": 113, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3885,7 +3933,7 @@ "0.6394267984578837" ] }, - "execution_count": 112, + "execution_count": 113, "metadata": {}, "output_type": "execute_result" } @@ -3896,7 +3944,7 @@ }, { "cell_type": "code", - "execution_count": 113, + "execution_count": 114, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3909,7 +3957,7 @@ }, { "cell_type": "code", - "execution_count": 114, + "execution_count": 115, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3922,7 +3970,7 @@ "0.6394267984578837" ] }, - "execution_count": 114, + "execution_count": 115, "metadata": {}, "output_type": "execute_result" } @@ -3978,7 +4026,7 @@ } }, "source": [ - "[numpy](http://www.numpy.org/) is the de-facto standard in the Python world for handling **array-like** data. That is a fancy word for data that can be put into a matrix or vector format. We look at it in depth in [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_arrays_00_lecture.ipynb).\n", + "[numpy](http://www.numpy.org/) is the de-facto standard in the Python world for handling **array-like** data. That is a fancy word for data that can be put into a matrix or vector format.\n", "\n", "As [numpy](http://www.numpy.org/) is *not* in the [standard library](https://docs.python.org/3/library/index.html), it must be *manually* installed, for example, with the [pip](https://pip.pypa.io/en/stable/) tool. As mentioned in [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb#Markdown-vs.-Code-Cells), to execute terminal commands from within a Jupyter notebook, we start a code cell with an exclamation mark.\n", "\n", @@ -3987,7 +4035,7 @@ }, { "cell_type": "code", - "execution_count": 115, + "execution_count": 116, "metadata": { "slideshow": { "slide_type": "slide" @@ -3998,7 +4046,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Requirement already satisfied: numpy in /home/webartifex/.pyenv/versions/3.7.6/envs/v-ipp/lib/python3.7/site-packages (1.18.1)\n" + "Requirement already satisfied: numpy in /home/webartifex/.pyenv/versions/anaconda3-2019.10/lib/python3.7/site-packages (1.17.2)\n" ] } ], @@ -4019,7 +4067,7 @@ }, { "cell_type": "code", - "execution_count": 116, + "execution_count": 117, "metadata": { "slideshow": { "slide_type": "slide" @@ -4043,7 +4091,7 @@ }, { "cell_type": "code", - "execution_count": 117, + "execution_count": 118, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4053,10 +4101,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 117, + "execution_count": 118, "metadata": {}, "output_type": "execute_result" } @@ -4078,7 +4126,7 @@ }, { "cell_type": "code", - "execution_count": 118, + "execution_count": 119, "metadata": { "slideshow": { "slide_type": "slide" @@ -4089,30 +4137,6 @@ "vec = np.array(numbers)" ] }, - { - "cell_type": "code", - "execution_count": 119, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4])" - ] - }, - "execution_count": 119, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "vec" - ] - }, { "cell_type": "code", "execution_count": 120, @@ -4125,7 +4149,7 @@ { "data": { "text/plain": [ - "numpy.ndarray" + "array([ 7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4])" ] }, "execution_count": 120, @@ -4133,6 +4157,30 @@ "output_type": "execute_result" } ], + "source": [ + "vec" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "numpy.ndarray" + ] + }, + "execution_count": 121, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "type(vec)" ] @@ -4152,7 +4200,7 @@ }, { "cell_type": "code", - "execution_count": 121, + "execution_count": 122, "metadata": { "slideshow": { "slide_type": "slide" @@ -4165,7 +4213,7 @@ "array([14, 22, 16, 10, 6, 24, 4, 12, 18, 20, 2, 8])" ] }, - "execution_count": 121, + "execution_count": 122, "metadata": {}, "output_type": "execute_result" } @@ -4187,7 +4235,7 @@ }, { "cell_type": "code", - "execution_count": 122, + "execution_count": 123, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4200,7 +4248,7 @@ "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4, 7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" ] }, - "execution_count": 122, + "execution_count": 123, "metadata": {}, "output_type": "execute_result" } @@ -4222,7 +4270,7 @@ }, { "cell_type": "code", - "execution_count": 123, + "execution_count": 124, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4235,7 +4283,7 @@ "78" ] }, - "execution_count": 123, + "execution_count": 124, "metadata": {}, "output_type": "execute_result" } @@ -4246,7 +4294,7 @@ }, { "cell_type": "code", - "execution_count": 124, + "execution_count": 125, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4259,7 +4307,7 @@ "7" ] }, - "execution_count": 124, + "execution_count": 125, "metadata": {}, "output_type": "execute_result" } @@ -4298,7 +4346,7 @@ }, { "cell_type": "code", - "execution_count": 125, + "execution_count": 126, "metadata": { "slideshow": { "slide_type": "slide" @@ -4311,7 +4359,7 @@ }, { "cell_type": "code", - "execution_count": 126, + "execution_count": 127, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4324,7 +4372,7 @@ "" ] }, - "execution_count": 126, + "execution_count": 127, "metadata": {}, "output_type": "execute_result" } @@ -4350,7 +4398,7 @@ }, { "cell_type": "code", - "execution_count": 127, + "execution_count": 128, "metadata": { "slideshow": { "slide_type": "skip" @@ -4375,7 +4423,7 @@ " 'average_odds']" ] }, - "execution_count": 127, + "execution_count": 128, "metadata": {}, "output_type": "execute_result" } @@ -4397,7 +4445,7 @@ }, { "cell_type": "code", - "execution_count": 128, + "execution_count": 129, "metadata": { "slideshow": { "slide_type": "slide" @@ -4410,7 +4458,7 @@ "" ] }, - "execution_count": 128, + "execution_count": 129, "metadata": {}, "output_type": "execute_result" } @@ -4421,7 +4469,7 @@ }, { "cell_type": "code", - "execution_count": 129, + "execution_count": 130, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4443,7 +4491,7 @@ " scalar (float, optional): multiplies the average; defaults to 1\n", " \n", " Returns:\n", - " float: (scaled) average\n", + " scaled_average (float)\n", "\n" ] } @@ -4454,7 +4502,7 @@ }, { "cell_type": "code", - "execution_count": 130, + "execution_count": 131, "metadata": { "slideshow": { "slide_type": "slide" @@ -4467,7 +4515,7 @@ "7.0" ] }, - "execution_count": 130, + "execution_count": 131, "metadata": {}, "output_type": "execute_result" } @@ -4478,7 +4526,7 @@ }, { "cell_type": "code", - "execution_count": 131, + "execution_count": 132, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4491,7 +4539,7 @@ "14.0" ] }, - "execution_count": 131, + "execution_count": 132, "metadata": {}, "output_type": "execute_result" } @@ -4571,7 +4619,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.4" }, "livereveal": { "auto_select": "code", diff --git a/02_functions_01_review.ipynb b/02_functions_01_review.ipynb index 3b58b22..36a95ea 100644 --- a/02_functions_01_review.ipynb +++ b/02_functions_01_review.ipynb @@ -18,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb) of the book. Then, work through the questions below." + "The questions below assume that you have read [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb) in the book.\n", + "\n", + "Be concise in your answers! Most questions can be answered in *one* sentence." ] }, { @@ -28,13 +30,6 @@ "### Essay Questions " ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Answer the following questions *briefly*!" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -46,7 +41,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -60,7 +55,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -74,7 +69,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -88,7 +83,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -102,7 +97,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -116,7 +111,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -130,7 +125,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -158,7 +153,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -172,7 +167,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -186,7 +181,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -200,7 +195,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] } ], @@ -220,7 +215,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.4" }, "toc": { "base_numbering": 1, diff --git a/02_functions_02_exercises.ipynb b/02_functions_02_exercises.ipynb index cc0accd..e749839 100644 --- a/02_functions_02_exercises.ipynb +++ b/02_functions_02_exercises.ipynb @@ -18,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb) of the book. Then, work through the exercises below. The `...` indicate where you need to fill in your answers. You should not need to create any additional code cells." + "The exercises below assume that you have read [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb) in the book.\n", + "\n", + "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." ] }, { @@ -66,7 +68,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q2**: Encapsulate the logic into a function `sphere_volume()` that takes one *positional* argument `radius` and one *keyword-only* argument `digits` defaulting to `5`. The volume should be returned as a `float` object under *all* circumstances. Document your work appropriately in a docstring according to [Google's Python Style Guide](https://github.com/google/styleguide/blob/gh-pages/pyguide.md)." + "**Q2**: Encapsulate the logic into a function `sphere_volume()` that takes one *positional* argument `radius` and one *keyword-only* argument `digits` defaulting to `5`. The volume should be returned as a `float` object under *all* circumstances." ] }, { @@ -76,7 +78,17 @@ "outputs": [], "source": [ "def sphere_volume(...):\n", - " ..." + " \"\"\"Calculate the volume of a sphere.\n", + "\n", + " Args:\n", + " radius (float): radius of the sphere\n", + " digits (optional, int): number of digits\n", + " for rounding the resulting volume\n", + "\n", + " Returns:\n", + " volume (float)\n", + " \"\"\"\n", + " return ..." ] }, { @@ -151,7 +163,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -193,7 +205,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] } ], @@ -213,7 +225,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.4" }, "toc": { "base_numbering": 1, diff --git a/03_conditionals_00_lecture.ipynb b/03_conditionals_00_lecture.ipynb index 7b769c4..61a1d3f 100644 --- a/03_conditionals_00_lecture.ipynb +++ b/03_conditionals_00_lecture.ipynb @@ -1,5 +1,53 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A **video presentation** of the contents in this chapter is shown below. A playlist with *all* chapters as videos is linked [here](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChALCAgOCggIDRYNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxgVERUWFxcYExMYGBgVFRgWFRYWGBcVGxIaEhMXFRoYGBISFRcVFRUVFRUVFRUVGBUSFxIVFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAgIDAQEAAAAAAAAAAAAABgcFCAIDBAEJ/8QAURAAAQQBAgMBCQgRAgUEAgMAAQACAwQRBRIGEyExBxQYIjJBVZTVCBUXUVJhk9QjMzVCU1RxcnN0dYGSsbKz05G0FiQ2YrU0gqGiY3YlQ0X/xAAcAQEAAgMBAQEAAAAAAAAAAAAAAgQBAwUHBgj/xAA9EQABAwIDBQUGBAYBBQEAAAABAAIRAyEEEjEFQVFhcRMVU4GRBiIyocHwFjRysRQ1QlLR4fEjM0NigpL/2gAMAwEAAhEDEQA/ANMkREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXF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hodQ0EBkkco21dQ8qJ4e0HOodmWhZBgrB0X6DItAPDV4q9H8P+q6j7RTw1eKvR/D/quo+0VhZW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/682q/aJ/0Mn9DloT4avFXo/h/1XUfaK4WPdo8UvY9hoaBh7XNOKuo5w4EHGdR7eqItaURERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERf/2Q==\n", + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo(\"aDbblINzuGQ\", width=\"60%\")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -50,7 +98,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "slideshow": { "slide_type": "slide" @@ -63,7 +111,7 @@ "True" ] }, - "execution_count": 1, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -74,7 +122,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" @@ -87,7 +135,7 @@ "False" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -109,7 +157,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "slideshow": { "slide_type": "fragment" @@ -122,7 +170,7 @@ "True" ] }, - "execution_count": 3, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -144,7 +192,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "slideshow": { "slide_type": "fragment" @@ -157,7 +205,7 @@ "True" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -190,7 +238,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "slideshow": { "slide_type": "slide" @@ -200,31 +248,7 @@ { "data": { "text/plain": [ - "94426021241472" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "id(True)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "94426021241440" + "True" ] }, "execution_count": 6, @@ -233,7 +257,7 @@ } ], "source": [ - "id(False)" + "True" ] }, { @@ -248,7 +272,7 @@ { "data": { "text/plain": [ - "bool" + "94082696684160" ] }, "execution_count": 7, @@ -257,7 +281,7 @@ } ], "source": [ - "type(True)" + "id(True)" ] }, { @@ -265,7 +289,7 @@ "execution_count": 8, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -280,6 +304,78 @@ "output_type": "execute_result" } ], + "source": [ + "type(True)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "False" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "94082696684128" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "id(False)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "bool" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "type(False)" ] @@ -301,7 +397,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 12, "metadata": { "slideshow": { "slide_type": "slide" @@ -314,7 +410,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 13, "metadata": { "slideshow": { "slide_type": "fragment" @@ -324,10 +420,10 @@ { "data": { "text/plain": [ - "94426021228432" + "94082696671120" ] }, - "execution_count": 10, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -338,10 +434,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 14, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -351,7 +447,7 @@ "NoneType" ] }, - "execution_count": 11, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -386,10 +482,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 15, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -399,7 +495,7 @@ "True" ] }, - "execution_count": 12, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -424,10 +520,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 16, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -437,7 +533,7 @@ "False" ] }, - "execution_count": 13, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -457,12 +553,12 @@ } }, "source": [ - "So the following expression regards *four* objects in memory: *One* `list` object holding ten references to *three* other objects." + "So the following expression regards *four* objects in memory: *One* `list` object holding six references to *three* other objects." ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 17, "metadata": { "slideshow": { "slide_type": "slide" @@ -472,16 +568,16 @@ { "data": { "text/plain": [ - "[True, False, None, None, None, True, False, None, None, None]" + "[True, False, None, True, False, None]" ] }, - "execution_count": 14, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "[True, False, None, None, None, True, False, None, None, None]" + "[True, False, None, True, False, None]" ] }, { @@ -508,7 +604,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 18, "metadata": { "slideshow": { "slide_type": "slide" @@ -521,7 +617,7 @@ "False" ] }, - "execution_count": 15, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -532,7 +628,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 19, "metadata": { "slideshow": { "slide_type": "fragment" @@ -545,13 +641,13 @@ "True" ] }, - "execution_count": 16, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "42 != 123 # \"not equal to\"; other languages may use \"<>\"" + "42 != 123 # \"not equal to\"" ] }, { @@ -567,7 +663,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 20, "metadata": { "slideshow": { "slide_type": "slide" @@ -580,7 +676,7 @@ "True" ] }, - "execution_count": 17, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -591,10 +687,10 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 21, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -604,7 +700,7 @@ "True" ] }, - "execution_count": 18, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -615,7 +711,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 22, "metadata": { "slideshow": { "slide_type": "fragment" @@ -628,7 +724,7 @@ "False" ] }, - "execution_count": 19, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -639,10 +735,10 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 23, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -652,7 +748,7 @@ "False" ] }, - "execution_count": 20, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -691,7 +787,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 24, "metadata": { "slideshow": { "slide_type": "slide" @@ -716,7 +812,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 25, "metadata": { "slideshow": { "slide_type": "slide" @@ -729,7 +825,7 @@ "True" ] }, - "execution_count": 22, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -749,89 +845,6 @@ "However, sometimes, it is good to use *parentheses* around each operand for clarity." ] }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "(a > 5) and (b <= 100)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "This is especially so when several logical operators are combined." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a <= 5 or not b > 100" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "(a <= 5) or not (b > 100)" - ] - }, { "cell_type": "code", "execution_count": 26, @@ -853,7 +866,7 @@ } ], "source": [ - "(a <= 5) or (not (b > 100)) # no need to \"over do\" it" + "(a > 5) and (b <= 100)" ] }, { @@ -864,9 +877,7 @@ } }, "source": [ - "For even better readability, some practitioners suggest to *never* use the `>` and `>=` operators (cf., [source](https://llewellynfalco.blogspot.com/2016/02/dont-use-greater-than-sign-in.html); note that the included example is written in [Java](https://en.wikipedia.org/wiki/Java_%28programming_language%29) where `&&` means `and` and `||` means `or`).\n", - "\n", - "We may **chain** operators if the expressions that contain them are combined with the `and` operator. For example, the following two cells implement the same logic, where the second is a lot easier to read." + "This is especially so when several logical operators are combined." ] }, { @@ -890,7 +901,7 @@ } ], "source": [ - "5 < a and a < 87" + "a <= 5 or not b > 100" ] }, { @@ -913,6 +924,91 @@ "output_type": "execute_result" } ], + "source": [ + "(a <= 5) or not (b > 100)" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(a <= 5) or (not (b > 100)) # no need to \"over do\" it" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "For even better readability, some practitioners suggest to *never* use the `>` and `>=` operators (cf., [source](https://llewellynfalco.blogspot.com/2016/02/dont-use-greater-than-sign-in.html); note that the included example is written in [Java](https://en.wikipedia.org/wiki/Java_%28programming_language%29) where `&&` means `and` and `||` means `or`).\n", + "\n", + "We may **chain** operators if the expressions that contain them are combined with the `and` operator. For example, the following two cells implement the same logic, where the second is a lot easier to read." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "5 < a and a < 87" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "5 < a < 87" ] @@ -940,101 +1036,7 @@ "\n", "For example, any non-zero numeric object is cast as `True`. While this behavior allows writing more concise and thus more \"beautiful\" code, it may also be a source of confusion.\n", "\n", - "So, `(a - 21)` is cast as `True` and then the overall expression evaluates to `True` as well." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "(a - 21) and (b < 100) # => 21 and (b < 100) => 21 and True" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Whenever we are unsure how Python evaluates a non-boolean expression in a boolean context, the [bool()](https://docs.python.org/3/library/functions.html#bool) built-in allows us to do it ourselves. [bool()](https://docs.python.org/3/library/functions.html#bool), like [int()](https://docs.python.org/3/library/functions.html#int), is yet another *constructor*." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bool(a - 21) # = bool(21)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bool(a - 42) # = bool(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Let's keep in mind that negative numbers also evaluate to `True`!" + "So, `(a - 40)` is cast as `True` and then the overall expression evaluates to `True` as well." ] }, { @@ -1042,7 +1044,7 @@ "execution_count": 32, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" } }, "outputs": [ @@ -1058,7 +1060,7 @@ } ], "source": [ - "bool(a - 43) # = bool(-1)" + "(a - 40) and (b < 100)" ] }, { @@ -1069,7 +1071,7 @@ } }, "source": [ - "In a boolean context, `None` is cast as `False`! So, `None` is *not* a \"maybe\" answer but a \"no.\"" + "Whenever we are unsure how Python evaluates a non-boolean expression in a boolean context, the [bool()](https://docs.python.org/3/library/functions.html#bool) built-in allows us to do it ourselves. [bool()](https://docs.python.org/3/library/functions.html#bool), like [int()](https://docs.python.org/3/library/functions.html#int), is yet another *constructor*." ] }, { @@ -1077,14 +1079,14 @@ "execution_count": 33, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ - "False" + "True" ] }, "execution_count": 33, @@ -1093,18 +1095,7 @@ } ], "source": [ - "bool(None)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Another good rule to know is that container types (e.g., `list`) evaluate to `False` whenever they are empty and `True` if they hold at least one element." + "bool(a - 40)" ] }, { @@ -1112,7 +1103,7 @@ "execution_count": 34, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -1128,7 +1119,18 @@ } ], "source": [ - "bool([])" + "bool(a - 42)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Let's keep in mind that negative numbers also evaluate to `True`!" ] }, { @@ -1151,6 +1153,100 @@ "output_type": "execute_result" } ], + "source": [ + "bool(a - 44)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "In a boolean context, `None` is cast as `False`! So, `None` is *not* a \"maybe\" answer but a \"no.\"" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bool(None)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Another good rule to know is that container types (e.g., `list`) evaluate to `False` whenever they are empty and `True` if they hold at least one element." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bool([])" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "bool([False])" ] @@ -1168,7 +1264,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 39, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1181,7 +1277,7 @@ "False" ] }, - "execution_count": 36, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -1192,10 +1288,10 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 40, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1205,13 +1301,13 @@ "True" ] }, - "execution_count": 37, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "bool(\"Lorem ipsum dolor sit amet, ...\")" + "bool(\"Lorem ipsum dolor sit amet.\")" ] }, { @@ -1260,10 +1356,10 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 41, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [], @@ -1287,12 +1383,36 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 42, "metadata": { "slideshow": { "slide_type": "slide" } }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "0 or 1" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, "outputs": [ { "name": "stdout", @@ -1308,23 +1428,47 @@ "1" ] }, - "execution_count": 39, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "expr(0) or expr(1)" + "expr(0) or expr(1) # both operands are evaluated" ] }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 44, "metadata": { "slideshow": { "slide_type": "fragment" } }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 or 2" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, "outputs": [ { "name": "stdout", @@ -1339,7 +1483,7 @@ "1" ] }, - "execution_count": 40, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } @@ -1350,10 +1494,34 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 46, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "0 or 1 or 2" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "slideshow": { + "slide_type": "skip" } }, "outputs": [ @@ -1371,7 +1539,7 @@ "1" ] }, - "execution_count": 41, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -1393,12 +1561,36 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 48, "metadata": { "slideshow": { "slide_type": "fragment" } }, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "False or [] or 0" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, "outputs": [ { "name": "stdout", @@ -1415,13 +1607,13 @@ "0" ] }, - "execution_count": 42, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "expr(False) or expr([]) or expr(0)" + "expr(False) or expr([]) or expr(0) # all operands are evaluated" ] }, { @@ -1437,12 +1629,36 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 50, "metadata": { "slideshow": { "slide_type": "slide" } }, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "0 and 1" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, "outputs": [ { "name": "stdout", @@ -1457,7 +1673,7 @@ "0" ] }, - "execution_count": 43, + "execution_count": 51, "metadata": {}, "output_type": "execute_result" } @@ -1468,42 +1684,34 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 52, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Arg: 1\n", - "Arg: 0\n" - ] - }, { "data": { "text/plain": [ "0" ] }, - "execution_count": 44, + "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "expr(1) and expr(0)" + "1 and 0" ] }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 53, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -1521,7 +1729,63 @@ "0" ] }, - "execution_count": 45, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expr(1) and expr(0) # both operands are evaluated" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 and 0 and 2" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Arg: 1\n", + "Arg: 0\n" + ] + }, + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } @@ -1543,34 +1807,59 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 56, "metadata": { "slideshow": { "slide_type": "fragment" } }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 and 2 and 3" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Arg: 1\n", - "Arg: 2\n" + "Arg: 2\n", + "Arg: 3\n" ] }, { "data": { "text/plain": [ - "2" + "3" ] }, - "execution_count": 46, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "expr(1) and expr(2)" + "expr(1) and expr(2) and expr(3)" ] }, { @@ -1622,7 +1911,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 58, "metadata": { "slideshow": { "slide_type": "slide" @@ -1635,10 +1924,10 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 59, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -1648,10 +1937,10 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 60, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [], @@ -1659,6 +1948,17 @@ "random.seed(789)" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### \"Wrong Logic\" Example: Is the number divisible by `2`, `3`, both, or none?" + ] + }, { "cell_type": "markdown", "metadata": { @@ -1672,7 +1972,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 61, "metadata": { "slideshow": { "slide_type": "slide" @@ -1700,6 +2000,17 @@ " print(number, \"is divisible by neither 2 nor 3\")" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### \"Correct Logic\" Example: Is the number divisible by `2`, `3`, both, or none?" + ] + }, { "cell_type": "markdown", "metadata": { @@ -1713,7 +2024,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 62, "metadata": { "slideshow": { "slide_type": "skip" @@ -1726,7 +2037,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 63, "metadata": { "code_folding": [], "slideshow": { @@ -1755,6 +2066,17 @@ " print(number, \"is divisible by neither 2 nor 3\")" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### \"Concise Logic\" Example: Is the number divisible by `2`, `3`, both, or none?" + ] + }, { "cell_type": "markdown", "metadata": { @@ -1768,7 +2090,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 64, "metadata": { "slideshow": { "slide_type": "skip" @@ -1781,7 +2103,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 65, "metadata": { "slideshow": { "slide_type": "slide" @@ -1809,6 +2131,17 @@ " print(number, \"is divisible by neither 2 nor 3\")" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### Only the `if`-clause is mandatory" + ] + }, { "cell_type": "markdown", "metadata": { @@ -1824,7 +2157,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 66, "metadata": { "slideshow": { "slide_type": "slide" @@ -1844,6 +2177,17 @@ " print(\"You read this as often as you see heads when tossing a coin\")" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### Common Use Case: A binary Choice" + ] + }, { "cell_type": "markdown", "metadata": { @@ -1857,7 +2201,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 67, "metadata": { "slideshow": { "slide_type": "skip" @@ -1870,7 +2214,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 68, "metadata": { "slideshow": { "slide_type": "slide" @@ -1907,7 +2251,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 69, "metadata": { "slideshow": { "slide_type": "skip" @@ -1920,7 +2264,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 70, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1938,12 +2282,23 @@ "source": [ "number = random.choice(numbers)\n", "\n", - "if number % 2: # Beware of the opposite meaning!\n", + "if number % 2: # Note the opposite meaning!\n", " print(number, \"is odd\")\n", "else:\n", " print(number, \"is even\")" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### \"Hard to read\" Example: Nesting `if` Statements" + ] + }, { "cell_type": "markdown", "metadata": { @@ -1954,12 +2309,12 @@ "source": [ "We may **nest** `if` statements to control the flow of execution in a more granular way. Every additional layer, however, makes the code *less* readable, in particular, if we have more than one line per code block.\n", "\n", - "As another example, the code cell below first tosses a coin and then *either* checks if `signed_number` is even or odd *or* if it is positive or negative." + "For example, the code cell below implements an [A/B Testing](https://en.wikipedia.org/wiki/A/B_testing) strategy where half the time a \"complex\" message is shown to a \"user\" while in the remaining times an \"easy\" message is shown. To do so, the code first \"tosses a coin\" and then checks a randomly drawn `number`." ] }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 71, "metadata": { "slideshow": { "slide_type": "skip" @@ -1972,7 +2327,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 72, "metadata": { "slideshow": { "slide_type": "slide" @@ -1983,23 +2338,36 @@ "name": "stdout", "output_type": "stream", "text": [ - "4 is even\n" + "6 can be divided by 2 without a rest\n" ] } ], "source": [ - "signed_number = random.choice([-1, +1]) * random.choice(numbers)\n", + "number = random.choice(numbers)\n", "\n", + "# Coin is heads.\n", "if random.random() > 0.5:\n", - " if signed_number % 2:\n", - " print(signed_number, \"is odd\")\n", + " if number % 2 == 0:\n", + " print(number, \"can be divided by 2 without a rest\")\n", " else:\n", - " print(signed_number, \"is even\")\n", + " print(number, \"divided by 2 results in a non-zero rest\")\n", + "# Coin is tails.\n", "else:\n", - " if signed_number > 0:\n", - " print(signed_number, \"is positive\")\n", + " if number % 2 == 0:\n", + " print(number, \"is even\")\n", " else:\n", - " print(signed_number, \"is negative\")" + " print(number, \"is odd\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### \"Easy to read\" Example: Flattening nested `if` Statements" ] }, { @@ -2010,14 +2378,14 @@ } }, "source": [ - "A way to make this code more readable is to introduce **temporary variables** *in combination* with the `and` operator to **flatten** the branching logic. The `if` statement then reads almost like plain English. In contrast to many other languages, creating variables is a computationally *cheap* operation in Python and also helps to document the code *inline* with meaningful variable names.\n", + "A way to make this code more readable is to introduce **temporary variables** *in combination* with the `and` operator to **flatten** the branching logic. The `if` statement then reads almost like plain English. In contrast to many other languages, creating variables is a computationally *cheap* operation in Python (i.e., only a reference is created) and also helps to document the code *inline* with meaningful variable names.\n", "\n", "Flattening the logic *without* temporary variables could lead to *more* sub-expressions in the conditions be evaluated than necessary. Do you see why?" ] }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 73, "metadata": { "slideshow": { "slide_type": "skip" @@ -2030,7 +2398,7 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 74, "metadata": { "slideshow": { "slide_type": "slide" @@ -2041,25 +2409,24 @@ "name": "stdout", "output_type": "stream", "text": [ - "4 is even\n" + "6 can be divided by 2 without a rest\n" ] } ], "source": [ - "signed_number = random.choice([-1, +1]) * random.choice(numbers)\n", + "number = random.choice(numbers)\n", "\n", - "check_oddness = random.random() > 0.5\n", - "is_odd = signed_number % 2\n", - "is_positive = signed_number > 0\n", + "coin_is_heads = random.random() > 0.5\n", + "number_is_even = number % 2 == 0\n", "\n", - "if check_oddness and is_odd:\n", - " print(signed_number, \"is odd\")\n", - "elif check_oddness and not is_odd:\n", - " print(signed_number, \"is even\")\n", - "elif not check_oddness and is_positive:\n", - " print(signed_number, \"is positive\")\n", + "if coin_is_heads and number_is_even:\n", + " print(number, \"can be divided by 2 without a rest\")\n", + "elif coin_is_heads and not number_is_even:\n", + " print(number, \"divided by 2 results in a non-zero rest\")\n", + "elif not coin_is_heads and number_is_even:\n", + " print(number, \"is even\")\n", "else:\n", - " print(signed_number, \"is negative\")" + " print(number, \"is odd\")" ] }, { @@ -2098,24 +2465,11 @@ "y = f(x) =\n", "\\begin{cases}\n", "0, \\text{ if } x \\le 0 \\\\\n", - "x^2, \\text{ otherwise}\n", + "x, \\text{ otherwise}\n", "\\end{cases}\n", "$" ] }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "x = 3" - ] - }, { "cell_type": "markdown", "metadata": { @@ -2129,41 +2483,32 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 75, "metadata": { "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "if x <= 0:\n", - " y = 0\n", - "else:\n", - " y = x ** 2" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": { - "slideshow": { - "slide_type": "-" + "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ - "9" + "3" ] }, - "execution_count": 66, + "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "x = 3\n", + "\n", + "if x <= 0:\n", + " y = 0\n", + "else:\n", + " y = x\n", + "\n", "y" ] }, @@ -2180,38 +2525,29 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 76, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], - "source": [ - "y = 0 if x <= 0 else x ** 2" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, "outputs": [ { "data": { "text/plain": [ - "9" + "3" ] }, - "execution_count": 68, + "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "x = 3\n", + "\n", + "y = 0 if x <= 0 else x\n", + "\n", "y" ] }, @@ -2228,38 +2564,29 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 77, "metadata": { "slideshow": { "slide_type": "fragment" } }, - "outputs": [], - "source": [ - "y = max(0, x) ** 2" - ] - }, - { - "cell_type": "code", - "execution_count": 70, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, "outputs": [ { "data": { "text/plain": [ - "9" + "3" ] }, - "execution_count": 70, + "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "x = 3\n", + "\n", + "y = max(0, x)\n", + "\n", "y" ] }, @@ -2282,16 +2609,14 @@ } }, "source": [ - "In the previous two chapters, we encountered a couple of *runtime* errors. A natural urge we might have after reading about conditional statements is to write code that somehow reacts to the occurrence of such exceptions. All we need is a way to formulate a condition for that.\n", + "In the previous two chapters, we encountered a couple of *runtime* errors. A natural urge we might have after reading about conditional statements is to write code that somehow reacts to the occurrence of such exceptions.\n", "\n", - "For sure, this is such a common thing to do that Python provides a language construct for it, namely the compound `try` statement (cf., [reference](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement)).\n", - "\n", - "In its simplest form, it comes with just two clauses: `try` and `except`. The following tells Python to execute the code in the `try`-clause, and if *anything* goes wrong, continue in the `except`-clause instead of **raising** an error to us. Of course, if nothing goes wrong, the `except`-clause is *not* executed." + "Consider a situation where we are given some user input that may contain values that cause problems. To illustrate this, we draw a random integer between `0` and `5`, and then divide by this number. Naturally, we see a `ZeroDivisionError` in 16.6% of the cases." ] }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 78, "metadata": { "slideshow": { "slide_type": "skip" @@ -2304,7 +2629,60 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 79, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "ename": "ZeroDivisionError", + "evalue": "division by zero", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0muser_input\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mchoice\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;36m1\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0muser_input\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero" + ] + } + ], + "source": [ + "user_input = random.choice([0, 1, 2, 3, 4, 5])\n", + "\n", + "1 / user_input" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "With the compound `try` statement (cf., [reference](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement)), we can **handle** any *runtime* error.\n", + "\n", + "In its simplest form, it comes with just two clauses: `try` and `except`. The following tells Python to execute the code in the `try`-clause, and if *anything* goes wrong, continue in the `except`-clause instead of **raising** an error to us. Of course, if nothing goes wrong, the `except`-clause is *not* executed." + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "random.seed(123)" + ] + }, + { + "cell_type": "code", + "execution_count": 81, "metadata": { "slideshow": { "slide_type": "slide" @@ -2320,10 +2698,10 @@ } ], "source": [ - "user_input = random.choice([0, 1])\n", + "user_input = random.choice([0, 1, 2, 3, 4, 5])\n", "\n", "try:\n", - " 1 / user_input\n", + " print(\"The result is\", 1 / user_input)\n", "except:\n", " print(\"Something went wrong\")" ] @@ -2336,7 +2714,7 @@ } }, "source": [ - "However, it is good practice *not* to **handle** *any* possible exception but only the ones we may *expect* from the code in the `try`-clause. The reason for that is that we do not want to risk *suppressing* an exception that we do *not* expect. Also, the code base becomes easier to understand as we communicate what could go wrong during execution in an *explicit* way to the (human) reader. Python comes with a lot of [built-in exceptions](https://docs.python.org/3/library/exceptions.html#concrete-exceptions) that we should familiarize ourselves with.\n", + "However, it is good practice *not* to handle *any* possible exception but only the ones we may *expect* from the code in the `try`-clause. The reason for that is that we do not want to risk *suppressing* an exception that we do *not* expect. Also, the code base becomes easier to understand as we communicate what could go wrong during execution in an *explicit* way to the (human) reader. Python comes with a lot of [built-in exceptions](https://docs.python.org/3/library/exceptions.html#concrete-exceptions) that we should familiarize ourselves with.\n", "\n", "Another good practice is to always keep the code in the `try`-clause short to not *accidentally* handle an exception we do *not* want to handle.\n", "\n", @@ -2345,7 +2723,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 82, "metadata": { "slideshow": { "slide_type": "skip" @@ -2358,7 +2736,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 83, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2374,10 +2752,10 @@ } ], "source": [ - "user_input = random.choice([0, 1])\n", + "user_input = random.choice([0, 1, 2, 3, 4, 5])\n", "\n", "try:\n", - " 1 / user_input\n", + " print(\"The result is\", 1 / user_input)\n", "except ZeroDivisionError:\n", " print(\"Something went wrong\")" ] @@ -2399,7 +2777,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 84, "metadata": { "slideshow": { "slide_type": "skip" @@ -2412,7 +2790,7 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 85, "metadata": { "slideshow": { "slide_type": "slide" @@ -2429,14 +2807,14 @@ } ], "source": [ - "user_input = random.choice([0, 1])\n", + "user_input = random.choice([0, 1, 2, 3, 4, 5])\n", "\n", "try:\n", - " 1 / user_input\n", + " result = 1 / user_input\n", "except ZeroDivisionError:\n", " print(\"Oops. Division by 0. How does that work?\")\n", "else:\n", - " print(\"Yes, division worked smoothly.\")\n", + " print(\"The result is\", result)\n", "finally:\n", " print(\"I am always printed\")" ] diff --git a/03_conditionals_01_review.ipynb b/03_conditionals_01_review.ipynb index cd56223..5a5da9d 100644 --- a/03_conditionals_01_review.ipynb +++ b/03_conditionals_01_review.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", "# Chapter 3: Conditionals & Exceptions" ] }, @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb) of the book. Then, work through the questions below." + "The questions below assume that you have read [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb) in the book.\n", + "\n", + "Be concise in your answers! Most questions can be answered in *one* sentence." ] }, { @@ -29,13 +30,6 @@ "### Essay Questions " ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Answer the following questions *briefly*!" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -47,7 +41,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -61,7 +55,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -75,7 +69,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -89,7 +83,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -103,7 +97,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -129,7 +123,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -159,7 +153,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -173,7 +167,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] } ], diff --git a/03_conditionals_02_exercises.ipynb b/03_conditionals_02_exercises.ipynb index ac4acd1..510b8cb 100644 --- a/03_conditionals_02_exercises.ipynb +++ b/03_conditionals_02_exercises.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", "# Chapter 3: Conditionals & Exceptions" ] }, @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb) of the book. Then, work through the exercises below. The `...` indicate where you need to fill in your answers. You should not need to create any additional code cells." + "The exercises below assume that you have read [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb) in the book.\n", + "\n", + "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." ] }, { @@ -49,8 +50,28 @@ "metadata": {}, "outputs": [], "source": [ - "def discounted_price(...):\n", - " ..." + "def discounted_price(unit_price, quantity):\n", + " \"\"\"Calculate the price of a line item in an order.\n", + "\n", + " Args:\n", + " unit_price (float): price of one ordered item\n", + " quantity (int): number of items ordered\n", + "\n", + " Returns:\n", + " line_item_price (float)\n", + " \"\"\"\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " return ..." ] }, { @@ -143,7 +164,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -182,9 +203,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q2.2**: Loop over the `numbers` list and replace numbers for which one of the two (or both) conditions apply with text strings `\"Fizz\"`, `\"Buzz\"`, or `\"FizzBuzz\"` using the indexing operator `[]` and the assignment statement `=`.\n", + "**Q2.2**: Loop over the `numbers` list and *replace* numbers for which one of the two (or both) conditions apply with text strings `\"Fizz\"`, `\"Buzz\"`, or `\"FizzBuzz\"` using the indexing operator `[]` and the assignment statement `=`.\n", "\n", - "In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb), we saw that Python starts indexing with `0` as the first element. Keep that in mind.\n", + "In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Who-am-I?-And-how-many?), we saw that Python starts indexing with `0` as the first element. Keep that in mind.\n", "\n", "So in each iteration of the `for`-loop, you have to determine an `index` variable as well as check the actual `number` for its divisors.\n", "\n", @@ -198,6 +219,13 @@ "outputs": [], "source": [ "for number in numbers:\n", + " ...\n", + "\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", " ..." ] }, diff --git a/04_iteration_00_lecture.ipynb b/04_iteration_00_lecture.ipynb index 61858c5..cba0152 100644 --- a/04_iteration_00_lecture.ipynb +++ b/04_iteration_00_lecture.ipynb @@ -1,5 +1,53 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A **video presentation** of the contents in this chapter is shown below. A playlist with *all* chapters as videos is linked [here](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChALCAgOCggIDRYNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxgVERUWFxcYExMYGBgVFRgWFRYWGBcVGxIaEhMXFRoYGBISFRcVFRUVFRUVFRUVGBUSFxIVFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAgIDAQEAAAAAAAAAAAAABgcFCAIDBAEJ/8QAURAAAQQBAgMBCQgRAgUEAgMAAQACAwQRBRIGEyExBxQYIjJBVZTVCBUXUVJhk9QjMzVCU1RxcnN0dYGSsbKz05G0FiQ2YrU0gqGiY3YlQ0X/xAAcAQEAAgMBAQEAAAAAAAAAAAAAAgQBAwUHBgj/xAA9EQABAwIDBQUGBAYBBQEAAAABAAIRAyEEEjEFQVFhcRMVU4GRBiIyocHwFjRysRQ1QlLR4fEjM0NigpL/2gAMAwEAAhEDEQA/ANMkREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXF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hodQ0EBkkco21dQ8qJ4e0HOodmWhZBgrB0X6DItAPDV4q9H8P+q6j7RTw1eKvR/D/quo+0VhZW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/682q/aJ/0Mn9DloT4avFXo/h/1XUfaK4WPdo8UvY9hoaBh7XNOKuo5w4EHGdR7eqItaURERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERf/2Q==\n", + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo(\"jT6hr4vOJks\", width=\"60%\")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -98,7 +146,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "code_folding": [], "slideshow": { @@ -113,7 +161,7 @@ " Args:\n", " n (int): seconds until the party begins\n", " \"\"\"\n", - " if n == 0: # = base case\n", + " if n == 0:\n", " print(\"Happy New Year!\")\n", " else:\n", " print(n)\n", @@ -122,7 +170,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "slide" @@ -226,7 +274,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "code_folding": [], "slideshow": { @@ -244,7 +292,7 @@ " Returns:\n", " factorial (int)\n", " \"\"\"\n", - " if n == 0: # = base case\n", + " if n == 0:\n", " return 1\n", " else:\n", " recurse = factorial(n - 1)\n", @@ -267,7 +315,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "slideshow": { "slide_type": "slide" @@ -280,7 +328,7 @@ "6" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -291,7 +339,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "slideshow": { "slide_type": "skip" @@ -304,7 +352,7 @@ "3628800" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -328,7 +376,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "slideshow": { "slide_type": "slide" @@ -345,14 +393,14 @@ " Returns:\n", " factorial (int)\n", " \"\"\"\n", - " if n == 0: # = base case\n", + " if n == 0:\n", " return 1\n", " return n * factorial(n - 1)" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "slideshow": { "slide_type": "slide" @@ -365,7 +413,7 @@ "6" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -376,7 +424,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "slideshow": { "slide_type": "skip" @@ -389,7 +437,7 @@ "3628800" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -411,7 +459,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "slideshow": { "slide_type": "skip" @@ -424,7 +472,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": { "slideshow": { "slide_type": "skip" @@ -451,7 +499,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": { "slideshow": { "slide_type": "skip" @@ -464,7 +512,7 @@ "6" ] }, - "execution_count": 11, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -475,7 +523,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": { "slideshow": { "slide_type": "skip" @@ -488,7 +536,7 @@ "3628800" ] }, - "execution_count": 12, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -521,7 +569,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": { "slideshow": { "slide_type": "slide" @@ -539,14 +587,14 @@ " Returns:\n", " gcd (int)\n", " \"\"\"\n", - " if b == 0: # = base case\n", + " if b == 0:\n", " return a \n", " return gcd(b, a % b)" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": { "slideshow": { "slide_type": "slide" @@ -559,7 +607,7 @@ "4" ] }, - "execution_count": 14, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -581,7 +629,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": { "slideshow": { "slide_type": "fragment" @@ -594,7 +642,7 @@ "9" ] }, - "execution_count": 15, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -616,7 +664,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": { "slideshow": { "slide_type": "fragment" @@ -629,7 +677,7 @@ "1" ] }, - "execution_count": 16, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -651,7 +699,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": { "slideshow": { "slide_type": "skip" @@ -676,7 +724,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "metadata": { "slideshow": { "slide_type": "skip" @@ -689,37 +737,13 @@ "4" ] }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "math.gcd(12, 4)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "9" - ] - }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "math.gcd(112233445566778899, 987654321)" + "math.gcd(12, 4)" ] }, { @@ -734,7 +758,7 @@ { "data": { "text/plain": [ - "1" + "9" ] }, "execution_count": 20, @@ -742,6 +766,30 @@ "output_type": "execute_result" } ], + "source": [ + "math.gcd(112233445566778899, 987654321)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "math.gcd(7, 7919)" ] @@ -792,7 +840,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": { "slideshow": { "slide_type": "fragment" @@ -809,16 +857,16 @@ " Returns:\n", " ith_fibonacci (int)\n", " \"\"\"\n", - " if i == 0: # = first base case\n", + " if i == 0:\n", " return 0\n", - " elif i == 1: # = second base case\n", + " elif i == 1:\n", " return 1\n", " return fibonacci(i - 1) + fibonacci(i - 2)" ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": { "slideshow": { "slide_type": "slide" @@ -831,7 +879,7 @@ "144" ] }, - "execution_count": 22, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -863,14 +911,14 @@ "\n", "To understand this in detail, we have to study algorithms and data structures (e.g., with [this book](https://www.amazon.de/Introduction-Algorithms-Press-Thomas-Cormen/dp/0262033844/ref=sr_1_1?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=1JNE8U0VZGU0O&qid=1569837169&s=gateway&sprefix=algorithms+an%2Caps%2C180&sr=8-1)), a discipline within computer science, and dive into the analysis of **[time complexity of algorithms](https://en.wikipedia.org/wiki/Time_complexity)**.\n", "\n", - "Luckily, in the Fibonacci case, the inefficiency can be resolved with a **caching** (i.e., \"reuse\") strategy from the field of **[dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming)**, namely **[memoization](https://en.wikipedia.org/wiki/Memoization)**. We do so in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb#Memoization), after introducing the `dict` data type.\n", + "Luckily, in the Fibonacci case, the inefficiency can be resolved with a **caching** (i.e., \"reuse\") strategy from the field of **[dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming)**, namely **[memoization](https://en.wikipedia.org/wiki/Memoization)**. We do so in [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_lecture.ipynb#Memoization), after introducing the `dict` data type.\n", "\n", "Let's measure the average run times for `fibonacci()` and varying `i` arguments with the `%%timeit` [cell magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit) that comes with Jupyter." ] }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, "metadata": { "slideshow": { "slide_type": "slide" @@ -881,7 +929,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "35.2 µs ± 971 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + "70.9 µs ± 22.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], @@ -890,28 +938,6 @@ "fibonacci(12)" ] }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "11.2 ms ± 81.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" - ] - } - ], - "source": [ - "%%timeit -n 100\n", - "fibonacci(24)" - ] - }, { "cell_type": "code", "execution_count": 25, @@ -925,7 +951,29 @@ "name": "stdout", "output_type": "stream", "text": [ - "3.67 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + "11.3 ms ± 31.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit -n 100\n", + "fibonacci(24)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.65 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" ] } ], @@ -936,7 +984,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": { "slideshow": { "slide_type": "skip" @@ -947,7 +995,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "5.94 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + "5.9 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" ] } ], @@ -982,7 +1030,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 28, "metadata": { "slideshow": { "slide_type": "slide" @@ -997,7 +1045,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 29, "metadata": { "slideshow": { "slide_type": "slide" @@ -1011,10 +1059,10 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mrun_forever\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"\"\"Also a pointless function should have a docstring.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mrun_forever\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"\"\"Also a pointless function should have a docstring.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "... last 1 frames repeated, from the frame below ...\n", - "\u001b[0;32m\u001b[0m in \u001b[0;36mrun_forever\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"\"\"Also a pointless function should have a docstring.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mrun_forever\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"\"\"Also a pointless function should have a docstring.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mrun_forever\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded" ] } @@ -1036,7 +1084,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 30, "metadata": { "slideshow": { "slide_type": "slide" @@ -4010,10 +4058,10 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mcountdown\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mcountdown\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "... last 1 frames repeated, from the frame below ...\n", - "\u001b[0;32m\u001b[0m in \u001b[0;36mcountdown\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mcountdown\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded while calling a Python object" ] } @@ -4035,7 +4083,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 31, "metadata": { "slideshow": { "slide_type": "slide" @@ -4049,10 +4097,10 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# = base case\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "... last 1 frames repeated, from the frame below ...\n", - "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# = base case\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded in comparison" ] } @@ -4069,94 +4117,35 @@ } }, "source": [ - "The infinite recursions could easily be avoided by replacing `n == 0` with `n <= 0` in both functions and thereby **generalizing** them. But even then, calling either `countdown()` or `factorial()` with a non-integer number is *semantically* wrong, and, therefore, we better leave the base cases unchanged.\n", - "\n", - "Errors as above are a symptom of missing **type checking**: By design, Python allows us to pass in not only integers but objects of any type as arguments to the `countdown()` and `factorial()` functions. As long as the arguments \"behave\" like integers, we do not encounter any *runtime* errors. This is the case here as the two example functions only use the `-` and `*` operators internally, and, in the context of arithmetic, a `float` object behaves like an `int` object. So, the functions keep calling themselves until Python decides with a built-in heuristic that the recursion is likely not going to end and aborts the computations with a `RecursionError`. Strictly speaking, a `RecursionError` is, of course, a *runtime* error as well.\n", + "The infinite recursions could easily be avoided by replacing `n == 0` with `n <= 0` in both functions and thereby **generalizing** them. However, even then, calling either `countdown()` or `factorial()` with a non-integer number is still *semantically* wrong.\n", "\n", + "Errors as above are a symptom of missing **type checking**: By design, Python allows us to pass in not only integers but objects of any type as arguments to the `countdown()` and `factorial()` functions. As long as the arguments \"behave\" like integers, we do not encounter any *runtime* errors. This is the case here as the two example functions only use the `-` and `*` operators internally, and, in the context of arithmetic, a `float` object behaves like an `int` object. So, the functions keep calling themselves until Python decides with a built-in heuristic that the recursion is likely not going to end and aborts the computations with a `RecursionError`. Strictly speaking, a `RecursionError` is, of course, a *runtime* error as well." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Duck Typing" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ "The missing type checking is *100% intentional* and considered a **[feature of rather than a bug](https://www.urbandictionary.com/define.php?term=It%27s%20not%20a%20bug%2C%20it%27s%20a%20feature)** in Python!\n", "\n", - "Pythonistas often use the colloquial term **[duck typing](https://en.wikipedia.org/wiki/Duck_typing)** when referring to the same idea, and the saying goes, \"If it walks like a duck and it quacks like a duck, it must be a duck.\" For example, we could call `factorial()` with the `float` object `3.0`, and the recursion works out fine. So, as long as the `3.0` \"walks\" like a `3` and \"quacks\" like a `3`, it \"must be\" a `3`.\n", + "Pythonistas use the \"technical\" term **[duck typing](https://en.wikipedia.org/wiki/Duck_typing)** to express the idea of two objects of *different* types behaving in the *same* way in a given context. The colloquial saying goes, \"If it walks like a duck and it quacks like a duck, it must be a duck.\"\n", "\n", - "We see similar behavior when we mix objects of types `int` and `float` with arithmetic operators. For example, `1 + 2.0` works because Python implicitly views the `1` as a `1.0` at runtime and then knows how to do floating-point arithmetic: Here, the `int` \"walks\" and \"quacks\" like a `float`. Strictly speaking, this is yet another example of operator overloading, whereas duck typing refers to the same behavior when passing arguments to function calls.\n", - "\n", - "The important lesson is that we must expect our functions to be called with objects of *any* type at runtime, as opposed to the one type we had in mind when we defined the function.\n", - "\n", - "Duck typing is possible because Python is a dynamically typed language. On the contrary, in statically typed languages like C, we *must* declare (i.e., \"specify\") the data type of every parameter in a function definition. Then, a `RecursionError` as for `countdown(3.1)` or `factorial(3.1)` above could not occur. For example, if we declared the `countdown()` and `factorial()` functions to only accept `int` objects, calling the functions with a `float` argument would immediately fail *syntactically*. As a downside, we would then lose the ability to call `factorial()` with `3.0`, which is *semantically* correct nevertheless.\n", - "\n", - "So, there is no black or white answer as to which of the two language designs is better. Yet, most professional programmers have strong opinions concerning duck typing, reaching from \"love\" to \"hate.\" This is another example of how programming is a subjective art rather than \"objective\" science. Python's design is probably more appealing to beginners who intuitively regard `3` and `3.0` as interchangeable." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Type Checking & Input Validation" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "We use the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to make sure `factorial()` is called with an `int` object as the argument. We further **validate the input** by verifying that the integer is non-negative.\n", - "\n", - "Meanwhile, we also see how we manually raise exceptions with the `raise` statement (cf., [reference](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement)), another way of controlling the flow of execution.\n", - "\n", - "The first two branches in the revised `factorial()` function act as **guardians** ensuring that the code does not produce *unexpected* runtime errors: Errors may be expected when mentioned in the docstring.\n", - "\n", - "Forcing `n` to be an `int` is a very puritan way of handling the issues discussed above. A more relaxed approach could be to also accept a `float` and use its [is_integer()](https://docs.python.org/3/library/stdtypes.html#float.is_integer) method to check if `n` could be cast as an `int`. After all, being too puritan, we cannot take advantage of duck typing.\n", - "\n", - "So, in essence, we are doing *two* things here: Besides checking the type, we also enforce **domain-specific** (i.e., mathematical here) rules concerning the non-negativity of `n`." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "def factorial(n):\n", - " \"\"\"Calculate the factorial of a number.\n", - "\n", - " Args:\n", - " n (int): number to calculate the factorial for; must be positive\n", - "\n", - " Returns:\n", - " factorial (int)\n", - "\n", - " Raises:\n", - " TypeError: if n is not an integer\n", - " ValueError: if n is negative\n", - " \"\"\"\n", - " if not isinstance(n, int):\n", - " raise TypeError(\"Factorial is only defined for integers\")\n", - " elif n < 0:\n", - " raise ValueError(\"Factorial is not defined for negative integers\")\n", - " elif n == 0: # = base case\n", - " return 1\n", - " return n * factorial(n - 1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The revised `factorial()` function works like the old one." + "For example, we could call `factorial()` with the `float` object `3.0`, and the recursion works out fine. So, because the `3.0` \"walks\" and \"quacks\" like a `3`, it \"must be\" a `3`." ] }, { @@ -4171,7 +4160,7 @@ { "data": { "text/plain": [ - "1" + "6.0" ] }, "execution_count": 32, @@ -4180,7 +4169,7 @@ } ], "source": [ - "factorial(0)" + "factorial(3.0)" ] }, { @@ -4215,12 +4204,205 @@ } }, "source": [ - "Instead of running into a situation of infinite recursion, we now receive specific error messages." + "We see similar behavior when we mix objects of types `int` and `float` with arithmetic operators. For example, `1 + 2.0` works because Python implicitly views the `1` as a `1.0` at runtime and then knows how to do floating-point arithmetic: Here, the `int` \"walks\" and \"quacks\" like a `float`." ] }, { "cell_type": "code", "execution_count": 34, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3.0" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 + 2.0" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3.0" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1.0 + 2.0" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The important lesson is that we must expect our functions to be called with objects of *any* type at runtime, as opposed to the one type we had in mind when defining the function.\n", + "\n", + "Duck typing is possible because Python is a dynamically typed language. On the contrary, in statically typed languages like C, we *must* declare (i.e., \"specify\") the data type of every parameter in a function definition. Then, a `RecursionError` as for `countdown(3.1)` or `factorial(3.1)` above could not occur. For example, if we declared the `countdown()` and `factorial()` functions to only accept `int` objects, calling the functions with a `float` argument would immediately fail *syntactically*. As a downside, we would then lose the ability to call `factorial()` with `3.0`, which is *semantically* correct nevertheless.\n", + "\n", + "So, there is no black or white answer as to which of the two language designs is better. Yet, most professional programmers have strong opinions concerning duck typing, reaching from \"love\" to \"hate.\" This is another example of how programming is a subjective art rather than \"objective\" science. Python's design is probably more appealing to beginners who intuitively regard `3` and `3.0` as interchangeable." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Type Checking & Input Validation" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "We use the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to make sure `factorial()` is called with an `int` object as the argument. We further **validate** the **input** by verifying that the integer is non-negative.\n", + "\n", + "Meanwhile, we also see how we manually raise exceptions with the `raise` statement (cf., [reference](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement)), another way of controlling the flow of execution.\n", + "\n", + "The first two branches in the revised `factorial()` function act as **guardians** ensuring that the code does not produce *unexpected* runtime errors: Errors may be expected when mentioned in the docstring.\n", + "\n", + "So, in essence, we are doing *two* things here: Besides checking the type, we also enforce **domain-specific** (i.e., mathematical here) rules concerning the non-negativity of `n`." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for; must be positive\n", + "\n", + " Returns:\n", + " factorial (int)\n", + "\n", + " Raises:\n", + " TypeError: if n is not an integer\n", + " ValueError: if n is negative\n", + " \"\"\"\n", + " if not isinstance(n, int):\n", + " raise TypeError(\"Factorial is only defined for integers\")\n", + " elif n < 0:\n", + " raise ValueError(\"Factorial is not defined for negative integers\")\n", + " elif n == 0:\n", + " return 1\n", + " return n * factorial(n - 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The revised `factorial()` function works like the old one." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Instead of running into a situation of infinite recursion, we now receive specific error messages." + ] + }, + { + "cell_type": "code", + "execution_count": 39, "metadata": { "slideshow": { "slide_type": "slide" @@ -4234,8 +4416,8 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[1;32m 14\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 16\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[1;32m 14\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 16\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mTypeError\u001b[0m: Factorial is only defined for integers" ] } @@ -4246,7 +4428,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 40, "metadata": { "slideshow": { "slide_type": "slide" @@ -4260,8 +4442,8 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m42\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# = base case\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m42\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mValueError\u001b[0m: Factorial is not defined for negative integers" ] } @@ -4270,6 +4452,436 @@ "factorial(-42)" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Forcing `n` to be an `int` is a very puritan way of handling the issues discussed above. So, we can *not* call `factorial()` with, for example, `3.0`." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "Factorial is only defined for integers", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[1;32m 14\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 16\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: Factorial is only defined for integers" + ] + } + ], + "source": [ + "factorial(3.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Type Casting" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A similar way to prevent an infinite recursion is to **cast** the **type** of the `n` argument with the built-in [int()](https://docs.python.org/3/library/functions.html#int) constructor." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for; must be positive\n", + "\n", + " Returns:\n", + " factorial (int)\n", + "\n", + " Raises:\n", + " TypeError: if n cannot be cast as an integer\n", + " ValueError: if n is negative\n", + " \"\"\"\n", + " n = int(n)\n", + " if n < 0:\n", + " raise ValueError(\"Factorial is not defined for negative integers\")\n", + " elif n == 0:\n", + " return 1\n", + " return n * factorial(n - 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The not so strict type casting implements duck typing for `factorial()` as, for example, `3.0` \"walks\" and \"quacks\" like a `3`." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "However, if we now call `factorial()` with a non-integer `float` object like `3.1`, *no* error is raised. This is a potential source for *semantic* errors as the function runs for invalid input." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "We could adjust the type casting logic such that a `TypeError` is raised for `n` arguments with non-zero decimals. " + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "code_folding": [], + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for; must be positive\n", + "\n", + " Returns:\n", + " factorial (int)\n", + "\n", + " Raises:\n", + " TypeError: if n cannot be cast as an integer\n", + " ValueError: if n is negative\n", + " \"\"\"\n", + " if n != int(n):\n", + " raise TypeError(\"n is not integer-like; it has non-zero decimals\")\n", + " n = int(n)\n", + "\n", + " if n < 0:\n", + " raise ValueError(\"Factorial is not defined for negative integers\")\n", + " elif n == 0:\n", + " return 1\n", + " return n * factorial(n - 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "n is not integer-like; it has non-zero decimals", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[1;32m 14\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not integer-like; it has non-zero decimals\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 16\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: n is not integer-like; it has non-zero decimals" + ] + } + ], + "source": [ + "factorial(3.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "However, using built-in constructors for type casting leads to another subtle inconsistency. As constructors are designed to take *any* object as their argument, they do not raise a `TypeError` when called with invalid input but a `ValueError` instead. So, if we, for example, called `factorial()` with `\"text\"` as the `n` argument, we see the `ValueError` raised by [int()](https://docs.python.org/3/library/functions.html#int) in a situation where a `TypeError` would be more appropriate." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "invalid literal for int() with base 10: 'text'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"text\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mnegative\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[0;32m---> 14\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 15\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not integer-like; it has non-zero decimals\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: 'text'" + ] + } + ], + "source": [ + "factorial(\"text\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "We could, of course, use a `try` statement to suppress the exceptions raised by [int()](https://docs.python.org/3/library/functions.html#int) and replace them with a custom `TypeError`. However, now the implementation as a whole is more about type checking than about the actual logic solving the problem. We took this example to the extreme on purpose. In practice, we rarely see such code!" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "def factorial(n):\n", + " \"\"\"Calculate the factorial of a number.\n", + "\n", + " Args:\n", + " n (int): number to calculate the factorial for; must be positive\n", + "\n", + " Returns:\n", + " factorial (int)\n", + "\n", + " Raises:\n", + " TypeError: if n cannot be cast as an integer\n", + " ValueError: if n is negative\n", + " \"\"\"\n", + " try:\n", + " casted_n = int(n)\n", + " except ValueError:\n", + " raise TypeError(\"n cannot be casted as an integer\") from None\n", + " else:\n", + " if n != casted_n:\n", + " raise TypeError(\"n is not integer-like; it has non-zero decimals\")\n", + " n = casted_n\n", + "\n", + " if n < 0:\n", + " raise ValueError(\"Factorial is not defined for negative integers\")\n", + " elif n == 0:\n", + " return 1\n", + " return n * factorial(n - 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "n cannot be casted as an integer", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"text\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mcasted_n\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n cannot be casted as an integer\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mcasted_n\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: n cannot be casted as an integer" + ] + } + ], + "source": [ + "factorial(\"text\")" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "n is not integer-like; it has non-zero decimals", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mcasted_n\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not integer-like; it has non-zero decimals\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 21\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcasted_n\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: n is not integer-like; it has non-zero decimals" + ] + } + ], + "source": [ + "factorial(3.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Which way we choose for **hardening** the `factorial()` function depends on the concrete circumstances. If we are the main caller of the function ourselves, we may choose to *not* do any of the approaches at all. After all, we should be able to call our own function in the correct way. The lesson is that just because Python has no static typing, this does *not* mean that we cannot do this \"manually.\" Yet, the idea behind a dynamically typed language is to *not* deal with the types too much at all." + ] + }, { "cell_type": "markdown", "metadata": { @@ -4353,7 +4965,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 53, "metadata": { "code_folding": [], "slideshow": { @@ -4367,16 +4979,7 @@ "\n", " Args:\n", " n (int): seconds until the party begins; must be positive\n", - "\n", - " Raises:\n", - " TypeError: if n is not an integer\n", - " ValueError: if n is not positive\n", " \"\"\"\n", - " if not isinstance(n, int):\n", - " raise TypeError(\"Can only count down with whole numbers\")\n", - " elif n <= 0:\n", - " raise ValueError(\"n must be stricly positive\")\n", - "\n", " while n != 0:\n", " print(n)\n", " n -= 1\n", @@ -4386,7 +4989,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 54, "metadata": { "slideshow": { "slide_type": "slide" @@ -4416,7 +5019,7 @@ } }, "source": [ - "As [PythonTutor](http://pythontutor.com/visualize.html#code=def%20countdown%28n%29%3A%0A%20%20%20%20if%20not%20isinstance%28n,%20int%29%3A%0A%20%20%20%20%20%20%20%20raise%20TypeError%28%22...%22%29%0A%20%20%20%20elif%20n%20%3C%3D%200%3A%0A%20%20%20%20%20%20%20%20raise%20ValueError%28%22...%22%29%0A%0A%20%20%20%20while%20n%20!%3D%200%3A%0A%20%20%20%20%20%20%20%20print%28n%29%0A%20%20%20%20%20%20%20%20n%20-%3D%201%0A%0A%20%20%20%20print%28%22Happy%20new%20Year!%22%29%0A%0Acountdown%283%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows, there is a subtle but essential difference in the way a `while` statement is treated in memory: In short, `while` statements can *not* run into a `RecursionError` as only *one* frame is needed to manage the names. After all, there is only *one* function call to be made. For typical day-to-day applications, this difference is, however, not so important *unless* a problem instance becomes so big that a large (i.e., $> 3.000$) number of recursive calls must be made." + "As [PythonTutor](http://pythontutor.com/visualize.html#code=def%20countdown%28n%29%3A%0A%20%20%20%20while%20n%20!%3D%200%3A%0A%20%20%20%20%20%20%20%20print%28n%29%0A%20%20%20%20%20%20%20%20n%20-%3D%201%0A%0A%20%20%20%20print%28%22Happy%20new%20Year!%22%29%0A%0Acountdown%283%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows, there is a subtle but essential difference in the way a `while` statement is treated in memory: In short, `while` statements can *not* run into a `RecursionError` as only *one* frame is needed to manage the names. After all, there is only *one* function call to be made. For typical day-to-day applications, this difference is, however, not so important *unless* a problem instance becomes so big that a large (i.e., $> 3.000$) number of recursive calls must be made." ] }, { @@ -4445,7 +5048,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 55, "metadata": { "code_folding": [], "slideshow": { @@ -4463,16 +5066,7 @@ "\n", " Returns:\n", " gcd (int)\n", - "\n", - " Raises:\n", - " TypeError: if a or b are not integers\n", - " ValueError: if a or b are not positive\n", " \"\"\"\n", - " if not isinstance(a, int) or not isinstance(b, int):\n", - " raise TypeError(\"Greatest common divisor is only defined for two integers\")\n", - " elif a <= 0 or b <= 0:\n", - " raise ValueError(\"a and b must be strictly positive\")\n", - "\n", " while a != b:\n", " if a > b:\n", " a -= b\n", @@ -4484,7 +5078,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 56, "metadata": { "slideshow": { "slide_type": "slide" @@ -4497,7 +5091,7 @@ "4" ] }, - "execution_count": 39, + "execution_count": 56, "metadata": {}, "output_type": "execute_result" } @@ -4508,7 +5102,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 57, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4521,7 +5115,7 @@ "1" ] }, - "execution_count": 40, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } @@ -4554,7 +5148,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 58, "metadata": { "slideshow": { "slide_type": "slide" @@ -4565,7 +5159,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "5.22 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + "5.18 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" ] } ], @@ -4637,7 +5231,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 59, "metadata": { "code_folding": [], "slideshow": { @@ -4656,16 +5250,7 @@ "\n", " Args:\n", " n (int): a positive number to start the Collatz sequence at\n", - "\n", - " Raises:\n", - " TypeError: if n is not an integer\n", - " ValueError: if n is not positive\n", " \"\"\"\n", - " if not isinstance(n, int):\n", - " raise TypeError(\"non-integers require some advanced math\")\n", - " elif n <= 0:\n", - " raise ValueError(\"n must be stricly positive\")\n", - "\n", " while n != 1:\n", " print(n, end=\" \")\n", " if n % 2 == 0:\n", @@ -4689,7 +5274,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 60, "metadata": { "slideshow": { "slide_type": "slide" @@ -4710,7 +5295,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 61, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4731,7 +5316,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 62, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4752,7 +5337,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 63, "metadata": { "slideshow": { "slide_type": "skip" @@ -4799,7 +5384,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 64, "metadata": { "slideshow": { "slide_type": "slide" @@ -4812,7 +5397,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 65, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4851,7 +5436,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 66, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4879,12 +5464,12 @@ } }, "source": [ - "For sequences of integers, the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in makes the `for` statement even more convenient: It creates a `list`-like object of type `range` that generates integers \"on the fly,\" and we look closely at the underlying effects in memory in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Mapping)." + "For sequences of integers, the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in makes the `for` statement even more convenient: It creates a `list`-like object of type `range` that generates integers \"on the fly,\" and we look closely at the underlying effects in memory in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_lecture.ipynb#Mapping)." ] }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 67, "metadata": { "slideshow": { "slide_type": "slide" @@ -4906,7 +5491,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 68, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4919,7 +5504,7 @@ "range" ] }, - "execution_count": 51, + "execution_count": 68, "metadata": {}, "output_type": "execute_result" } @@ -4941,7 +5526,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 69, "metadata": { "slideshow": { "slide_type": "slide" @@ -4963,7 +5548,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 70, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5021,7 +5606,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 71, "metadata": { "slideshow": { "slide_type": "slide" @@ -5045,7 +5630,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 72, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5058,7 +5643,7 @@ "True" ] }, - "execution_count": 55, + "execution_count": 72, "metadata": {}, "output_type": "execute_result" } @@ -5069,7 +5654,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 73, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5082,7 +5667,7 @@ "False" ] }, - "execution_count": 56, + "execution_count": 73, "metadata": {}, "output_type": "execute_result" } @@ -5104,7 +5689,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 74, "metadata": { "slideshow": { "slide_type": "skip" @@ -5117,7 +5702,7 @@ "[0, 1, 2, 3, 4]" ] }, - "execution_count": 57, + "execution_count": 74, "metadata": {}, "output_type": "execute_result" } @@ -5128,7 +5713,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 75, "metadata": { "slideshow": { "slide_type": "skip" @@ -5141,7 +5726,7 @@ "True" ] }, - "execution_count": 58, + "execution_count": 75, "metadata": {}, "output_type": "execute_result" } @@ -5163,7 +5748,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 76, "metadata": { "slideshow": { "slide_type": "slide" @@ -5196,7 +5781,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 77, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5229,7 +5814,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 78, "metadata": { "slideshow": { "slide_type": "skip" @@ -5262,7 +5847,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 79, "metadata": { "slideshow": { "slide_type": "skip" @@ -5275,7 +5860,7 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 80, "metadata": { "slideshow": { "slide_type": "skip" @@ -5323,7 +5908,7 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 81, "metadata": { "code_folding": [], "slideshow": { @@ -5340,16 +5925,7 @@ "\n", " Returns:\n", " ith_fibonacci (int)\n", - "\n", - " Raises:\n", - " TypeError: if i is not an integer\n", - " ValueError: if i is not positive\n", " \"\"\"\n", - " if not isinstance(i, int):\n", - " raise TypeError(\"i must be an integer\")\n", - " elif i < 0:\n", - " raise ValueError(\"i must be non-negative\")\n", - "\n", " a = 0\n", " b = 1\n", " print(a, b, sep=\" \", end=\" \") # added for didactical purposes\n", @@ -5364,7 +5940,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 82, "metadata": { "slideshow": { "slide_type": "slide" @@ -5384,7 +5960,7 @@ "144" ] }, - "execution_count": 65, + "execution_count": 82, "metadata": {}, "output_type": "execute_result" } @@ -5417,7 +5993,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 83, "metadata": { "slideshow": { "slide_type": "slide" @@ -5437,7 +6013,7 @@ "218922995834555169026" ] }, - "execution_count": 66, + "execution_count": 83, "metadata": {}, "output_type": "execute_result" } @@ -5470,7 +6046,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 84, "metadata": { "slideshow": { "slide_type": "slide" @@ -5486,16 +6062,7 @@ "\n", " Returns:\n", " factorial (int)\n", - "\n", - " Raises:\n", - " TypeError: if n is not an integer\n", - " ValueError: if n is negative\n", " \"\"\"\n", - " if not isinstance(n, int):\n", - " raise TypeError(\"Factorial is only defined for integers\")\n", - " elif n < 0:\n", - " raise ValueError(\"Factorial is not defined for negative integers\")\n", - "\n", " product = 1 # because 0! = 1\n", " for i in range(1, n + 1):\n", " product *= i\n", @@ -5506,7 +6073,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 85, "metadata": { "slideshow": { "slide_type": "slide" @@ -5526,7 +6093,7 @@ "6" ] }, - "execution_count": 68, + "execution_count": 85, "metadata": {}, "output_type": "execute_result" } @@ -5537,7 +6104,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 86, "metadata": { "slideshow": { "slide_type": "skip" @@ -5557,7 +6124,7 @@ "3628800" ] }, - "execution_count": 69, + "execution_count": 86, "metadata": {}, "output_type": "execute_result" } @@ -5612,7 +6179,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 87, "metadata": { "slideshow": { "slide_type": "slide" @@ -5640,7 +6207,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 88, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5693,7 +6260,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 89, "metadata": { "slideshow": { "slide_type": "slide" @@ -5760,7 +6327,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 90, "metadata": { "slideshow": { "slide_type": "slide" @@ -5803,7 +6370,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 91, "metadata": { "slideshow": { "slide_type": "slide" @@ -5841,7 +6408,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 92, "metadata": { "slideshow": { "slide_type": "skip" @@ -5870,7 +6437,7 @@ "cell_type": "markdown", "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "slide" } }, "source": [ @@ -5893,7 +6460,7 @@ "- **filtering**: throw away individual numbers (e.g., statistical outliers in a sample)\n", "- **reducing**: collect individual numbers into summary statistics\n", "\n", - "We study this **map-filter-reduce** paradigm extensively in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#The-Map-Filter-Reduce-Paradigm) after introducing more advanced data types that are needed to work with \"big\" data.\n", + "We study this **map-filter-reduce** paradigm extensively in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_lecture.ipynb) after introducing more advanced data types that are needed to work with \"big\" data.\n", "\n", "Here, we focus on *filtering out* some numbers in a `for`-loop." ] @@ -5919,15 +6486,15 @@ "source": [ "Calculate the sum of all even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` after squaring them and adding `1` to the squares:\n", "\n", - "- **\"all\"** => loop over an iterable\n", - "- **\"even\"** => *filter* out the odd numbers\n", - "- **\"square and add $1$\"** => apply the *map* $y = f(x) = x^2 + 1$\n", - "- **\"sum\"** => *reduce* the remaining and mapped numbers to their sum" + "- \"*all*\" => **loop** over an iterable\n", + "- \"*even*\" => **filter** out the odd numbers\n", + "- \"*square and add $1$*\" => apply the **map** $y = f(x) = x^2 + 1$\n", + "- \"*sum*\" => **reduce** the remaining and mapped numbers to their sum" ] }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 93, "metadata": { "slideshow": { "slide_type": "slide" @@ -5940,7 +6507,7 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 94, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5960,7 +6527,7 @@ "370" ] }, - "execution_count": 77, + "execution_count": 94, "metadata": {}, "output_type": "execute_result" } @@ -6013,34 +6580,21 @@ "source": [ "Calculate the sum of every third and even number in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` after squaring them and adding `1` to the squares:\n", "\n", - "- **\"every\"** => loop over an iterable\n", - "- **\"third\"** => *filter* out all numbers except every third\n", - "- **\"even\"** => *filter* out the odd numbers\n", - "- **\"square and add $1$\"** => apply the *map* $y = f(x) = x^2 + 1$\n", - "- **\"sum\"** => *reduce* the remaining and mapped numbers to their sum" + "- \"*every*\" => **loop** over an iterable\n", + "- \"*third*\" => **filter** out all numbers except every third\n", + "- \"*even*\" => **filter** out the odd numbers\n", + "- \"*square and add $1$*\" => apply the **map** $y = f(x) = x^2 + 1$\n", + "- \"*sum*\" => **reduce** the remaining and mapped numbers to their sum" ] }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 95, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], - "source": [ - "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, "outputs": [ { "name": "stdout", @@ -6055,7 +6609,7 @@ "227" ] }, - "execution_count": 79, + "execution_count": 95, "metadata": {}, "output_type": "execute_result" } @@ -6112,7 +6666,7 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 96, "metadata": { "slideshow": { "slide_type": "slide" @@ -6132,7 +6686,7 @@ "227" ] }, - "execution_count": 80, + "execution_count": 96, "metadata": {}, "output_type": "execute_result" } @@ -6216,7 +6770,7 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 97, "metadata": { "slideshow": { "slide_type": "slide" @@ -6229,10 +6783,10 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 98, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [], @@ -6242,7 +6796,7 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 99, "metadata": { "code_folding": [], "slideshow": { @@ -6353,7 +6907,7 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 100, "metadata": { "slideshow": { "slide_type": "slide" @@ -6390,7 +6944,7 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 101, "metadata": { "slideshow": { "slide_type": "slide" @@ -6428,7 +6982,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 102, "metadata": { "slideshow": { "slide_type": "skip" @@ -6441,7 +6995,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 103, "metadata": { "slideshow": { "slide_type": "slide" diff --git a/04_iteration_01_review.ipynb b/04_iteration_01_review.ipynb index 29c1f2f..283a72a 100644 --- a/04_iteration_01_review.ipynb +++ b/04_iteration_01_review.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", "# Chapter 4: Recursion & Looping" ] }, @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) of the book. Then, work through the questions below." + "The questions below assume that you have read [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) in the book.\n", + "\n", + "Be concise in your answers! Most questions can be answered in *one* sentence." ] }, { @@ -29,13 +30,6 @@ "### Essay Questions " ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Answer the following questions *briefly*!" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -47,7 +41,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -61,7 +55,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -75,7 +69,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -89,7 +83,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -103,7 +97,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -117,7 +111,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -145,7 +139,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -159,7 +153,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -173,7 +167,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -187,7 +181,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -201,7 +195,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -215,7 +209,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -240,7 +234,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] } ], diff --git a/04_iteration_02_exercises.ipynb b/04_iteration_02_exercises.ipynb index ab80178..d795aa5 100644 --- a/04_iteration_02_exercises.ipynb +++ b/04_iteration_02_exercises.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", "# Chapter 4: Recursion & Looping" ] }, @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) of the book. Then, work through the exercises below. The `...` indicate where you need to fill in your answers. You should not need to create any additional code cells. Occasionally, the `...` mean that you have to write more than one line of code." + "The exercises below assume that you have read the \"*Recursion*\" part in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) of the book.\n", + "\n", + "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." ] }, { @@ -95,7 +96,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -109,7 +110,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -123,7 +124,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -137,7 +138,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -151,53 +152,52 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As most likely the first couple of tries will result in *semantic* errors, it is advisable to have some sort of **visualization tool** for the program's output: For example, an online version of the game can be found **[here](https://www.mathsisfun.com/games/towerofhanoi.html)**." + "As most likely the first couple of tries will result in *semantic* errors, it is advisable to have some sort of **visualization tool** for the program's output: For example, an online version of the game can be found [here](https://www.mathsisfun.com/games/towerofhanoi.html)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let's first **generalize** the mathematical relationship from above.\n", + "Let's first **generalize** the mathematical relationship from above and then introduce the variable names used in our `sol()` implementation below.\n", "\n", - "While the first number of $Sol(\\cdot)$ is the number of `disks` $n$, the second and third \"numbers\" are the **labels** for the three spots. Instead of spots `1`, `2`, and `3`, we could also call them `\"left\"`, `\"center\"`, and `\"right\"` in our Python implementation. When \"passed\" to the $Sol(\\cdot)$ \"function\" they take on the role of an `origin` (= $o$) and `destination` (= $d$) pair.\n", + "Unsurprisingly, the recursive relationship in the video may be generalized into:\n", "\n", - "So, the expression $Sol(4, 1, 3)$ is the same as $Sol(4, \\text{\"left\"}, \\text{\"right\"})$ and describes the problem of moving a tower consisting of $n = 4$ disks from `origin` `1` / `\"left\"` to `destination` `3` / `right`. As we have seen in the video, we need some `intermediate` (= $i$) spot." + "$Sol(n, o, d) = Sol(n-1, o, i) ~ \\bigoplus ~ Sol(1, o, d) ~ \\bigoplus ~ Sol(n-1, i, d)$\n", + "\n", + "$Sol(\\cdot)$ takes three \"arguments\" $n$, $o$, and $d$ and is defined with *three* references to itself that take modified versions of $n$, $o$, and $d$ in different orders. The middle reference, Sol(1, o, d), constitutes the \"end\" of the recursive definition: It is the problem of solving Towers of Hanoi for a \"tower\" of only one disk.\n", + "\n", + "While the first \"argument\" of $Sol(\\cdot)$ is a number that we refer to as `n_disks` below, the second and third \"arguments\" are merely **labels** for the spots, and we refer to the **roles** they take in a given problem as `origin` and `destination` below. Instead of labeling individual spots with the numbers `1`, `2`, and `3` as in the video, we may also call them `\"left\"`, `\"center\"`, and `\"right\"`. Both ways are equally correct! So, only the first \"argument\" of $Sol(\\cdot)$ is really a number!\n", + "\n", + "As an example, the notation $Sol(4, 1, 3)$ from above can then be \"translated\" into Python as either the function call `sol(4, 1, 3)` or `sol(4, \"left\", \"right\")`. This describes the problem of moving a tower consisting of `n_disks=4` disks from either the `origin=1` spot to the `destination=3` spot or from the `origin=\"left\"` spot to the `destination=\"right\"` spot.\n", + "\n", + "To adhere to the rules, an `intermediate` spot $i$ is needed. In `sol()` below, this is a temporary variable within a function call and *not* a parameter of the function itself." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "In summary, the generalized functional relationship can be expressed as:\n", + "In summary, to move a tower consisting of `n_disks` (= $n$) disks from an `origin` (= $o$) to a `destination` (= $d$), three steps must be executed:\n", "\n", - "$Sol(n, o, d) = Sol(n-1, o, i) ~ \\bigoplus ~ Sol(1, o, d) ~ \\bigoplus ~ Sol(n-1, i, d)$" + "1. Move the tower's topmost `n_disks - 1` (= $n - 1$) disks from the `origin` (= $o$) to an `intermediate` (= $i$) spot (= **Sub-Problem 1**),\n", + "2. move the remaining and largest disk from the `origin` (= $o$) to the `destination` (= $d$), and\n", + "3. move the `n_disks - 1` (= $n - 1$) disks from the `intermediate` (= $i$) spot to the `destination` (= $d$) spot (= **Sub-Problem 2**).\n", + "\n", + "The two sub-problems themselves are solved via the same *recursive* logic." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "In words, this means that to move a tower consisting of $n$ disks from an `origin` $o$ to a `destination` $d$, three steps must be executed:\n", + "Write your answers to **Q5** to **Q7** into the skeleton of `sol()` below.\n", "\n", - "1. Move the topmost $n - 1$ disks of the tower temporarily from $o$ to $i$ (= sub-problem 1)\n", - "2. Move the remaining and largest disk from $o$ to $d$\n", - "3. Move the the $n - 1$ disks from the temporary spot $i$ to $d$ (= sub-problem 2)\n", + "`sol()` takes three arguments `n_disks`, `origin`, and `destination` that mirror $n$, $o$, and $d$ above.\n", "\n", - "The two sub-problems can be solved via the same recursive logic." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "$Sol(\\cdot)$ can be written in Python as a function `sol()` that takes three arguments `disks`, `origin`, and `destination` that mirror $n$, $o$, and $d$.\n", + "For now, assume that all arguments to `sol()` are `int` objects! We generalize this into real labels further below in the `hanoi()` function.\n", "\n", - "Assume that all arguments to `sol()` are `int` objects!\n", - "\n", - "Once completed, `sol()` should print out all the moves in the correct order. With **printing a move**, we mean a line like \"1 -> 3\", short for \"Move the top-most disk from spot 1 to spot 3\".\n", - "\n", - "Write your answers to **Q5** to **Q7** into the subsequent code cell and finalize `sol()`! No need to write a docstring or validate the input here." + "Once completed, `sol()` should *print* out all the moves in the correct order. For example, *print* `\"1 -> 3\"` to mean \"Move the top-most `n_disks - 1` disks from spot `1` to spot `3`.\"" ] }, { @@ -206,48 +206,74 @@ "metadata": {}, "outputs": [], "source": [ - "def sol(disks, origin, destination):\n", + "def sol(n_disks, origin, destination):\n", + " \"\"\"A naive implementation of Towers of Hanoi.\n", "\n", + " This function prints out the moves to solve a Towers of Hanoi problem.\n", + "\n", + " Args:\n", + " n_disks (int): number of disks in the tower\n", + " origin (int): spot of the tower at the start; 1, 2, or 3\n", + " destination (int): spot of the tower at the end; 1, 2, or 3\n", + " \"\"\"\n", " # answer to Q5\n", - " # ...\n", + " ...\n", + " ...\n", "\n", " # answer to Q6\n", - " # ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", "\n", " # answer to Q7\n", - " # ..." + " ...\n", + " ...\n", + " ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q5**: What is the `disks` argument when the function reaches its **base case**? Check for the base case with a simple `if` statement and return from the function using the **early exit** pattern!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q6**: If not in the base case, `sol()` needs to determine the `intermediate` spot given concrete `origin` and `destination` arguments. For example, if called with `origin=1` and `destination=2`, `intermediate` must be `3`.\n", + "**Q5**: What is the `n_disks` argument when the function reaches its **base case**? Check for the base case with a simple `if` statement and return from the function using the **early exit** pattern!\n", "\n", - "Add **one** compound `if` statement to `sol()` that has a branch for **every** possible `origin`-`destination` pair that sets a variable `intermediate` to the correct temporary spot. **How many** branches will there be?" + "Hint: The base case in the Python implementation may be slightly different than the one shown in the generalized mathematical relationship above!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q7**: `sol()` needs to call itself **two more times** with the correct 2-pairs chosen from the three available spots `origin`, `intermediate`, and `destination`.\n", + "**Q6**: If not in the base case, `sol()` determines the `intermediate` spot given concrete `origin` and `destination` arguments. For example, if called with `origin=1` and `destination=2`, `intermediate` must be `3`.\n", "\n", - "In between the two recursive function calls, write a `print()` statement that prints out from where to where the \"remaining and largest\" disk has to be moved!" + "Add *one* compound `if` statement to `sol()` that has a branch for *every* possible `origin`-`destination`-pair that assigns the correct temporary spot to a variable `intermediate`.\n", + "\n", + "Hint: How many 2-tuples of 3 elements can there be if the order matters?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q8**: Execute the code cells below and confirm that the printed moves are correct!" + "**Q7**: `sol()` calls itself *two* more times with the correct 2-tuples chosen from the three available spots `origin`, `intermediate`, and `destination`.\n", + "\n", + "*In between* the two recursive function calls, use [print()](https://docs.python.org/3/library/functions.html#print) to print out from where to where the \"remaining and largest\" disk has to be moved!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q8**: Execute the code cells below and confirm that the moves are correct!" ] }, { @@ -297,11 +323,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The previous `sol()` implementation does the job, but the conditional statement needed in unnecessarily tedious. \n", + "The previous `sol()` implementation does the job, but the conditional statement is unnecessarily tedious. \n", "\n", - "Let's create a more concise `hanoi()` function that, in addition to a positional `disks` argument, takes three keyword-only arguments `origin`, `intermediate`, and `destination` with default values `\"left\"`, `\"center\"`, and `\"right\"`.\n", + "Let's create a concise `hanoi()` function that, in addition to a positional `n_disks` argument, takes three keyword-only arguments `origin`, `intermediate`, and `destination` with default values `\"left\"`, `\"center\"`, and `\"right\"`.\n", "\n", - "Write your answers to **Q9** and **Q10** into the subsequent code cell and finalize `hanoi()`! No need to write a docstring or validate the input here." + "Write your answers to **Q9** and **Q10** into the subsequent code cell and finalize `hanoi()`!" ] }, { @@ -310,13 +336,25 @@ "metadata": {}, "outputs": [], "source": [ - "def hanoi(disks, *, origin=\"left\", intermediate=\"center\", destination=\"right\"):\n", + "def hanoi(n_disks, *, origin=\"left\", intermediate=\"center\", destination=\"right\"):\n", + " \"\"\"A Pythonic implementation of Towers of Hanoi.\n", "\n", + " This function prints out the moves to solve a Towers of Hanoi problem.\n", + "\n", + " Args:\n", + " n_disks (int): number of disks in the tower\n", + " origin (str, optional): label for the spot of the tower at the start\n", + " intermediate (str, optional): label for the intermediate spot\n", + " destination (str, optional): label for the spot of the tower at the end\n", + " \"\"\"\n", " # answer to Q9\n", - " # ...\n", + " ...\n", + " ...\n", "\n", " # answer to Q10\n", - " # ..." + " ...\n", + " ...\n", + " ..." ] }, { @@ -330,18 +368,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q10**: Instead of conditional logic, `hanoi()` calls itself **two times** with the **three** arguments `origin`, `intermediate`, and `destination` passed on in a **different** order.\n", + "**Q10**: Instead of conditional logic, `hanoi()` calls itself *two* times with the *three* arguments `origin`, `intermediate`, and `destination` passed on in a *different* order.\n", "\n", - "Figure out how the arguments are passed on in the two recursive `hanoi()` calls!\n", + "Figure out how the arguments are passed on in the two recursive `hanoi()` calls and finish `hanoi()`.\n", "\n", - "Also, write a `print()` statement analogous to the one in `sol()` in between the two recursive function calls. Is it ok to copy and paste it?" + "Hint: Do not forget to use [print()](https://docs.python.org/3/library/functions.html#print) to print out the moves!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q11**: Execute the code cells below and confirm that the printed moves are correct!" + "**Q11**: Execute the code cells below and confirm that the moves are correct!" ] }, { @@ -384,7 +422,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We could, of course, also use **numeric labels** for the three steps like so." + "We could, of course, also use *numeric* labels for the three steps like so." ] }, { @@ -400,22 +438,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Passing a Value \"up\" the Recursion Tree" + "#### Passing a Value \"down\" the Recursion Tree" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let's say we did not know about the **analytical formula** for the number of **minimal moves** given $n$.\n", + "The above `hanoi()` prints the optimal solution's moves in the correct order but fails to label each move with an order number. This is built in the `hanoi_ordered()` function below by passing on a \"private\" `_offset` argument \"down\" the recursion tree. The leading underscore `_` in the parameter name indicates that it is *not* to be used by the caller of the function. That is also why the parameter is *not* mentioned in the docstring.\n", "\n", - "In such cases, we could modify a recursive function to return a count value to be passed up the recursion tree.\n", - "\n", - "This is similar to what we do in the recursive versions of `factorial()` and `fibonacci()` in [Chapter 4](https://github.com/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb), where we pass up an intermediate result.\n", - "\n", - "Let's create a `hanoi_moves()` function that follows the same internal logic as `hanoi()`, but, instead of printing out the moves, returns the number of steps done so far in the recursion.\n", - "\n", - "Write your answers to **Q12** to **Q14** into the subsequent code cell and finalize `hanoi_moves()`! No need to write a docstring or validate the input here." + "Write your answers to **Q12** and **Q13** into the subsequent code cell and finalize `hanoi_ordered()`! As the logic gets a bit \"involved,\" `hanoi_ordered()` below is almost finished." ] }, { @@ -424,166 +456,56 @@ "metadata": {}, "outputs": [], "source": [ - "def hanoi_moves(disks, *, origin=\"left\", intermediate=\"center\", destination=\"right\"):\n", + "def hanoi_ordered(n_disks, *, origin=\"left\", intermediate=\"center\", destination=\"right\", _offset=None):\n", + " \"\"\"A Pythonic implementation of Towers of Hanoi.\n", "\n", + " This function prints out the moves to solve a Towers of Hanoi problem.\n", + " Each move is labeled with an order number.\n", + "\n", + " Args:\n", + " n_disks (int): number of disks in the tower\n", + " origin (str, optional): label for the spot of the tower at the start\n", + " intermediate (str, optional): label for the intermediate spot\n", + " destination (str, optional): label for the spot of the tower at the end\n", + " \"\"\"\n", " # answer to Q12\n", - " # ...\n", + " ...\n", + " ...\n", "\n", - " moves = ... # <- answer to Q13\n", - " moves += hanoi_moves(...) # <- answer to Q14 between the ()\n", - " moves += hanoi_moves(...) # <- answer to Q14 between the ()\n", - "\n", - " return moves" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q12**: Copy the base case from `hanoi()`! What count should be returned when it is reached?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q13**: Initialize the variable `moves` with an appropriate count! This is the number of moves that corresponds to **one** recursive function call." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q14**: `moves` is updated with the counts passed up from the two recursive calls.\n", - "\n", - "Complete the two recursive function calls with the same arguments as in `hanoi()`!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q15**: Write a `for`-loop that prints out the **minimum number** of moves needed to solve Towers of Hanoi for any number of `disks` from `1` through `20` to confirm your answer to **Q2**." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for ... in ...:\n", - " ..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Time Complexity" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Observe how quickly the `hanoi_moves()` function slows down for increasing `disks` arguments.\n", - "\n", - "With `disks` in the range from `24` through `26`, the computation time roughly doubles for each increase of `disks` by 1.\n", - "\n", - "**Q16**: Execute the code cells below and see for yourself!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%timeit -n 1 -r 1\n", - "print(\"Number of moves:\", hanoi_moves(24))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%timeit -n 1 -r 1\n", - "print(\"Number of moves:\", hanoi_moves(25))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%timeit -n 1 -r 1\n", - "print(\"Number of moves:\", hanoi_moves(26))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Passing a Value \"down\" the Recursion Tree (Advanced)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The above `hanoi()` prints the optimal solution's moves in the correct order but fails to label each move with an order number. This can be built in by passing on one more argument `offset` down the recursion tree. As the logic gets a bit \"involved,\" `hanoi_ordered()` below is almost finished.\n", - "\n", - "Write your answers to **Q17** and **Q18** into the subsequent code cell and finalize `hanoi_ordered()`! No need to write a docstring or validate the input here." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def hanoi_ordered(disks, *, origin=\"left\", intermediate=\"center\", destination=\"right\", offset=None):\n", - "\n", - " # answer to Q17\n", - " # ...\n", - "\n", - " total = (2 ** disks - 1)\n", - " half = (2 ** (disks - 1) - 1)\n", + " total = (2 ** n_disks - 1)\n", + " half = (2 ** (n_disks - 1) - 1)\n", " count = total - half\n", "\n", - " if offset is not None:\n", - " count += offset\n", + " if _offset is not None:\n", + " count += _offset\n", "\n", - " hanoi_ordered(..., offset=offset) # <- answer to Q18\n", - " # ... <- answer to Q18\n", - " hanoi_ordered(..., offset=count) # <- answer to Q18" + " # answer to Q18\n", + " hanoi_ordered(..., _offset=_offset)\n", + " ...\n", + " hanoi_ordered(..., _offset=count)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q17**: Copy the base case from the original `hanoi()`!" + "**Q12**: Copy the base case from the original `hanoi()`!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q18**: Complete the two recursive function calls with the same arguments as in `hanoi()` or `hanoi_moves()`! Do not change the already filled in `offset` arguments!\n", + "**Q13**: Complete the two recursive function calls with the same arguments as in `hanoi()`! Do *not* change the already filled in `offset` arguments!\n", "\n", - "Then, copy the `print()` statement from `hanoi()` and adjust it to print out `count` as well!" + "Then, adjust the use of [print()](https://docs.python.org/3/library/functions.html#print) from above to print out the moves with their order number!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q19**: Execute the code cells below and confirm that the order numbers are correct!" + "**Q14**: Execute the code cells below and confirm that the order numbers are correct!" ] }, { @@ -626,7 +548,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Lastly, it is to be mentioned that for problem instances with a small `disks` argument, it is easier to collect all the moves first in a list and then add the order number with the [enumerate()](https://docs.python.org/3/library/functions.html#enumerate) built-in." + "Lastly, it is to be mentioned that for problem instances with a small `n_disks` argument, it is easier to collect all the moves first in a `list` object and then add the order number with the [enumerate()](https://docs.python.org/3/library/functions.html#enumerate) built-in." ] }, { @@ -640,14 +562,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q20**: Conducting your own research on the internet (max. 15 minutes), what can you say about generalizing the **[Towers of Hanoi](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** problem to a setting with **more than three** landing spots?" + "**Q15**: Conducting your own research on the internet, what can you say about generalizing the **[Towers of Hanoi](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** problem to a setting with *more than three* landing spots?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] } ], diff --git a/04_iteration_03_exercises.ipynb b/04_iteration_03_exercises.ipynb index da32407..7d69c33 100644 --- a/04_iteration_03_exercises.ipynb +++ b/04_iteration_03_exercises.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", "# Chapter 4: Recursion & Looping" ] }, @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) of the book. Then, work through the exercises below. The `...` indicate where you need to fill in your answers. You should not need to create any additional code cells." + "The exercises below assume that you have read the \"*Looping*\" part in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) of the book.\n", + "\n", + "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." ] }, { @@ -264,7 +265,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " ..." + " < your answer >" ] }, { diff --git a/05_numbers_00_lecture.ipynb b/05_numbers_00_lecture.ipynb index 771a0ad..3f0bdb3 100644 --- a/05_numbers_00_lecture.ipynb +++ b/05_numbers_00_lecture.ipynb @@ -1,5 +1,53 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A **video presentation** of the contents in this chapter is shown below. A playlist with *all* chapters as videos is linked [here](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChALCAgOCggIDRYNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxgVERUWFxcYExMYGBgVFRgWFRYWGBcVGxIaEhMXFRoYGBISFRcVFRUVFRUVFRUVGBUSFxIVFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAgIDAQEAAAAAAAAAAAAABgcFCAIDBAEJ/8QAURAAAQQBAgMBCQgRAgUEAgMAAQACAwQRBRIGEyExBxQYIjJBVZTVCBUXUVJhk9QjMzVCU1RxcnN0dYGSsbKz05G0FiQ2YrU0gqGiY3YlQ0X/xAAcAQEAAgMBAQEAAAAAAAAAAAAAAgQBAwUHBgj/xAA9EQABAwIDBQUGBAYBBQEAAAABAAIRAyEEEjEFQVFhcRMVU4GRBiIyocHwFjRysRQ1QlLR4fEjM0NigpL/2gAMAwEAAhEDEQA/ANMkREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXF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hodQ0EBkkco21dQ8qJ4e0HOodmWhZBgrB0X6DItAPDV4q9H8P+q6j7RTw1eKvR/D/quo+0VhZW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/682q/aJ/0Mn9DloT4avFXo/h/1XUfaK4WPdo8UvY9hoaBh7XNOKuo5w4EHGdR7eqItaURERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERf/2Q==\n", + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo(\"nB00WGCnVjg\", width=\"60%\")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -8,7 +56,7 @@ } }, "source": [ - "# Chapter 5: Bits & Numbers" + "# Chapter 5: Numbers & Bits" ] }, { @@ -23,7 +71,7 @@ "\n", "We start with the \"simple\" ones: Numeric types in this chapter and textual data in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb). An important fact that holds for all objects of these types is that they are **immutable**. To reuse the bag analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Objects-vs.-Types-vs.-Values), this means that the $0$s and $1$s making up an object's *value* cannot be changed once the bag is created in memory, implying that any operation with or method on the object creates a *new* object in a *different* memory location.\n", "\n", - "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb), [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb), and [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_arrays_00_lecture.ipynb) then cover the more \"complex\" data types, including, for example, the `list` type. Finally, Chapter 10 completes the picture by introducing language constructs to create custom types.\n", + "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb), [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_lecture.ipynb), and [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_lecture.ipynb) then cover the more \"complex\" data types, including, for example, the `list` type. Finally, Chapter 10 completes the picture by introducing language constructs to create custom types.\n", "\n", "We have already seen many hints indicating that numbers are not as trivial to work with as it seems at first sight:\n", "\n", @@ -60,7 +108,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "slideshow": { "slide_type": "slide" @@ -82,30 +130,6 @@ "Just like any other object, the `42` has an identity, a type, and a value." ] }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "94784085682240" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "id(a)" - ] - }, { "cell_type": "code", "execution_count": 3, @@ -118,7 +142,7 @@ { "data": { "text/plain": [ - "int" + "94381541328960" ] }, "execution_count": 3, @@ -127,7 +151,7 @@ } ], "source": [ - "type(a)" + "id(a)" ] }, { @@ -142,7 +166,7 @@ { "data": { "text/plain": [ - "42" + "int" ] }, "execution_count": 4, @@ -150,6 +174,30 @@ "output_type": "execute_result" } ], + "source": [ + "type(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "42" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "a" ] @@ -167,7 +215,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "slideshow": { "slide_type": "slide" @@ -180,7 +228,7 @@ "1000000" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -202,7 +250,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "slideshow": { "slide_type": "fragment" @@ -215,7 +263,7 @@ "123456789" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -237,7 +285,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "slideshow": { "slide_type": "fragment" @@ -246,10 +294,10 @@ "outputs": [ { "ename": "SyntaxError", - "evalue": "invalid token (, line 1)", + "evalue": "invalid token (, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 042\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid token\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 042\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid token\n" ] } ], @@ -270,7 +318,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "slideshow": { "slide_type": "slide" @@ -283,7 +331,7 @@ "42" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -294,7 +342,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "slideshow": { "slide_type": "fragment" @@ -307,7 +355,7 @@ "42" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -329,7 +377,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": { "slideshow": { "slide_type": "fragment" @@ -342,7 +390,7 @@ "-42" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -364,10 +412,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -377,7 +425,7 @@ "42" ] }, - "execution_count": 11, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -388,10 +436,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -402,7 +450,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"42.0\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"42.0\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: '42.0'" ] } @@ -413,10 +461,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -426,7 +474,7 @@ "42" ] }, - "execution_count": 13, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -448,7 +496,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": { "slideshow": { "slide_type": "skip" @@ -461,7 +509,7 @@ "1" ] }, - "execution_count": 14, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -525,7 +573,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": { "slideshow": { "slide_type": "slide" @@ -538,7 +586,7 @@ "'0b11'" ] }, - "execution_count": 15, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -558,41 +606,6 @@ "We may pass a `str` object formatted this way as the argument to the [int()](https://docs.python.org/3/library/functions.html#int) built-in, together with `base=2`, to create an `int` object, for example, with the value of `3`." ] }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "3" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "int(\"0b11\", base=2)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Moreover, we may also use the contents of the returned `str` object as a **literal** instead: Just like we type, for example, `3` without quotes (i.e., \"literally\") into a code cell to create the `int` object `3`, we may type `0b11` to obtain an `int` object with the same value." - ] - }, { "cell_type": "code", "execution_count": 17, @@ -614,7 +627,7 @@ } ], "source": [ - "0b11" + "int(\"0b11\", base=2)" ] }, { @@ -625,7 +638,7 @@ } }, "source": [ - "It is convenient to use the underscore `_` to separate the `\"0b\"` prefix from the bits." + "Moreover, we may also use the contents of the returned `str` object as a **literal** instead: Just like we type, for example, `3` without quotes (i.e., \"literally\") into a code cell to create the `int` object `3`, we may type `0b11` to obtain an `int` object with the same value." ] }, { @@ -649,7 +662,7 @@ } ], "source": [ - "0b_11" + "0b11" ] }, { @@ -1472,7 +1485,7 @@ } ], "source": [ - "0x_7b" + "0x7b" ] }, { @@ -1491,7 +1504,7 @@ "execution_count": 43, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "slide" } }, "outputs": [ @@ -1515,7 +1528,7 @@ "execution_count": 44, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "fragment" } }, "outputs": [ @@ -1550,7 +1563,7 @@ "execution_count": 45, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "fragment" } }, "outputs": [ @@ -1869,7 +1882,7 @@ "execution_count": 55, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -1893,7 +1906,7 @@ "execution_count": 56, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -1987,7 +2000,7 @@ "execution_count": 59, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -2062,7 +2075,7 @@ "execution_count": 61, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2086,7 +2099,7 @@ "execution_count": 62, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2121,7 +2134,7 @@ "execution_count": 63, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2156,7 +2169,7 @@ "execution_count": 64, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -2180,7 +2193,7 @@ "execution_count": 65, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2204,7 +2217,7 @@ "execution_count": 66, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2239,7 +2252,7 @@ "execution_count": 67, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2274,7 +2287,7 @@ "execution_count": 68, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -2298,7 +2311,7 @@ "execution_count": 69, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2322,7 +2335,7 @@ "execution_count": 70, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2357,7 +2370,7 @@ "execution_count": 71, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2394,7 +2407,7 @@ "execution_count": 72, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -2418,7 +2431,7 @@ "execution_count": 73, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2442,7 +2455,7 @@ "execution_count": 74, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2466,7 +2479,7 @@ "execution_count": 75, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2538,7 +2551,7 @@ "execution_count": 77, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -2562,7 +2575,7 @@ "execution_count": 78, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2586,7 +2599,7 @@ "execution_count": 79, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2610,7 +2623,7 @@ "execution_count": 80, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2645,7 +2658,7 @@ "execution_count": 81, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -2669,7 +2682,7 @@ "execution_count": 82, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2693,7 +2706,7 @@ "execution_count": 83, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2717,7 +2730,7 @@ "execution_count": 84, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2789,7 +2802,7 @@ { "data": { "text/plain": [ - "139663468493296" + "139960518791696" ] }, "execution_count": 86, @@ -3113,7 +3126,7 @@ "execution_count": 97, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -3487,7 +3500,7 @@ } ], "source": [ - "float(\"inf\") # same as float(\"+inf\")" + "float(\"inf\") # also float(\"+inf\")" ] }, { @@ -3836,7 +3849,7 @@ "execution_count": 120, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -3871,7 +3884,7 @@ "execution_count": 121, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -4125,7 +4138,7 @@ } }, "source": [ - "A popular workaround is to benchmark the difference between the two numbers to be checked for equality against a pre-defined `threshold` *sufficiently* close to `0`, for example, `1e-15`." + "A popular workaround is to benchmark the absolute value of the difference between the two numbers to be checked for equality against a pre-defined `threshold` *sufficiently* close to `0`, for example, `1e-15`." ] }, { @@ -4162,7 +4175,7 @@ } ], "source": [ - "(sqrt(2) ** 2) - 2 < threshold" + "abs((sqrt(2) ** 2) - 2) < threshold" ] }, { @@ -4186,7 +4199,7 @@ } ], "source": [ - "(0.1 + 0.2) - 0.3 < threshold" + "abs((0.1 + 0.2) - 0.3) < threshold" ] }, { @@ -5021,7 +5034,7 @@ } ], "source": [ - "Decimal(0.1) # do not do this" + "Decimal(0.1) # do not do this!" ] }, { @@ -5182,7 +5195,7 @@ "execution_count": 166, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -5206,7 +5219,7 @@ "execution_count": 167, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -5241,7 +5254,7 @@ "execution_count": 168, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -5265,7 +5278,7 @@ "execution_count": 169, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -5300,7 +5313,7 @@ "execution_count": 170, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -5436,7 +5449,7 @@ "execution_count": 174, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -5471,7 +5484,7 @@ "execution_count": 175, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -5879,7 +5892,7 @@ } ], "source": [ - "Fraction(1, 3) # 1/3 with \"full\" precision" + "Fraction(1, 3) # 1 / 3 with \"full\" precision" ] }, { @@ -5903,7 +5916,7 @@ } ], "source": [ - "Fraction(\"1/3\") # 1/3 with \"full\" precision" + "Fraction(\"1/3\") # 1 / 3 with \"full\" precision" ] }, { @@ -5927,7 +5940,7 @@ } ], "source": [ - "Fraction(\"0.3333333333\") # 1/3 with a precision of 10 significant digits" + "Fraction(\"0.3333333333\") # 1 / 3 with a precision of 10 significant digits" ] }, { @@ -5970,7 +5983,7 @@ "execution_count": 191, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -5994,7 +6007,7 @@ "execution_count": 192, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -6222,7 +6235,7 @@ } ], "source": [ - "10.0 * Fraction(1, 100) # do not do this" + "10.0 * Fraction(1, 100) # do not do this!" ] }, { @@ -6348,7 +6361,7 @@ { "data": { "text/plain": [ - "139663415663408" + "139960519210800" ] }, "execution_count": 202, @@ -6556,7 +6569,7 @@ } }, "source": [ - " The arguments to [complex()](https://docs.python.org/3/library/functions.html#complex) may be any numeric type." + "The arguments to [complex()](https://docs.python.org/3/library/functions.html#complex) may be any numeric type or properly formated `str` object." ] }, { @@ -6623,7 +6636,7 @@ "execution_count": 211, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [], @@ -6637,7 +6650,7 @@ "execution_count": 212, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -6661,7 +6674,7 @@ "execution_count": 213, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -6781,7 +6794,7 @@ "execution_count": 218, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -6805,7 +6818,7 @@ "execution_count": 219, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -6832,7 +6845,7 @@ } }, "source": [ - "The absolute value of a `complex` number $x$ is defined with the Pythagorean Theorem where $\\lVert x \\rVert = \\sqrt{a^2 + b^2}$ and $a$ and $b$ are the real and imaginary parts. The [abs()](https://docs.python.org/3/library/functions.html#abs) built-in function implements that in Python." + "A `complex` number comes with two **attributes** `real` and `imag` that return the two parts as `float` objects on their own." ] }, { @@ -6847,7 +6860,7 @@ { "data": { "text/plain": [ - "5.0" + "0.0" ] }, "execution_count": 220, @@ -6856,18 +6869,7 @@ } ], "source": [ - "abs(3 + 4j)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "A `complex` number comes with two **attributes** `real` and `imag` that return the two parts as `float` objects on their own." + "x.real" ] }, { @@ -6891,31 +6893,7 @@ } ], "source": [ - "c1.real" - ] - }, - { - "cell_type": "code", - "execution_count": 222, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "2.0" - ] - }, - "execution_count": 222, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "c1.imag" + "x.imag" ] }, { @@ -6931,7 +6909,7 @@ }, { "cell_type": "code", - "execution_count": 223, + "execution_count": 222, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6941,16 +6919,16 @@ { "data": { "text/plain": [ - "(1-2j)" + "-1j" ] }, - "execution_count": 223, + "execution_count": 222, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "c1.conjugate()" + "x.conjugate()" ] }, { @@ -6993,7 +6971,7 @@ "- $\\mathbb{R}$: [Real numbers](https://en.wikipedia.org/wiki/Real_number) are all numbers that can be represented as a distance along a line, and negative means \"reversed,\" e.g., $\\sqrt{2}, \\pi, \\text{e}, ...$\n", "- $\\mathbb{C}$: [Complex numbers](https://en.wikipedia.org/wiki/Complex_number) are all numbers of the form $a + b\\textbf{i}$ where $a$ and $b$ are real numbers and $\\textbf{i}$ is the [imaginary number](https://en.wikipedia.org/wiki/Imaginary_number), e.g., $0, \\textbf{i}, 1 + \\textbf{i}, ...$\n", "\n", - "In the listed order, the five sets are perfect subsets of the respective following sets, and $\\mathbb{C}$ is the largest set (cf., the figure below illustrates that observation as well). To be precise, all sets are infinite, but they still have a different number of elements." + "In the listed order, the five sets are perfect subsets of the respective following sets, and $\\mathbb{C}$ is the largest set. To be precise, all sets are infinite, but they still have a different number of elements." ] }, { @@ -7015,7 +6993,7 @@ } }, "source": [ - "The data types introduced in this chapter are all *imperfect* models of *abstract* mathematical ideas.\n", + "The data types introduced in this chapter are all *(im)perfect* models of *abstract* mathematical ideas.\n", "\n", "The `int` and `Fraction` types are the models \"closest\" to the idea they implement: Whereas $\\mathbb{Z}$ and $\\mathbb{Q}$ are, by definition, infinite, every computer runs out of bits when representing sufficiently large integers or fractions with a sufficiently large number of decimals. However, within a system-dependent range, we can model an integer or fraction without any loss in precision.\n", "\n", @@ -7032,7 +7010,7 @@ }, { "cell_type": "code", - "execution_count": 224, + "execution_count": 223, "metadata": { "slideshow": { "slide_type": "slide" @@ -7045,7 +7023,7 @@ }, { "cell_type": "code", - "execution_count": 225, + "execution_count": 224, "metadata": { "slideshow": { "slide_type": "slide" @@ -7073,7 +7051,7 @@ " 'abstractmethod']" ] }, - "execution_count": 225, + "execution_count": 224, "metadata": {}, "output_type": "execute_result" } @@ -7082,286 +7060,6 @@ "dir(numbers)" ] }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "As a reminder, the built-in [help()](https://docs.python.org/3/library/functions.html#help) function is always our friend.\n", - "\n", - "The ABCs' docstrings are unsurprisingly similar to the corresponding data types' docstrings. For now, let's not worry about the dunder-style names in the docstrings.\n", - "\n", - "For example, both `numbers.Complex` and `complex` list the `imag` and `real` attributes shown above." - ] - }, - { - "cell_type": "code", - "execution_count": 226, - "metadata": { - "scrolled": true, - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on class Complex in module numbers:\n", - "\n", - "class Complex(Number)\n", - " | Complex defines the operations that work on the builtin complex type.\n", - " | \n", - " | In short, those are: a conversion to complex, .real, .imag, +, -,\n", - " | *, /, abs(), .conjugate, ==, and !=.\n", - " | \n", - " | If it is given heterogeneous arguments, and doesn't have special\n", - " | knowledge about them, it should fall back to the builtin complex\n", - " | type as described below.\n", - " | \n", - " | Method resolution order:\n", - " | Complex\n", - " | Number\n", - " | builtins.object\n", - " | \n", - " | Methods defined here:\n", - " | \n", - " | __abs__(self)\n", - " | Returns the Real distance from 0. Called for abs(self).\n", - " | \n", - " | __add__(self, other)\n", - " | self + other\n", - " | \n", - " | __bool__(self)\n", - " | True if self != 0. Called for bool(self).\n", - " | \n", - " | __complex__(self)\n", - " | Return a builtin complex instance. Called for complex(self).\n", - " | \n", - " | __eq__(self, other)\n", - " | self == other\n", - " | \n", - " | __mul__(self, other)\n", - " | self * other\n", - " | \n", - " | __neg__(self)\n", - " | -self\n", - " | \n", - " | __pos__(self)\n", - " | +self\n", - " | \n", - " | __pow__(self, exponent)\n", - " | self**exponent; should promote to float or complex when necessary.\n", - " | \n", - " | __radd__(self, other)\n", - " | other + self\n", - " | \n", - " | __rmul__(self, other)\n", - " | other * self\n", - " | \n", - " | __rpow__(self, base)\n", - " | base ** self\n", - " | \n", - " | __rsub__(self, other)\n", - " | other - self\n", - " | \n", - " | __rtruediv__(self, other)\n", - " | other / self\n", - " | \n", - " | __sub__(self, other)\n", - " | self - other\n", - " | \n", - " | __truediv__(self, other)\n", - " | self / other: Should promote to float when necessary.\n", - " | \n", - " | conjugate(self)\n", - " | (x+y*i).conjugate() returns (x-y*i).\n", - " | \n", - " | ----------------------------------------------------------------------\n", - " | Data descriptors defined here:\n", - " | \n", - " | imag\n", - " | Retrieve the imaginary component of this number.\n", - " | \n", - " | This should subclass Real.\n", - " | \n", - " | real\n", - " | Retrieve the real component of this number.\n", - " | \n", - " | This should subclass Real.\n", - " | \n", - " | ----------------------------------------------------------------------\n", - " | Data and other attributes defined here:\n", - " | \n", - " | __abstractmethods__ = frozenset({'__abs__', '__add__', '__complex__', ...\n", - " | \n", - " | __hash__ = None\n", - "\n" - ] - } - ], - "source": [ - "help(numbers.Complex)" - ] - }, - { - "cell_type": "code", - "execution_count": 227, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on class complex in module builtins:\n", - "\n", - "class complex(object)\n", - " | complex(real=0, imag=0)\n", - " | \n", - " | Create a complex number from a real part and an optional imaginary part.\n", - " | \n", - " | This is equivalent to (real + imag*1j) where imag defaults to 0.\n", - " | \n", - " | Methods defined here:\n", - " | \n", - " | __abs__(self, /)\n", - " | abs(self)\n", - " | \n", - " | __add__(self, value, /)\n", - " | Return self+value.\n", - " | \n", - " | __bool__(self, /)\n", - " | self != 0\n", - " | \n", - " | __divmod__(self, value, /)\n", - " | Return divmod(self, value).\n", - " | \n", - " | __eq__(self, value, /)\n", - " | Return self==value.\n", - " | \n", - " | __float__(self, /)\n", - " | float(self)\n", - " | \n", - " | __floordiv__(self, value, /)\n", - " | Return self//value.\n", - " | \n", - " | __format__(...)\n", - " | complex.__format__() -> str\n", - " | \n", - " | Convert to a string according to format_spec.\n", - " | \n", - " | __ge__(self, value, /)\n", - " | Return self>=value.\n", - " | \n", - " | __getattribute__(self, name, /)\n", - " | Return getattr(self, name).\n", - " | \n", - " | __getnewargs__(...)\n", - " | \n", - " | __gt__(self, value, /)\n", - " | Return self>value.\n", - " | \n", - " | __hash__(self, /)\n", - " | Return hash(self).\n", - " | \n", - " | __int__(self, /)\n", - " | int(self)\n", - " | \n", - " | __le__(self, value, /)\n", - " | Return self<=value.\n", - " | \n", - " | __lt__(self, value, /)\n", - " | Return self complex\n", - " | \n", - " | Return the complex conjugate of its argument. (3-4j).conjugate() == 3+4j.\n", - " | \n", - " | ----------------------------------------------------------------------\n", - " | Static methods defined here:\n", - " | \n", - " | __new__(*args, **kwargs) from builtins.type\n", - " | Create and return a new object. See help(type) for accurate signature.\n", - " | \n", - " | ----------------------------------------------------------------------\n", - " | Data descriptors defined here:\n", - " | \n", - " | imag\n", - " | the imaginary part of a complex number\n", - " | \n", - " | real\n", - " | the real part of a complex number\n", - "\n" - ] - } - ], - "source": [ - "help(complex)" - ] - }, { "cell_type": "markdown", "metadata": { @@ -7370,7 +7068,7 @@ } }, "source": [ - "### Duck Typing" + "### Duck Typing (continued)" ] }, { @@ -7383,14 +7081,14 @@ "source": [ "The primary purpose of ABCs is to classify the *concrete* data types and standardize how they behave. This guides us as the programmers in what kind of behavior we should expect from objects of a given data type. In this context, ABCs are not reflected in code but only in our heads.\n", "\n", - "For, example, as all numeric data types are `Complex` numbers in the abstract sense, they all work with the built-in [abs()](https://docs.python.org/3/library/functions.html#abs) function (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Complex)). While it is intuitively clear what the [absolute value](https://en.wikipedia.org/wiki/Absolute_value) (i.e., \"distance\" to $0$) of an integer, a fraction, or any real number is, [abs()](https://docs.python.org/3/library/functions.html#abs) calculates the equivalent of that for complex numbers. That concept is called the [magnitude](https://en.wikipedia.org/wiki/Magnitude_%28mathematics%29) of a number, and is really a *generalization* of the absolute value.\n", + "For, example, as all numeric data types are `Complex` numbers in the abstract sense, they all work with the built-in [abs()](https://docs.python.org/3/library/functions.html#abs) function (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Complex)). While it is intuitively clear what the [absolute value](https://en.wikipedia.org/wiki/Absolute_value) (i.e., \"distance\" from $0$) of an integer, a fraction, or any real number is, [abs()](https://docs.python.org/3/library/functions.html#abs) calculates the equivalent of that for complex numbers. That concept is called the [magnitude](https://en.wikipedia.org/wiki/Magnitude_%28mathematics%29) of a number, and is really a *generalization* of the absolute value.\n", "\n", - "Relating back to the concept of **duck typing** mentioned in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Type-Checking-&-Input-Validation), `int`, `float`, and `complex` objects \"walk\" and \"quack\" alike in context of the [abs()](https://docs.python.org/3/library/functions.html#abs) function." + "Relating back to the concept of **duck typing** mentioned in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Duck-Typing), `int`, `float`, and `complex` objects \"walk\" and \"quack\" alike in context of the [abs()](https://docs.python.org/3/library/functions.html#abs) function." ] }, { "cell_type": "code", - "execution_count": 228, + "execution_count": 225, "metadata": { "slideshow": { "slide_type": "slide" @@ -7403,7 +7101,7 @@ "1" ] }, - "execution_count": 228, + "execution_count": 225, "metadata": {}, "output_type": "execute_result" } @@ -7414,7 +7112,7 @@ }, { "cell_type": "code", - "execution_count": 229, + "execution_count": 226, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7427,7 +7125,7 @@ "42.87" ] }, - "execution_count": 229, + "execution_count": 226, "metadata": {}, "output_type": "execute_result" } @@ -7436,9 +7134,20 @@ "abs(-42.87)" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The absolute value of a `complex` number $x$ is defined with the Pythagorean Theorem where $\\lVert x \\rVert = \\sqrt{a^2 + b^2}$ and $a$ and $b$ are the real and imaginary parts." + ] + }, { "cell_type": "code", - "execution_count": 230, + "execution_count": 227, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7451,13 +7160,13 @@ "5.0" ] }, - "execution_count": 230, + "execution_count": 227, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "abs(4 - 3j)" + "abs(3 + 4j)" ] }, { @@ -7473,7 +7182,7 @@ }, { "cell_type": "code", - "execution_count": 231, + "execution_count": 228, "metadata": { "slideshow": { "slide_type": "slide" @@ -7486,7 +7195,7 @@ "100" ] }, - "execution_count": 231, + "execution_count": 228, "metadata": {}, "output_type": "execute_result" } @@ -7497,7 +7206,7 @@ }, { "cell_type": "code", - "execution_count": 232, + "execution_count": 229, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7510,7 +7219,7 @@ "42" ] }, - "execution_count": 232, + "execution_count": 229, "metadata": {}, "output_type": "execute_result" } @@ -7532,7 +7241,7 @@ }, { "cell_type": "code", - "execution_count": 233, + "execution_count": 230, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7546,7 +7255,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mround\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m2j\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mround\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m2j\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: type complex doesn't define __round__ method" ] } @@ -7581,7 +7290,7 @@ }, { "cell_type": "code", - "execution_count": 234, + "execution_count": 231, "metadata": { "slideshow": { "slide_type": "slide" @@ -7594,7 +7303,7 @@ "True" ] }, - "execution_count": 234, + "execution_count": 231, "metadata": {}, "output_type": "execute_result" } @@ -7616,7 +7325,7 @@ }, { "cell_type": "code", - "execution_count": 235, + "execution_count": 232, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7629,7 +7338,7 @@ "True" ] }, - "execution_count": 235, + "execution_count": 232, "metadata": {}, "output_type": "execute_result" } @@ -7640,7 +7349,7 @@ }, { "cell_type": "code", - "execution_count": 236, + "execution_count": 233, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7653,7 +7362,7 @@ "True" ] }, - "execution_count": 236, + "execution_count": 233, "metadata": {}, "output_type": "execute_result" } @@ -7664,7 +7373,7 @@ }, { "cell_type": "code", - "execution_count": 237, + "execution_count": 234, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7677,7 +7386,7 @@ "True" ] }, - "execution_count": 237, + "execution_count": 234, "metadata": {}, "output_type": "execute_result" } @@ -7699,7 +7408,7 @@ }, { "cell_type": "code", - "execution_count": 238, + "execution_count": 235, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7712,7 +7421,7 @@ "False" ] }, - "execution_count": 238, + "execution_count": 235, "metadata": {}, "output_type": "execute_result" } @@ -7729,12 +7438,12 @@ } }, "source": [ - "However, if we model `1 / 10` as a `Fraction`, it is recognized as a `Rational` number." + "However, if we model `1 / 10` as a `Fraction` object, it is recognized as a `Rational` number." ] }, { "cell_type": "code", - "execution_count": 239, + "execution_count": 236, "metadata": { "slideshow": { "slide_type": "skip" @@ -7747,7 +7456,7 @@ "True" ] }, - "execution_count": 239, + "execution_count": 236, "metadata": {}, "output_type": "execute_result" } @@ -7764,7 +7473,7 @@ } }, "source": [ - "Replacing *concrete* data types with ABCs is particularly valuable in the context of input validation: The revised version of the `factorial()` function below allows its user to take advantage of *duck typing*: If a real but non-integer argument `n` is passed in, `factorial()` tries to cast `n` as an `int` object with the [int()](https://docs.python.org/3/library/functions.html#int) built-in.\n", + "Replacing *concrete* data types with ABCs is particularly valuable in the context of \"type checking:\" The revised version of the `factorial()` function below allows its user to take advantage of *duck typing*: If a real but non-integer argument `n` is passed in, `factorial()` tries to cast `n` as an `int` object with the [int()](https://docs.python.org/3/library/functions.html#int) built-in.\n", "\n", "Two popular and distinguished Pythonistas, [Luciano Ramalho](https://github.com/ramalho) and [Alex Martelli](https://en.wikipedia.org/wiki/Alex_Martelli), coin the term **goose typing** to specifically mean using the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function with an ABC (cf., Chapter 11 in this [book](https://www.amazon.com/Fluent-Python-Concise-Effective-Programming/dp/1491946008) or this [summary](https://dgkim5360.github.io/blog/python/2017/07/duck-typing-vs-goose-typing-pythonic-interfaces/) thereof)." ] @@ -7782,7 +7491,7 @@ }, { "cell_type": "code", - "execution_count": 240, + "execution_count": 237, "metadata": { "slideshow": { "slide_type": "slide" @@ -7808,7 +7517,7 @@ " if not isinstance(n, numbers.Integral):\n", " if isinstance(n, numbers.Real):\n", " if n != int(n) and strict:\n", - " raise TypeError(\"n is not integer-like; it has decimals\")\n", + " raise TypeError(\"n is not integer-like; it has non-zero decimals\")\n", " n = int(n)\n", " else:\n", " raise TypeError(\"Factorial is only defined for integers\")\n", @@ -7833,7 +7542,7 @@ }, { "cell_type": "code", - "execution_count": 241, + "execution_count": 238, "metadata": { "slideshow": { "slide_type": "slide" @@ -7846,7 +7555,7 @@ "1" ] }, - "execution_count": 241, + "execution_count": 238, "metadata": {}, "output_type": "execute_result" } @@ -7855,6 +7564,102 @@ "factorial(0)" ] }, + { + "cell_type": "code", + "execution_count": 239, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 239, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 240, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 240, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(3.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "With the keyword-only argument `strict`, we can control whether or not a passed in `float` object may come with decimals that are then truncated. By default, this is not allowed and results in a `TypeError`." + ] + }, + { + "cell_type": "code", + "execution_count": 241, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "n is not integer-like; it has non-zero decimals", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n, strict)\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mReal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mstrict\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not integer-like; it has non-zero decimals\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 20\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: n is not integer-like; it has non-zero decimals" + ] + } + ], + "source": [ + "factorial(3.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "In non-strict mode, the passed in `3.1` is truncated into `3` resulting in a factorial of `6`." + ] + }, { "cell_type": "code", "execution_count": 242, @@ -7875,102 +7680,6 @@ "output_type": "execute_result" } ], - "source": [ - "factorial(3)" - ] - }, - { - "cell_type": "code", - "execution_count": 243, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "6" - ] - }, - "execution_count": 243, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "factorial(3.0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "With the keyword-only argument `strict`, we can control whether or not a passed in `float` object may come with decimals that are then truncated. By default, this is not allowed and results in a `TypeError`." - ] - }, - { - "cell_type": "code", - "execution_count": 244, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "ename": "TypeError", - "evalue": "n is not integer-like; it has decimals", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n, strict)\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mReal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mstrict\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not integer-like; it has decimals\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 20\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m: n is not integer-like; it has decimals" - ] - } - ], - "source": [ - "factorial(3.1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "In non-strict mode, the passed in `3.1` is truncated into `3` resulting in a factorial of `6`." - ] - }, - { - "cell_type": "code", - "execution_count": 245, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "6" - ] - }, - "execution_count": 245, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "factorial(3.1, strict=False)" ] @@ -7988,7 +7697,7 @@ }, { "cell_type": "code", - "execution_count": 246, + "execution_count": 243, "metadata": { "slideshow": { "slide_type": "slide" @@ -8002,8 +7711,8 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m2j\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n, strict)\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 22\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 23\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m2j\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n, strict)\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 22\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 23\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mTypeError\u001b[0m: Factorial is only defined for integers" ] } @@ -8072,7 +7781,7 @@ }, { "cell_type": "code", - "execution_count": 247, + "execution_count": 244, "metadata": { "slideshow": { "slide_type": "skip" @@ -8094,22 +7803,21 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 247, + "execution_count": 244, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from IPython.display import YouTubeVideo\n", "YouTubeVideo(\"RgklPQ8rbkg\", width=\"60%\")" ] }, { "cell_type": "code", - "execution_count": 248, + "execution_count": 245, "metadata": { "slideshow": { "slide_type": "skip" @@ -8131,10 +7839,10 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 248, + "execution_count": 245, "metadata": {}, "output_type": "execute_result" } @@ -8156,7 +7864,7 @@ }, { "cell_type": "code", - "execution_count": 249, + "execution_count": 246, "metadata": { "slideshow": { "slide_type": "skip" @@ -8178,10 +7886,10 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 249, + "execution_count": 246, "metadata": {}, "output_type": "execute_result" } @@ -8203,7 +7911,7 @@ }, { "cell_type": "code", - "execution_count": 250, + "execution_count": 247, "metadata": { "slideshow": { "slide_type": "skip" @@ -8225,10 +7933,10 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 250, + "execution_count": 247, "metadata": {}, "output_type": "execute_result" } @@ -8250,7 +7958,7 @@ }, { "cell_type": "code", - "execution_count": 251, + "execution_count": 248, "metadata": { "slideshow": { "slide_type": "skip" @@ -8272,10 +7980,10 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 251, + "execution_count": 248, "metadata": {}, "output_type": "execute_result" } diff --git a/05_numbers_01_review.ipynb b/05_numbers_01_review.ipynb index 01d88fe..7b3ac58 100644 --- a/05_numbers_01_review.ipynb +++ b/05_numbers_01_review.ipynb @@ -4,8 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "# Chapter 5: Bits & Numbers" + "# Chapter 5: Numbers & Bits" ] }, { @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb) of the book. Then, work through the questions below." + "The questions below assume that you have read [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb) in the book.\n", + "\n", + "Be concise in your answers! Most questions can be answered in *one* sentence." ] }, { @@ -47,7 +48,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -61,28 +62,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q3**: Why is it *inefficient* to store `bool` objects in bits resembling a **hexadecimal representation**?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q4**: Colors are commonly expressed in the **hexadecimal system** in websites (cf., the [HTML](https://en.wikipedia.org/wiki/HTML) and [CSS](https://en.wikipedia.org/wiki/Cascading_Style_Sheets) formats).\n", + "**Q3**: Colors are commonly expressed in the **hexadecimal system** in websites (cf., the [HTML](https://en.wikipedia.org/wiki/HTML) and [CSS](https://en.wikipedia.org/wiki/Cascading_Style_Sheets) formats).\n", "\n", "For example, $#000000$, $#ff9900$, and $#ffffff$ turn out to be black, orange, and white. The six digits are read in *pairs of two* from left to right, and the *three pairs* correspond to the proportions of red, green, and blue mixed together. They reach from $0_{16} = 0_{10}$ for $0$% to $\\text{ff}_{16} = 255_{10}$ for $100$% (cf., this [article](https://en.wikipedia.org/wiki/RGB_color_model) for an in-depth discussion).\n", "\n", @@ -93,77 +80,77 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q5**: What does it mean for a code fragment to **fail silently**?" + "**Q4**: What does it mean for a code fragment to **fail silently**?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q6**: Explain why the mathematical set of all real numbers $\\mathbb{R}$ can only be **approximated** by floating-point numbers on a computer!" + "**Q5**: Explain why the mathematical set of all real numbers $\\mathbb{R}$ can only be **approximated** by floating-point numbers on a computer!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q7**: How do we deal with a `float` object's imprecision if we need to **check for equality**?" + "**Q6**: How do we deal with a `float` object's imprecision if we need to **check for equality**?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q8**: What data type, built-in or from the [standard library](https://docs.python.org/3/library/index.html), is best suited to represent the [transcendental numbers](https://en.wikipedia.org/wiki/Transcendental_number) $\\pi$ and $\\text{e}$?" + "**Q7**: What data type, built-in or from the [standard library](https://docs.python.org/3/library/index.html), is best suited to represent the [transcendental numbers](https://en.wikipedia.org/wiki/Transcendental_number) $\\pi$ and $\\text{e}$?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q9**: How can **abstract base classes**, for example, as defined in the **numerical tower**, be helpful in enabling **duck typing**?" + "**Q8**: How can **abstract base classes**, for example, as defined in the **numerical tower**, be helpful in enabling **duck typing**?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -184,63 +171,63 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q10**: The precision of `int` objects depends on how we choose to represent them in memory. For example, using a **hexadecimal representation** gives us $16^8$ digits whereas with a **binary representation** an `int` object can have *at most* $2^8$ digits." + "**Q9**: The precision of `int` objects depends on how we choose to represent them in memory. For example, using a **hexadecimal representation** gives us $16^8$ digits whereas with a **binary representation** an `int` object can have *at most* $2^8$ digits." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q11**: With the built-in [round()](https://docs.python.org/3/library/functions.html#round) function, we obtain a *precise* representation for any `float` object if we can live with *less than* $15$ digits of precision." + "**Q10**: With the built-in [round()](https://docs.python.org/3/library/functions.html#round) function, we obtain a *precise* representation for any `float` object if we can live with *less than* $15$ digits of precision." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q12**: As most currencies operate with $2$ or $3$ decimals (e.g., EUR $9.99$), the `float` type's limitation of *at most* $15$ digits is *not* a problem in practice." + "**Q11**: As most currencies operate with $2$ or $3$ decimals (e.g., EUR $9.99$), the `float` type's limitation of *at most* $15$ digits is *not* a problem in practice." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q13**: The [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) standard's **special values** provide no benefit in practice as we could always use a **[sentinel](https://en.wikipedia.org/wiki/Sentinel_value)** value (i.e., a \"dummy\"). For example, instead of `nan`, we can always use `0` to indicate a *missing* value." + "**Q12**: The [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) standard's **special values** provide no benefit in practice as we could always use a **[sentinel](https://en.wikipedia.org/wiki/Sentinel_value)** value (i.e., a \"dummy\"). For example, instead of `nan`, we can always use `0` to indicate a *missing* value." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q14**: The following code fragment raises an `InvalidOperation` exception. That is an example of code **failing loudly**.\n", + "**Q13**: The following code fragment raises an `InvalidOperation` exception. That is an example of code **failing loudly**.\n", "```python\n", "float(\"inf\") + float(\"-inf\")\n", "```" @@ -250,63 +237,63 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q15**: Python provides a `scientific` type (e.g., `1.23e4`) that is useful mainly to model problems in the domains of physics or astrophysics." + "**Q14**: Python provides a `scientific` type (e.g., `1.23e4`) that is useful mainly to model problems in the domains of physics or astrophysics." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q16**: From a practitioner's point of view, the built-in [format()](https://docs.python.org/3/library/functions.html#format) function does the *same* as the built-in [round()](https://docs.python.org/3/library/functions.html#round) function." + "**Q15**: From a practitioner's point of view, the built-in [format()](https://docs.python.org/3/library/functions.html#format) function does the *same* as the built-in [round()](https://docs.python.org/3/library/functions.html#round) function." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q17**: The `Decimal` type from the [decimal](https://docs.python.org/3/library/decimal.html) module in the [standard library](https://docs.python.org/3/library/index.html) allows us to model the set of the real numbers $\\mathbb{R}$ *precisely*." + "**Q16**: The `Decimal` type from the [decimal](https://docs.python.org/3/library/decimal.html) module in the [standard library](https://docs.python.org/3/library/index.html) allows us to model the set of the real numbers $\\mathbb{R}$ *precisely*." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q18**: The `Fraction` type from the [fractions](https://docs.python.org/3/library/fractions.html) module in the [standard library](https://docs.python.org/3/library/index.html) allows us to model the set of the rational numbers $\\mathbb{Q}$ *precisely*." + "**Q17**: The `Fraction` type from the [fractions](https://docs.python.org/3/library/fractions.html) module in the [standard library](https://docs.python.org/3/library/index.html) allows us to model the set of the rational numbers $\\mathbb{Q}$ *precisely*." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] } ], diff --git a/05_numbers_02_exercises.ipynb b/05_numbers_02_exercises.ipynb index ff5e9a8..8eaeaac 100644 --- a/05_numbers_02_exercises.ipynb +++ b/05_numbers_02_exercises.ipynb @@ -4,8 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "# Chapter 5: Bits & Numbers" + "# Chapter 5: Numbers & Bits" ] }, { @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb) of the book. Then, work through the exercises below. The `...` indicate where you need to fill in your answers. You should not need to create any additional code cells." + "The exercises below assume that you have read [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb) in the book.\n", + "\n", + "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." ] }, { @@ -80,7 +81,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -94,7 +95,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -110,7 +111,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -238,7 +239,7 @@ "\n", "Enable **duck typing** by allowing the function to be called with various numeric types as the arguments, in particular, `quantity` may be a non-integer as well: Use an appropriate **abstract base class** from the [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) to verify the arguments' types and also that they are both positive!\n", "\n", - "It is considered a *best practice* to only round towards the *end* of the calculations." + "Hint: It is considered a *best practice* to only round towards the *end* of the calculations." ] }, { @@ -256,8 +257,43 @@ "metadata": {}, "outputs": [], "source": [ - "def discounted_price(...):\n", - " ..." + "def discounted_price(unit_price, quantity):\n", + " \"\"\"Calculate the price of a line item in an order.\n", + "\n", + " Args:\n", + " unit_price (numbers.Real): price of an ordered item; must be positive\n", + " quantity (numbers.Real): number of items ordered; must be positive\n", + "\n", + " Returns:\n", + " line_item_price (decimal.Decimal): precision of 2 decimals\n", + " \"\"\"\n", + " # Basic input validation.\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " # Calculate the final price if only\n", + " # the first discount scheme is applied.\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " # Calculate the final price if only\n", + " # the second discount scheme is applied.\n", + " # \"One in every five\" means we need to figure out\n", + " # how many full groups of five are contained.\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " # Choose the better option for the customer.\n", + " ...\n", + " # Round correctly for pricing purposes.\n", + " return ..." ] }, { diff --git a/06_text_00_lecture.ipynb b/06_text_00_lecture.ipynb index 3c23901..6a676d4 100644 --- a/06_text_00_lecture.ipynb +++ b/06_text_00_lecture.ipynb @@ -1,5 +1,53 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A **video presentation** of the contents in this chapter is shown below. A playlist with *all* chapters as videos is linked [here](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChALCAgOCggIDRYNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxgVERUWFxcYExMYGBgVFRgWFRYWGBcVGxIaEhMXFRoYGBISFRcVFRUVFRUVFRUVGBUSFxIVFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAgIDAQEAAAAAAAAAAAAABgcFCAIDBAEJ/8QAURAAAQQBAgMBCQgRAgUEAgMAAQACAwQRBRIGEyExBxQYIjJBVZTVCBUXUVJhk9QjMzVCU1RxcnN0dYGSsbKz05G0FiQ2YrU0gqGiY3YlQ0X/xAAcAQEAAgMBAQEAAAAAAAAAAAAAAgQBAwUHBgj/xAA9EQABAwIDBQUGBAYBBQEAAAABAAIRAyEEEjEFQVFhcRMVU4GRBiIyocHwFjRysRQ1QlLR4fEjM0NigpL/2gAMAwEAAhEDEQA/ANMkREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXF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hodQ0EBkkco21dQ8qJ4e0HOodmWhZBgrB0X6DItAPDV4q9H8P+q6j7RTw1eKvR/D/quo+0VhZW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/682q/aJ/0Mn9DloT4avFXo/h/1XUfaK4WPdo8UvY9hoaBh7XNOKuo5w4EHGdR7eqItaURERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERf/2Q==\n", + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo(\"3WTRlgN09sM\", width=\"60%\")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -8,7 +56,7 @@ } }, "source": [ - "# Chapter 6: Bytes & Text" + "# Chapter 6: Text & Bytes" ] }, { @@ -46,7 +94,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "slideshow": { "slide_type": "slide" @@ -70,7 +118,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" @@ -80,10 +128,10 @@ { "data": { "text/plain": [ - "140461336295424" + "140388598371792" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -94,7 +142,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "slideshow": { "slide_type": "fragment" @@ -107,7 +155,7 @@ "str" ] }, - "execution_count": 3, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -131,7 +179,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "slideshow": { "slide_type": "fragment" @@ -144,7 +192,7 @@ "'Lorem ipsum dolor sit amet.'" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -170,7 +218,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "slideshow": { "slide_type": "slide" @@ -183,7 +231,7 @@ "'Einstein said, \"If you can\\'t explain it, you don\\'t understand it.\"'" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -194,7 +242,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "slideshow": { "slide_type": "fragment" @@ -207,7 +255,7 @@ "'Einstein said, \"If you can\\'t explain it, you don\\'t understand it.\"'" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -231,7 +279,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "slideshow": { "slide_type": "fragment" @@ -252,7 +300,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "slideshow": { "slide_type": "skip" @@ -284,7 +332,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "slideshow": { "slide_type": "slide" @@ -297,37 +345,13 @@ "'42'" ] }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "str(42)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'42.87'" - ] - }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "str(42.87)" + "str(42)" ] }, { @@ -342,7 +366,7 @@ { "data": { "text/plain": [ - "'[1, 2, 3]'" + "'42.87'" ] }, "execution_count": 11, @@ -351,7 +375,7 @@ } ], "source": [ - "str([1, 2, 3])" + "str(42.87)" ] }, { @@ -366,7 +390,7 @@ { "data": { "text/plain": [ - "'True'" + "'[1, 2, 3]'" ] }, "execution_count": 12, @@ -375,7 +399,7 @@ } ], "source": [ - "str(True)" + "str([1, 2, 3])" ] }, { @@ -383,14 +407,14 @@ "execution_count": 13, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ - "'False'" + "'True'" ] }, "execution_count": 13, @@ -399,7 +423,7 @@ } ], "source": [ - "str(False)" + "str(True)" ] }, { @@ -414,7 +438,7 @@ { "data": { "text/plain": [ - "'None'" + "'False'" ] }, "execution_count": 14, @@ -422,6 +446,30 @@ "output_type": "execute_result" } ], + "source": [ + "str(False)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'None'" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "str(None)" ] @@ -450,7 +498,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": { "slideshow": { "slide_type": "slide" @@ -461,7 +509,7 @@ "name": "stdin", "output_type": "stream", "text": [ - "Whatever you enter is put in a new string: I will be a string\n" + "Whatever you enter is put in a new string: 1\n" ] } ], @@ -469,30 +517,6 @@ "user_input = input(\"Whatever you enter is put in a new string: \")" ] }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "str" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(user_input)" - ] - }, { "cell_type": "code", "execution_count": 17, @@ -505,7 +529,7 @@ { "data": { "text/plain": [ - "'I will be a string'" + "str" ] }, "execution_count": 17, @@ -513,6 +537,30 @@ "output_type": "execute_result" } ], + "source": [ + "type(user_input)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'1'" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "user_input" ] @@ -541,7 +589,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "metadata": { "slideshow": { "slide_type": "slide" @@ -565,7 +613,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "metadata": { "slideshow": { "slide_type": "fragment" @@ -578,7 +626,7 @@ "_io.TextIOWrapper" ] }, - "execution_count": 19, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -589,7 +637,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "metadata": { "slideshow": { "slide_type": "fragment" @@ -602,7 +650,7 @@ "<_io.TextIOWrapper name='lorem_ipsum.txt' mode='r' encoding='UTF-8'>" ] }, - "execution_count": 20, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -624,7 +672,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": { "slideshow": { "slide_type": "slide" @@ -637,37 +685,13 @@ "True" ] }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "file.readable()" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "file.writable()" + "file.readable()" ] }, { @@ -682,7 +706,7 @@ { "data": { "text/plain": [ - "'lorem_ipsum.txt'" + "False" ] }, "execution_count": 23, @@ -691,7 +715,7 @@ } ], "source": [ - "file.name" + "file.writable()" ] }, { @@ -706,7 +730,7 @@ { "data": { "text/plain": [ - "'UTF-8'" + "'lorem_ipsum.txt'" ] }, "execution_count": 24, @@ -714,6 +738,30 @@ "output_type": "execute_result" } ], + "source": [ + "file.name" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'UTF-8'" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "file.encoding" ] @@ -733,7 +781,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": { "slideshow": { "slide_type": "slide" @@ -777,7 +825,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": { "slideshow": { "slide_type": "skip" @@ -802,7 +850,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 28, "metadata": { "slideshow": { "slide_type": "slide" @@ -815,7 +863,7 @@ "'the 1960s with the release of Letraset sheets.\\n'" ] }, - "execution_count": 27, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -826,7 +874,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 29, "metadata": { "slideshow": { "slide_type": "fragment" @@ -839,7 +887,7 @@ "str" ] }, - "execution_count": 28, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -863,7 +911,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 30, "metadata": { "slideshow": { "slide_type": "slide" @@ -876,7 +924,7 @@ "False" ] }, - "execution_count": 29, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -887,7 +935,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 31, "metadata": { "slideshow": { "slide_type": "fragment" @@ -900,7 +948,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 32, "metadata": { "slideshow": { "slide_type": "fragment" @@ -913,7 +961,7 @@ "True" ] }, - "execution_count": 31, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -935,7 +983,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 33, "metadata": { "slideshow": { "slide_type": "slide" @@ -969,7 +1017,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 34, "metadata": { "slideshow": { "slide_type": "fragment" @@ -982,7 +1030,7 @@ "True" ] }, - "execution_count": 33, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } @@ -1004,7 +1052,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 35, "metadata": { "slideshow": { "slide_type": "skip" @@ -1041,7 +1089,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 36, "metadata": { "slideshow": { "slide_type": "skip" @@ -1054,7 +1102,7 @@ "True" ] }, - "execution_count": 35, + "execution_count": 36, "metadata": {}, "output_type": "execute_result" } @@ -1078,7 +1126,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 37, "metadata": { "slideshow": { "slide_type": "slide" @@ -1091,7 +1139,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 38, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1104,7 +1152,7 @@ "'Lorem Ipsum'" ] }, - "execution_count": 37, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } @@ -1126,7 +1174,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 39, "metadata": { "slideshow": { "slide_type": "skip" @@ -1139,7 +1187,7 @@ "' is simply '" ] }, - "execution_count": 38, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -1161,7 +1209,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 40, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1174,7 +1222,7 @@ "'dummy text of the printing and typesetting industry.\\n'" ] }, - "execution_count": 39, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" } @@ -1196,7 +1244,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 41, "metadata": { "slideshow": { "slide_type": "skip" @@ -1209,7 +1257,7 @@ "\"Lorem Ipsum has been the industry's standard dummy text ever since the 1500s\\n\"" ] }, - "execution_count": 40, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" } @@ -1231,7 +1279,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 42, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1247,7 +1295,7 @@ " 'the 1960s with the release of Letraset sheets.\\n']" ] }, - "execution_count": 41, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" } @@ -1269,7 +1317,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 43, "metadata": { "slideshow": { "slide_type": "skip" @@ -1282,7 +1330,7 @@ "[]" ] }, - "execution_count": 42, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } @@ -1293,7 +1341,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 44, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1317,7 +1365,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 45, "metadata": { "slideshow": { "slide_type": "skip" @@ -1380,7 +1428,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 46, "metadata": { "slideshow": { "slide_type": "slide" @@ -1393,7 +1441,7 @@ "'Lorem ipsum dolor sit amet.'" ] }, - "execution_count": 45, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } @@ -1404,7 +1452,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 47, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1417,7 +1465,7 @@ "27" ] }, - "execution_count": 46, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -1439,7 +1487,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 48, "metadata": { "slideshow": { "slide_type": "slide" @@ -1472,7 +1520,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 49, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1505,36 +1553,12 @@ "The `in` operator has *two* distinct usages: First, it checks if a *single* character is contained in a `str` object. Second, it may also check if a shorter `str` object, then called a **substring**, is contained in a longer one." ] }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 49, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "\"L\" in text" - ] - }, { "cell_type": "code", "execution_count": 50, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" } }, "outputs": [ @@ -1550,7 +1574,7 @@ } ], "source": [ - "\"ipsum\" in text" + "\"L\" in text" ] }, { @@ -1565,7 +1589,7 @@ { "data": { "text/plain": [ - "False" + "True" ] }, "execution_count": 51, @@ -1573,6 +1597,30 @@ "output_type": "execute_result" } ], + "source": [ + "\"ipsum\" in text" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "\"veni, vidi, vici\" in text" ] @@ -1601,7 +1649,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 53, "metadata": { "slideshow": { "slide_type": "slide" @@ -1614,7 +1662,7 @@ "'L'" ] }, - "execution_count": 52, + "execution_count": 53, "metadata": {}, "output_type": "execute_result" } @@ -1625,7 +1673,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 54, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1638,7 +1686,7 @@ "'o'" ] }, - "execution_count": 53, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } @@ -1660,7 +1708,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 55, "metadata": { "slideshow": { "slide_type": "skip" @@ -1674,7 +1722,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: string indices must be integers" ] } @@ -1696,7 +1744,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 56, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1709,7 +1757,7 @@ "'.'" ] }, - "execution_count": 55, + "execution_count": 56, "metadata": {}, "output_type": "execute_result" } @@ -1731,7 +1779,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 57, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1745,7 +1793,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m27\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# == text[len(text)]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m27\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# == text[len(text)]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mIndexError\u001b[0m: string index out of range" ] } @@ -1781,7 +1829,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 58, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1794,7 +1842,7 @@ "'.'" ] }, - "execution_count": 57, + "execution_count": 58, "metadata": {}, "output_type": "execute_result" } @@ -1805,7 +1853,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 59, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1818,7 +1866,7 @@ "'L'" ] }, - "execution_count": 58, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" } @@ -1838,30 +1886,6 @@ "One reason why programmers like to start counting at `0` is that a positive index and its *corresponding* negative index always add up to the length of the sequence. Here, `6` and `21` add to `27`." ] }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'i'" - ] - }, - "execution_count": 59, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "text[6]" - ] - }, { "cell_type": "code", "execution_count": 60, @@ -1882,6 +1906,30 @@ "output_type": "execute_result" } ], + "source": [ + "text[6]" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'i'" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "text[-21]" ] @@ -1914,7 +1962,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 62, "metadata": { "slideshow": { "slide_type": "slide" @@ -1927,7 +1975,7 @@ "'Lorem'" ] }, - "execution_count": 61, + "execution_count": 62, "metadata": {}, "output_type": "execute_result" } @@ -1938,7 +1986,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 63, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1951,7 +1999,7 @@ "'dolor sit amet.'" ] }, - "execution_count": 62, + "execution_count": 63, "metadata": {}, "output_type": "execute_result" } @@ -1973,7 +2021,7 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 64, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1986,7 +2034,7 @@ "'Lorem'" ] }, - "execution_count": 63, + "execution_count": 64, "metadata": {}, "output_type": "execute_result" } @@ -1997,7 +2045,7 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 65, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2010,7 +2058,7 @@ "'dolor sit amet.'" ] }, - "execution_count": 64, + "execution_count": 65, "metadata": {}, "output_type": "execute_result" } @@ -2032,7 +2080,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 66, "metadata": { "slideshow": { "slide_type": "skip" @@ -2045,7 +2093,7 @@ "'Lorem ipsum dolor sit amet.'" ] }, - "execution_count": 65, + "execution_count": 66, "metadata": {}, "output_type": "execute_result" } @@ -2067,7 +2115,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 67, "metadata": { "slideshow": { "slide_type": "skip" @@ -2080,7 +2128,7 @@ "'Lorem ipsum sit amet.'" ] }, - "execution_count": 66, + "execution_count": 67, "metadata": {}, "output_type": "execute_result" } @@ -2102,7 +2150,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 68, "metadata": { "slideshow": { "slide_type": "slide" @@ -2115,7 +2163,7 @@ "'ipsum dolor'" ] }, - "execution_count": 67, + "execution_count": 68, "metadata": {}, "output_type": "execute_result" } @@ -2137,7 +2185,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 69, "metadata": { "slideshow": { "slide_type": "skip" @@ -2150,7 +2198,7 @@ "'Lorem ipsum dolor sit amet.'" ] }, - "execution_count": 68, + "execution_count": 69, "metadata": {}, "output_type": "execute_result" } @@ -2172,7 +2220,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 70, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2185,7 +2233,7 @@ "'Lorem ipsum dolor sit amet.'" ] }, - "execution_count": 69, + "execution_count": 70, "metadata": {}, "output_type": "execute_result" } @@ -2207,7 +2255,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 71, "metadata": { "slideshow": { "slide_type": "slide" @@ -2220,7 +2268,7 @@ "'Lrmismdlrstae.'" ] }, - "execution_count": 70, + "execution_count": 71, "metadata": {}, "output_type": "execute_result" } @@ -2242,7 +2290,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 72, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2255,7 +2303,7 @@ "'.tema tis rolod muspi meroL'" ] }, - "execution_count": 71, + "execution_count": 72, "metadata": {}, "output_type": "execute_result" } @@ -2292,7 +2340,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 73, "metadata": { "slideshow": { "slide_type": "slide" @@ -2306,7 +2354,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"X\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"X\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'str' object does not support item assignment" ] } @@ -2317,7 +2365,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 74, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2331,7 +2379,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"random\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"random\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'str' object does not support item assignment" ] } @@ -2366,7 +2414,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 75, "metadata": { "slideshow": { "slide_type": "slide" @@ -2379,37 +2427,13 @@ "'Lorem ipsum dolor sit amet.'" ] }, - "execution_count": 74, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "text" - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "22" - ] - }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "text.find(\"a\")" + "text" ] }, { @@ -2424,7 +2448,7 @@ { "data": { "text/plain": [ - "-1" + "22" ] }, "execution_count": 76, @@ -2433,7 +2457,7 @@ } ], "source": [ - "text.find(\"b\")" + "text.find(\"a\")" ] }, { @@ -2448,7 +2472,7 @@ { "data": { "text/plain": [ - "12" + "-1" ] }, "execution_count": 77, @@ -2456,6 +2480,30 @@ "output_type": "execute_result" } ], + "source": [ + "text.find(\"b\")" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "12" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "text.find(\"dolor\")" ] @@ -2471,30 +2519,6 @@ "[find()](https://docs.python.org/3/library/stdtypes.html#str.find) takes optional *start* and *end* arguments that allow us to find occurrences other than the first one." ] }, - { - "cell_type": "code", - "execution_count": 78, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 78, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "text.find(\"o\")" - ] - }, { "cell_type": "code", "execution_count": 79, @@ -2507,7 +2531,7 @@ { "data": { "text/plain": [ - "13" + "1" ] }, "execution_count": 79, @@ -2516,7 +2540,7 @@ } ], "source": [ - "text.find(\"o\", 2)" + "text.find(\"o\")" ] }, { @@ -2531,7 +2555,7 @@ { "data": { "text/plain": [ - "-1" + "13" ] }, "execution_count": 80, @@ -2539,6 +2563,30 @@ "output_type": "execute_result" } ], + "source": [ + "text.find(\"o\", 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "-1" + ] + }, + "execution_count": 81, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "text.find(\"o\", 2, 12)" ] @@ -2556,7 +2604,7 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 82, "metadata": { "slideshow": { "slide_type": "slide" @@ -2569,7 +2617,7 @@ "'Lorem ipsum dolor sit amet.'" ] }, - "execution_count": 81, + "execution_count": 82, "metadata": {}, "output_type": "execute_result" } @@ -2580,7 +2628,7 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 83, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2593,7 +2641,7 @@ "1" ] }, - "execution_count": 82, + "execution_count": 83, "metadata": {}, "output_type": "execute_result" } @@ -2615,7 +2663,7 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 84, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2628,7 +2676,7 @@ "2" ] }, - "execution_count": 83, + "execution_count": 84, "metadata": {}, "output_type": "execute_result" } @@ -2650,7 +2698,7 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 85, "metadata": { "slideshow": { "slide_type": "skip" @@ -2663,7 +2711,7 @@ "2" ] }, - "execution_count": 84, + "execution_count": 85, "metadata": {}, "output_type": "execute_result" } @@ -2685,7 +2733,7 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 86, "metadata": { "slideshow": { "slide_type": "slide" @@ -2698,7 +2746,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 87, "metadata": { "slideshow": { "slide_type": "skip" @@ -2708,10 +2756,10 @@ { "data": { "text/plain": [ - "140461430391152" + "140388701131184" ] }, - "execution_count": 86, + "execution_count": 87, "metadata": {}, "output_type": "execute_result" } @@ -2722,7 +2770,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 88, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2735,7 +2783,7 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 89, "metadata": { "slideshow": { "slide_type": "skip" @@ -2745,10 +2793,10 @@ { "data": { "text/plain": [ - "140461335949424" + "140388590822320" ] }, - "execution_count": 88, + "execution_count": 89, "metadata": {}, "output_type": "execute_result" } @@ -2770,7 +2818,7 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 90, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2783,7 +2831,7 @@ "False" ] }, - "execution_count": 89, + "execution_count": 90, "metadata": {}, "output_type": "execute_result" } @@ -2794,7 +2842,7 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 91, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2807,7 +2855,7 @@ "True" ] }, - "execution_count": 90, + "execution_count": 91, "metadata": {}, "output_type": "execute_result" } @@ -2829,7 +2877,7 @@ }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 92, "metadata": { "slideshow": { "slide_type": "skip" @@ -2842,37 +2890,13 @@ "'lorem ipsum dolor sit amet.'" ] }, - "execution_count": 91, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "text.lower()" - ] - }, - { - "cell_type": "code", - "execution_count": 92, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'LOREM IPSUM DOLOR SIT AMET.'" - ] - }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "text.upper()" + "text.lower()" ] }, { @@ -2887,7 +2911,7 @@ { "data": { "text/plain": [ - "'Lorem Ipsum Dolor Sit Amet.'" + "'LOREM IPSUM DOLOR SIT AMET.'" ] }, "execution_count": 93, @@ -2896,7 +2920,7 @@ } ], "source": [ - "text.title()" + "text.upper()" ] }, { @@ -2911,7 +2935,7 @@ { "data": { "text/plain": [ - "'lOREM IPSUM DOLOR SIT AMET.'" + "'Lorem Ipsum Dolor Sit Amet.'" ] }, "execution_count": 94, @@ -2919,6 +2943,30 @@ "output_type": "execute_result" } ], + "source": [ + "text.title()" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'lOREM IPSUM DOLOR SIT AMET.'" + ] + }, + "execution_count": 95, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "text.swapcase()" ] @@ -2938,7 +2986,7 @@ }, { "cell_type": "code", - "execution_count": 95, + "execution_count": 96, "metadata": { "slideshow": { "slide_type": "slide" @@ -2951,7 +2999,7 @@ "['Lorem', 'ipsum', 'dolor', 'sit', 'amet.']" ] }, - "execution_count": 95, + "execution_count": 96, "metadata": {}, "output_type": "execute_result" } @@ -2962,7 +3010,7 @@ }, { "cell_type": "code", - "execution_count": 96, + "execution_count": 97, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2995,7 +3043,7 @@ }, { "cell_type": "code", - "execution_count": 97, + "execution_count": 98, "metadata": { "slideshow": { "slide_type": "slide" @@ -3008,7 +3056,7 @@ }, { "cell_type": "code", - "execution_count": 98, + "execution_count": 99, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3021,7 +3069,7 @@ }, { "cell_type": "code", - "execution_count": 99, + "execution_count": 100, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3034,7 +3082,7 @@ "'This will become a sentence.'" ] }, - "execution_count": 99, + "execution_count": 100, "metadata": {}, "output_type": "execute_result" } @@ -3056,7 +3104,7 @@ }, { "cell_type": "code", - "execution_count": 100, + "execution_count": 101, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3069,7 +3117,7 @@ "'a b c d e'" ] }, - "execution_count": 100, + "execution_count": 101, "metadata": {}, "output_type": "execute_result" } @@ -3091,7 +3139,7 @@ }, { "cell_type": "code", - "execution_count": 101, + "execution_count": 102, "metadata": { "slideshow": { "slide_type": "slide" @@ -3104,7 +3152,7 @@ "'This is a sentence.'" ] }, - "execution_count": 101, + "execution_count": 102, "metadata": {}, "output_type": "execute_result" } @@ -3126,7 +3174,7 @@ }, { "cell_type": "code", - "execution_count": 102, + "execution_count": 103, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3139,7 +3187,7 @@ "'This will become a sentence.'" ] }, - "execution_count": 102, + "execution_count": 103, "metadata": {}, "output_type": "execute_result" } @@ -3161,7 +3209,7 @@ }, { "cell_type": "code", - "execution_count": 103, + "execution_count": 104, "metadata": { "slideshow": { "slide_type": "slide" @@ -3174,37 +3222,13 @@ "'text with whitespace'" ] }, - "execution_count": 103, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "\" text with whitespace \".strip()" - ] - }, - { - "cell_type": "code", - "execution_count": 104, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'text with whitespace '" - ] - }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "\" text with whitespace \".lstrip()" + "\" text with whitespace \".strip()" ] }, { @@ -3219,7 +3243,7 @@ { "data": { "text/plain": [ - "' text with whitespace'" + "'text with whitespace '" ] }, "execution_count": 105, @@ -3227,6 +3251,30 @@ "output_type": "execute_result" } ], + "source": [ + "\" text with whitespace \".lstrip()" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "' text with whitespace'" + ] + }, + "execution_count": 106, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "\" text with whitespace \".rstrip()" ] @@ -3244,7 +3292,7 @@ }, { "cell_type": "code", - "execution_count": 106, + "execution_count": 107, "metadata": { "slideshow": { "slide_type": "slide" @@ -3257,7 +3305,7 @@ "'This will become a sentence. '" ] }, - "execution_count": 106, + "execution_count": 107, "metadata": {}, "output_type": "execute_result" } @@ -3268,7 +3316,7 @@ }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 108, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3281,7 +3329,7 @@ "' This will become a sentence.'" ] }, - "execution_count": 107, + "execution_count": 108, "metadata": {}, "output_type": "execute_result" } @@ -3303,7 +3351,7 @@ }, { "cell_type": "code", - "execution_count": 108, + "execution_count": 109, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3316,7 +3364,7 @@ "'0000042.87'" ] }, - "execution_count": 108, + "execution_count": 109, "metadata": {}, "output_type": "execute_result" } @@ -3327,7 +3375,7 @@ }, { "cell_type": "code", - "execution_count": 109, + "execution_count": 110, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3340,7 +3388,7 @@ "'-000042.87'" ] }, - "execution_count": 109, + "execution_count": 110, "metadata": {}, "output_type": "execute_result" } @@ -3373,7 +3421,7 @@ }, { "cell_type": "code", - "execution_count": 110, + "execution_count": 111, "metadata": { "slideshow": { "slide_type": "slide" @@ -3386,7 +3434,7 @@ "'Hello Lore'" ] }, - "execution_count": 110, + "execution_count": 111, "metadata": {}, "output_type": "execute_result" } @@ -3397,7 +3445,7 @@ }, { "cell_type": "code", - "execution_count": 111, + "execution_count": 112, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3410,7 +3458,7 @@ "'Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum ...'" ] }, - "execution_count": 111, + "execution_count": 112, "metadata": {}, "output_type": "execute_result" } @@ -3443,7 +3491,7 @@ }, { "cell_type": "code", - "execution_count": 112, + "execution_count": 113, "metadata": { "slideshow": { "slide_type": "slide" @@ -3456,37 +3504,13 @@ "True" ] }, - "execution_count": 112, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "\"Apple\" < \"Banana\"" - ] - }, - { - "cell_type": "code", - "execution_count": 113, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, "execution_count": 113, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "\"apple\" < \"Banana\" # upper case letter come before lower case ones" + "\"Apple\" < \"Banana\"" ] }, { @@ -3501,7 +3525,7 @@ { "data": { "text/plain": [ - "True" + "False" ] }, "execution_count": 114, @@ -3509,6 +3533,30 @@ "output_type": "execute_result" } ], + "source": [ + "\"apple\" < \"Banana\"" + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 115, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "\"apple\" < \"Banana\".lower()" ] @@ -3526,7 +3574,7 @@ }, { "cell_type": "code", - "execution_count": 115, + "execution_count": 116, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3539,7 +3587,7 @@ "True" ] }, - "execution_count": 115, + "execution_count": 116, "metadata": {}, "output_type": "execute_result" } @@ -3594,7 +3642,7 @@ }, { "cell_type": "code", - "execution_count": 116, + "execution_count": 117, "metadata": { "slideshow": { "slide_type": "slide" @@ -3608,7 +3656,7 @@ }, { "cell_type": "code", - "execution_count": 117, + "execution_count": 118, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3621,7 +3669,7 @@ "'Hello Alexander! Good morning.'" ] }, - "execution_count": 117, + "execution_count": 118, "metadata": {}, "output_type": "execute_result" } @@ -3643,7 +3691,7 @@ }, { "cell_type": "code", - "execution_count": 118, + "execution_count": 119, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3656,7 +3704,7 @@ }, { "cell_type": "code", - "execution_count": 119, + "execution_count": 120, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3669,7 +3717,7 @@ "'Pi is 3.14'" ] }, - "execution_count": 119, + "execution_count": 120, "metadata": {}, "output_type": "execute_result" } @@ -3702,7 +3750,7 @@ }, { "cell_type": "code", - "execution_count": 120, + "execution_count": 121, "metadata": { "slideshow": { "slide_type": "slide" @@ -3715,7 +3763,7 @@ "'Hello Alexander! Good morning.'" ] }, - "execution_count": 120, + "execution_count": 121, "metadata": {}, "output_type": "execute_result" } @@ -3737,7 +3785,7 @@ }, { "cell_type": "code", - "execution_count": 121, + "execution_count": 122, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3750,7 +3798,7 @@ "'Good morning, Alexander'" ] }, - "execution_count": 121, + "execution_count": 122, "metadata": {}, "output_type": "execute_result" } @@ -3772,7 +3820,7 @@ }, { "cell_type": "code", - "execution_count": 122, + "execution_count": 123, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3785,7 +3833,7 @@ "'Hello Alexander! Good morning.'" ] }, - "execution_count": 122, + "execution_count": 123, "metadata": {}, "output_type": "execute_result" } @@ -3807,7 +3855,7 @@ }, { "cell_type": "code", - "execution_count": 123, + "execution_count": 124, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3820,7 +3868,7 @@ "'Pi is 3.14'" ] }, - "execution_count": 123, + "execution_count": 124, "metadata": {}, "output_type": "execute_result" } @@ -3855,7 +3903,7 @@ }, { "cell_type": "code", - "execution_count": 124, + "execution_count": 125, "metadata": { "slideshow": { "slide_type": "slide" @@ -3868,7 +3916,7 @@ "'Pi is 3.14'" ] }, - "execution_count": 124, + "execution_count": 125, "metadata": {}, "output_type": "execute_result" } @@ -3890,7 +3938,7 @@ }, { "cell_type": "code", - "execution_count": 125, + "execution_count": 126, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3903,7 +3951,7 @@ "'Hello Alexander! Good morning.'" ] }, - "execution_count": 125, + "execution_count": 126, "metadata": {}, "output_type": "execute_result" } @@ -3938,7 +3986,7 @@ }, { "cell_type": "code", - "execution_count": 126, + "execution_count": 127, "metadata": { "slideshow": { "slide_type": "slide" @@ -3951,7 +3999,7 @@ "'This is a sentence\\nthat is printed\\non three lines.'" ] }, - "execution_count": 126, + "execution_count": 127, "metadata": {}, "output_type": "execute_result" } @@ -3962,7 +4010,7 @@ }, { "cell_type": "code", - "execution_count": 127, + "execution_count": 128, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3996,7 +4044,7 @@ }, { "cell_type": "code", - "execution_count": 128, + "execution_count": 129, "metadata": { "slideshow": { "slide_type": "slide" @@ -4017,7 +4065,7 @@ }, { "cell_type": "code", - "execution_count": 129, + "execution_count": 130, "metadata": { "slideshow": { "slide_type": "skip" @@ -4049,7 +4097,7 @@ }, { "cell_type": "code", - "execution_count": 130, + "execution_count": 131, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4070,7 +4118,7 @@ }, { "cell_type": "code", - "execution_count": 131, + "execution_count": 132, "metadata": { "slideshow": { "slide_type": "skip" @@ -4102,7 +4150,7 @@ }, { "cell_type": "code", - "execution_count": 132, + "execution_count": 133, "metadata": { "slideshow": { "slide_type": "skip" @@ -4136,7 +4184,7 @@ }, { "cell_type": "code", - "execution_count": 133, + "execution_count": 134, "metadata": { "slideshow": { "slide_type": "slide" @@ -4180,7 +4228,7 @@ }, { "cell_type": "code", - "execution_count": 134, + "execution_count": 135, "metadata": { "slideshow": { "slide_type": "slide" @@ -4213,7 +4261,7 @@ }, { "cell_type": "code", - "execution_count": 135, + "execution_count": 136, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4222,10 +4270,10 @@ "outputs": [ { "ename": "SyntaxError", - "evalue": "(unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \\UXXXXXXXX escape (, line 1)", + "evalue": "(unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \\UXXXXXXXX escape (, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m print(\"C:\\Users\\Administrator\\Desktop\\Project\")\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \\UXXXXXXXX escape\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m print(\"C:\\Users\\Administrator\\Desktop\\Project\")\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \\UXXXXXXXX escape\n" ] } ], @@ -4246,7 +4294,7 @@ }, { "cell_type": "code", - "execution_count": 136, + "execution_count": 137, "metadata": { "slideshow": { "slide_type": "slide" @@ -4267,7 +4315,7 @@ }, { "cell_type": "code", - "execution_count": 137, + "execution_count": 138, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4299,7 +4347,7 @@ }, { "cell_type": "code", - "execution_count": 138, + "execution_count": 139, "metadata": { "slideshow": { "slide_type": "slide" @@ -4320,7 +4368,7 @@ }, { "cell_type": "code", - "execution_count": 139, + "execution_count": 140, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4389,7 +4437,7 @@ }, { "cell_type": "code", - "execution_count": 140, + "execution_count": 141, "metadata": { "slideshow": { "slide_type": "slide" @@ -4402,7 +4450,7 @@ "65" ] }, - "execution_count": 140, + "execution_count": 141, "metadata": {}, "output_type": "execute_result" } @@ -4413,7 +4461,7 @@ }, { "cell_type": "code", - "execution_count": 141, + "execution_count": 142, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4426,7 +4474,7 @@ "'A'" ] }, - "execution_count": 141, + "execution_count": 142, "metadata": {}, "output_type": "execute_result" } @@ -4448,7 +4496,7 @@ }, { "cell_type": "code", - "execution_count": 142, + "execution_count": 143, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4461,7 +4509,7 @@ "10" ] }, - "execution_count": 142, + "execution_count": 143, "metadata": {}, "output_type": "execute_result" } @@ -4472,7 +4520,7 @@ }, { "cell_type": "code", - "execution_count": 143, + "execution_count": 144, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4485,7 +4533,7 @@ "'\\n'" ] }, - "execution_count": 143, + "execution_count": 144, "metadata": {}, "output_type": "execute_result" } @@ -4511,7 +4559,7 @@ }, { "cell_type": "code", - "execution_count": 144, + "execution_count": 145, "metadata": { "slideshow": { "slide_type": "slide" @@ -4542,7 +4590,7 @@ }, { "cell_type": "code", - "execution_count": 145, + "execution_count": 146, "metadata": { "slideshow": { "slide_type": "slide" @@ -4573,7 +4621,7 @@ }, { "cell_type": "code", - "execution_count": 146, + "execution_count": 147, "metadata": { "slideshow": { "slide_type": "slide" @@ -4615,7 +4663,7 @@ }, { "cell_type": "code", - "execution_count": 147, + "execution_count": 148, "metadata": { "slideshow": { "slide_type": "slide" @@ -4633,7 +4681,7 @@ }, { "cell_type": "code", - "execution_count": 148, + "execution_count": 149, "metadata": { "slideshow": { "slide_type": "slide" @@ -4703,7 +4751,7 @@ }, { "cell_type": "code", - "execution_count": 149, + "execution_count": 150, "metadata": { "slideshow": { "slide_type": "slide" @@ -4716,7 +4764,7 @@ "'😄'" ] }, - "execution_count": 149, + "execution_count": 150, "metadata": {}, "output_type": "execute_result" } @@ -4738,7 +4786,7 @@ }, { "cell_type": "code", - "execution_count": 150, + "execution_count": 151, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4751,7 +4799,7 @@ "'😂'" ] }, - "execution_count": 150, + "execution_count": 151, "metadata": {}, "output_type": "execute_result" } @@ -4771,30 +4819,6 @@ "Whenever the code point can be expressed with just four hexadecimal digits, we may use the escape sequence `\"\\u\"` for brevity." ] }, - { - "cell_type": "code", - "execution_count": 151, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'A'" - ] - }, - "execution_count": 151, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "\"\\U00000041\" # hex(65) == 0x41" - ] - }, { "cell_type": "code", "execution_count": 152, @@ -4816,18 +4840,7 @@ } ], "source": [ - "\"\\u0041\"" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Analogously, if the code point can be expressed with two hexadecimal digits, we may use the escape sequence `\"\\x\"` for even conciser code." + "\"\\U00000041\" # hex(65) == 0x41" ] }, { @@ -4850,6 +4863,41 @@ "output_type": "execute_result" } ], + "source": [ + "\"\\u0041\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Analogously, if the code point can be expressed with two hexadecimal digits, we may use the escape sequence `\"\\x\"` for even conciser code." + ] + }, + { + "cell_type": "code", + "execution_count": 154, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'A'" + ] + }, + "execution_count": 154, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "\"\\x41\"" ] @@ -4869,7 +4917,7 @@ }, { "cell_type": "code", - "execution_count": 154, + "execution_count": 155, "metadata": { "slideshow": { "slide_type": "slide" @@ -4882,7 +4930,7 @@ "1" ] }, - "execution_count": 154, + "execution_count": 155, "metadata": {}, "output_type": "execute_result" } @@ -4904,7 +4952,7 @@ }, { "cell_type": "code", - "execution_count": 155, + "execution_count": 156, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4917,7 +4965,7 @@ "'🐍'" ] }, - "execution_count": 155, + "execution_count": 156, "metadata": {}, "output_type": "execute_result" } @@ -4928,7 +4976,7 @@ }, { "cell_type": "code", - "execution_count": 156, + "execution_count": 157, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4941,7 +4989,7 @@ "1" ] }, - "execution_count": 156, + "execution_count": 157, "metadata": {}, "output_type": "execute_result" } @@ -4963,7 +5011,7 @@ }, { "cell_type": "code", - "execution_count": 157, + "execution_count": 158, "metadata": { "slideshow": { "slide_type": "skip" @@ -4976,7 +5024,7 @@ "'straße'" ] }, - "execution_count": 157, + "execution_count": 158, "metadata": {}, "output_type": "execute_result" } @@ -4987,7 +5035,7 @@ }, { "cell_type": "code", - "execution_count": 158, + "execution_count": 159, "metadata": { "slideshow": { "slide_type": "skip" @@ -5000,7 +5048,7 @@ "'strasse'" ] }, - "execution_count": 158, + "execution_count": 159, "metadata": {}, "output_type": "execute_result" } @@ -5044,19 +5092,19 @@ }, { "cell_type": "code", - "execution_count": 159, + "execution_count": 160, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ { "ename": "SyntaxError", - "evalue": "EOL while scanning string literal (, line 1)", + "evalue": "EOL while scanning string literal (, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m \"\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m EOL while scanning string literal\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m \"\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m EOL while scanning string literal\n" ] } ], @@ -5079,7 +5127,7 @@ }, { "cell_type": "code", - "execution_count": 160, + "execution_count": 161, "metadata": { "slideshow": { "slide_type": "slide" @@ -5106,7 +5154,7 @@ }, { "cell_type": "code", - "execution_count": 161, + "execution_count": 162, "metadata": { "slideshow": { "slide_type": "skip" @@ -5119,7 +5167,7 @@ "'\\nI am a multi-line string\\nconsisting of four lines.\\n'" ] }, - "execution_count": 161, + "execution_count": 162, "metadata": {}, "output_type": "execute_result" } @@ -5130,7 +5178,7 @@ }, { "cell_type": "code", - "execution_count": 162, + "execution_count": 163, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5165,7 +5213,7 @@ }, { "cell_type": "code", - "execution_count": 163, + "execution_count": 164, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5201,7 +5249,7 @@ }, { "cell_type": "code", - "execution_count": 164, + "execution_count": 165, "metadata": { "slideshow": { "slide_type": "skip" @@ -5217,7 +5265,7 @@ }, { "cell_type": "code", - "execution_count": 165, + "execution_count": 166, "metadata": { "slideshow": { "slide_type": "skip" @@ -5264,7 +5312,7 @@ }, { "cell_type": "code", - "execution_count": 166, + "execution_count": 167, "metadata": { "slideshow": { "slide_type": "slide" @@ -5289,7 +5337,7 @@ }, { "cell_type": "code", - "execution_count": 167, + "execution_count": 168, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5299,10 +5347,10 @@ { "data": { "text/plain": [ - "140461335555696" + "140388598520624" ] }, - "execution_count": 167, + "execution_count": 168, "metadata": {}, "output_type": "execute_result" } @@ -5313,7 +5361,7 @@ }, { "cell_type": "code", - "execution_count": 168, + "execution_count": 169, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5326,7 +5374,7 @@ "bytes" ] }, - "execution_count": 168, + "execution_count": 169, "metadata": {}, "output_type": "execute_result" } @@ -5348,7 +5396,7 @@ }, { "cell_type": "code", - "execution_count": 169, + "execution_count": 170, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5361,7 +5409,7 @@ "b'\\xf0\\x9f\\x82\\xa7\\xf0\\x9f\\x82\\xb7\\xf0\\x9f\\x83\\x97\\xf0\\x9f\\x83\\x8e\\xf0\\x9f\\x83\\x9e'" ] }, - "execution_count": 169, + "execution_count": 170, "metadata": {}, "output_type": "execute_result" } @@ -5383,7 +5431,7 @@ }, { "cell_type": "code", - "execution_count": 170, + "execution_count": 171, "metadata": { "slideshow": { "slide_type": "slide" @@ -5396,7 +5444,7 @@ "20" ] }, - "execution_count": 170, + "execution_count": 171, "metadata": {}, "output_type": "execute_result" } @@ -5418,7 +5466,7 @@ }, { "cell_type": "code", - "execution_count": 171, + "execution_count": 172, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5451,7 +5499,7 @@ }, { "cell_type": "code", - "execution_count": 172, + "execution_count": 173, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5464,7 +5512,7 @@ "158" ] }, - "execution_count": 172, + "execution_count": 173, "metadata": {}, "output_type": "execute_result" } @@ -5486,7 +5534,7 @@ }, { "cell_type": "code", - "execution_count": 173, + "execution_count": 174, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5499,7 +5547,7 @@ "b'\\xf0\\x82\\xf0\\x82\\xf0\\x83\\xf0\\x83\\xf0\\x83'" ] }, - "execution_count": 173, + "execution_count": 174, "metadata": {}, "output_type": "execute_result" } @@ -5534,7 +5582,7 @@ }, { "cell_type": "code", - "execution_count": 174, + "execution_count": 175, "metadata": { "slideshow": { "slide_type": "slide" @@ -5547,7 +5595,7 @@ }, { "cell_type": "code", - "execution_count": 175, + "execution_count": 176, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5560,7 +5608,7 @@ "str" ] }, - "execution_count": 175, + "execution_count": 176, "metadata": {}, "output_type": "execute_result" } @@ -5582,7 +5630,7 @@ }, { "cell_type": "code", - "execution_count": 176, + "execution_count": 177, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5595,7 +5643,7 @@ "'🂧🂷🃗🃎🃞'" ] }, - "execution_count": 176, + "execution_count": 177, "metadata": {}, "output_type": "execute_result" } @@ -5617,7 +5665,7 @@ }, { "cell_type": "code", - "execution_count": 177, + "execution_count": 178, "metadata": { "slideshow": { "slide_type": "slide" @@ -5630,7 +5678,7 @@ }, { "cell_type": "code", - "execution_count": 178, + "execution_count": 179, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5643,7 +5691,7 @@ "b'Caf\\xc3\\xa9 Kastanient\\xc3\\xb6rtchen'" ] }, - "execution_count": 178, + "execution_count": 179, "metadata": {}, "output_type": "execute_result" } @@ -5665,7 +5713,7 @@ }, { "cell_type": "code", - "execution_count": 179, + "execution_count": 180, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5678,7 +5726,7 @@ "b'Caf\\xe9 Kastanient\\xf6rtchen'" ] }, - "execution_count": 179, + "execution_count": 180, "metadata": {}, "output_type": "execute_result" } @@ -5700,7 +5748,7 @@ }, { "cell_type": "code", - "execution_count": 180, + "execution_count": 181, "metadata": { "slideshow": { "slide_type": "slide" @@ -5714,7 +5762,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mUnicodeDecodeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mplace\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mencode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"iso-8859-1\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mplace\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mencode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"iso-8859-1\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mUnicodeDecodeError\u001b[0m: 'utf-8' codec can't decode byte 0xe9 in position 3: invalid continuation byte" ] } @@ -5736,7 +5784,7 @@ }, { "cell_type": "code", - "execution_count": 181, + "execution_count": 182, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5750,7 +5798,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mUnicodeEncodeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m\"Dobrý den, přátelé!\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mencode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"iso-8859-1\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m\"Dobrý den, přátelé!\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mencode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"iso-8859-1\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mUnicodeEncodeError\u001b[0m: 'latin-1' codec can't encode character '\\u0159' in position 12: ordinal not in range(256)" ] } @@ -5783,7 +5831,7 @@ }, { "cell_type": "code", - "execution_count": 182, + "execution_count": 183, "metadata": { "slideshow": { "slide_type": "slide" @@ -5797,7 +5845,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mUnicodeDecodeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"umlauts.txt\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mfile\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfile\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreadlines\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"umlauts.txt\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mfile\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfile\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreadlines\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m~/.pyenv/versions/anaconda3-2019.10/lib/python3.7/codecs.py\u001b[0m in \u001b[0;36mdecode\u001b[0;34m(self, input, final)\u001b[0m\n\u001b[1;32m 320\u001b[0m \u001b[0;31m# decode input (taking the buffer into account)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 321\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuffer\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 322\u001b[0;31m \u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconsumed\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_buffer_decode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfinal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 323\u001b[0m \u001b[0;31m# keep undecoded input until the next call\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 324\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuffer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mconsumed\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mUnicodeDecodeError\u001b[0m: 'utf-8' codec can't decode byte 0xe4 in position 9: invalid continuation byte" ] @@ -5810,7 +5858,7 @@ }, { "cell_type": "code", - "execution_count": 183, + "execution_count": 184, "metadata": { "slideshow": { "slide_type": "slide" @@ -5867,7 +5915,7 @@ }, { "cell_type": "code", - "execution_count": 184, + "execution_count": 185, "metadata": { "slideshow": { "slide_type": "slide" @@ -5881,7 +5929,31 @@ }, { "cell_type": "code", - "execution_count": 185, + "execution_count": 186, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "\"Lorem Ipsum is simply dummy text of the printing and typesetting industry.\\nLorem Ipsum has been the industry's standard dummy text ever since the 1500s\\nwhen an unknown printer took a galley of type and scrambled it to make a type\\nspecimen book. It has survived not only five centuries but also the leap into\\nelectronic typesetting, remaining essentially unchanged. It was popularised in\\nthe 1960s with the release of Letraset sheets.\\n\"" + ] + }, + "execution_count": 186, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "content" + ] + }, + { + "cell_type": "code", + "execution_count": 187, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5958,7 +6030,7 @@ }, { "cell_type": "code", - "execution_count": 186, + "execution_count": 188, "metadata": { "slideshow": { "slide_type": "skip" @@ -5980,16 +6052,15 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 186, + "execution_count": 188, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from IPython.display import YouTubeVideo\n", "YouTubeVideo(\"MijmeoH9LT4\", width=\"60%\")" ] }, @@ -6006,7 +6077,7 @@ }, { "cell_type": "code", - "execution_count": 187, + "execution_count": 189, "metadata": { "slideshow": { "slide_type": "skip" @@ -6028,10 +6099,10 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 187, + "execution_count": 189, "metadata": {}, "output_type": "execute_result" } @@ -6053,7 +6124,7 @@ }, { "cell_type": "code", - "execution_count": 188, + "execution_count": 190, "metadata": { "slideshow": { "slide_type": "skip" @@ -6075,10 +6146,10 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 188, + "execution_count": 190, "metadata": {}, "output_type": "execute_result" } @@ -6100,7 +6171,7 @@ }, { "cell_type": "code", - "execution_count": 189, + "execution_count": 191, "metadata": { "slideshow": { "slide_type": "skip" @@ -6122,10 +6193,10 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 189, + "execution_count": 191, "metadata": {}, "output_type": "execute_result" } @@ -6147,7 +6218,7 @@ }, { "cell_type": "code", - "execution_count": 190, + "execution_count": 192, "metadata": { "slideshow": { "slide_type": "skip" @@ -6169,10 +6240,10 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 190, + "execution_count": 192, "metadata": {}, "output_type": "execute_result" } @@ -6183,7 +6254,7 @@ }, { "cell_type": "code", - "execution_count": 191, + "execution_count": 193, "metadata": { "slideshow": { "slide_type": "skip" @@ -6205,10 +6276,10 @@ " " ], "text/plain": [ - "" + "" ] }, - "execution_count": 191, + "execution_count": 193, "metadata": {}, "output_type": "execute_result" } diff --git a/06_text_01_review.ipynb b/06_text_01_review.ipynb index d92bd12..8727868 100644 --- a/06_text_01_review.ipynb +++ b/06_text_01_review.ipynb @@ -4,8 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "# Chapter 6: Bytes & Text" + "# Chapter 6: Text & Bytes" ] }, { @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb) of the book. Then, work through the questions below." + "The questions below assume that you have read [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb) in the book.\n", + "\n", + "Be concise in your answers! Most questions can be answered in *one* sentence." ] }, { @@ -47,7 +48,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -61,7 +62,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -80,7 +81,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -94,7 +95,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -122,7 +123,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -136,7 +137,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -150,7 +151,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -164,7 +165,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] } ], diff --git a/06_text_02_exercises.ipynb b/06_text_02_exercises.ipynb index d8fe96b..d488f52 100644 --- a/06_text_02_exercises.ipynb +++ b/06_text_02_exercises.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", "# Chapter 6: Text & Bytes" ] }, @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb) of the book. Then, work through the exercises below. The `...` indicate where you need to fill in your answers. You should not need to create any additional code cells." + "The exercises below assume that you have read [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb) in the book.\n", + "\n", + "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." ] }, { @@ -86,21 +87,25 @@ " Returns:\n", " is_palindrome (bool)\n", " \"\"\"\n", - " is_palindrome = ... # Q3\n", + " # answer to Q3\n", + " is_palindrome = ...\n", " if ignore_case:\n", - " ... # Q3\n", - " chars_to_check = # Q1\n", + " ...\n", + " # answer to Q1\n", + " chars_to_check = ...\n", "\n", " for forward_index in range(chars_to_check):\n", - " backward_index = ... # Q2\n", - " forward = ... # Q2\n", - " backward = ... # Q2\n", + " # answer to Q2\n", + " backward_index = ...\n", + " forward = ...\n", + " backward = ...\n", "\n", " print(forward, \"and\", backward) # added for didactical purposes\n", "\n", - " if ...: # Q3\n", - " is_palindrome = ... # Q3\n", - " ... # Q3\n", + " # answer to Q3\n", + " if ...:\n", + " is_palindrome = ...\n", + " ...\n", "\n", " return is_palindrome" ] @@ -237,18 +242,21 @@ " Returns:\n", " is_palindrome (bool)\n", " \"\"\"\n", - " is_palindrome = ... # Q5\n", + " # answers from above\n", + " is_palindrome = ...\n", " if ignore_case:\n", - " ... # Q5\n", - " chars_to_check = # Q5\n", + " ...\n", + " chars_to_check = ...\n", "\n", - " for ... in ...: #Q6\n", + " # answer to Q6\n", + " for ... in ...:\n", "\n", " print(forward, \"and\", backward) # added for didactical purposes\n", "\n", - " if ...: # Q5\n", - " is_palindrome = ... # Q5\n", - " ... # Q5\n", + " # answers from above\n", + " if ...:\n", + " is_palindrome = ...\n", + " ...\n", "\n", " return is_palindrome" ] @@ -337,6 +345,7 @@ " Returns:\n", " is_palindrome (bool)\n", " \"\"\"\n", + " # answers from above\n", " if ignore_case:\n", " ...\n", " chars_to_check = ...\n", @@ -346,9 +355,11 @@ " print(forward, \"and\", backward) # added for didactical purposes\n", "\n", " if ...:\n", - " ... # Q8\n", + " # answer to Q8\n", + " ...\n", "\n", - " ... # Q8" + " # answer to Q8\n", + " return ..." ] }, { @@ -462,7 +473,9 @@ " Returns:\n", " is_palindrome (bool)\n", " \"\"\"\n", - " ... # Q11\n", + " # answer to Q11\n", + " ...\n", + " # answers from above\n", " if ignore_case:\n", " text = ...\n", " chars_to_check = ...\n", @@ -471,7 +484,7 @@ " if ...:\n", " ...\n", "\n", - " ..." + " return ..." ] }, { @@ -584,19 +597,22 @@ " Returns:\n", " is_palindrome (bool)\n", " \"\"\"\n", + " # answers from above\n", " ...\n", " if ignore_case:\n", " ...\n", + " # answer to Q13\n", " if ignore_symbols:\n", - " for ... in ...: # Q13\n", - " ... # Q13\n", + " for ... in ...:\n", + " ...\n", + " # answers from above\n", " chars_to_check = ...\n", "\n", " for ... in ...:\n", " if ...:\n", " ...\n", "\n", - " ..." + " return ..." ] }, { @@ -782,6 +798,7 @@ " Returns:\n", " is_palindrome (bool)\n", " \"\"\"\n", + " # answers from above\n", " ...\n", " if ignore_case:\n", " ...\n", @@ -789,12 +806,14 @@ " for ... in ...:\n", " ...\n", "\n", - " if ...: # Q16\n", - " ... # Q16\n", - " elif ...: # Q16\n", - " ... # Q16\n", + " # answer to Q16\n", + " if ...:\n", + " ...\n", + " elif ...:\n", + " ...\n", "\n", - " return ... # Q17" + " # answer to Q17\n", + " return ..." ] }, { @@ -955,7 +974,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.4" }, "toc": { "base_numbering": 1, diff --git a/07_sequences_00_lecture.ipynb b/07_sequences_00_lecture.ipynb index e3887a4..fc97607 100644 --- a/07_sequences_00_lecture.ipynb +++ b/07_sequences_00_lecture.ipynb @@ -1,5 +1,53 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A **video presentation** of the contents in this chapter is shown below. A playlist with *all* chapters as videos is linked [here](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChALCAgOCggIDRYNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxgVERUWFxcYExMYGBgVFRgWFRYWGBcVGxIaEhMXFRoYGBISFRcVFRUVFRUVFRUVGBUSFxIVFf/AABEIAWgB4AMBIgACEQEDEQH/xAAdAAEAAgIDAQEAAAAAAAAAAAAABgcFCAIDBAEJ/8QAURAAAQQBAgMBCQgRAgUEAgMAAQACAwQRBRIGEyExBxQYIjJBVZTVCBUXUVJhk9QjMzVCU1RxcnN0dYGSsbKz05G0FiQ2YrU0gqGiY3YlQ0X/xAAcAQEAAgMBAQEAAAAAAAAAAAAAAgQBAwUHBgj/xAA9EQABAwIDBQUGBAYBBQEAAAABAAIRAyEEEjEFQVFhcRMVU4GRBiIyocHwFjRysRQ1QlLR4fEjM0NigpL/2gAMAwEAAhEDEQA/ANMkREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXFX4/w/wCtaj7OTwKuKvx/h/1rUfZyItZkWzPgVcVfj/D/AK1qPs5PAq4q/H+H/WtR9nIi1mRbM+BVxV+P8P8ArWo+zk8Crir8f4f9a1H2ciLWZFsz4FXF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hodQ0EBkkco21dQ8qJ4e0HOodmWhZBgrB0X6DItAPDV4q9H8P+q6j7RTw1eKvR/D/quo+0VhZW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/6LQDw1eKvR/D/AKrqPtFPDV4q9H8P+q6j7RRFv+i0A8NXir0fw/6rqPtFPDV4q9H8P+q6j7RRFv8AotAPDV4q9H8P+q6j7RTw1eKvR/D/AKrqPtFEW/6LQDw1eKvR/D/quo+0U8NXir0fw/6rqPtFEW/682q/aJ/0Mn9DloT4avFXo/h/1XUfaK4WPdo8UvY9hoaBh7XNOKuo5w4EHGdR7eqItaURERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERf/2Q==\n", + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo(\"nx2sCDoeC3I\", width=\"60%\")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -23,7 +71,7 @@ "\n", "The `str` type is a bit of a corner case in this regard. While one could argue that a longer `str` object, for example, `\"text\"`, is composed of individual characters, this is *not* the case in memory as the literal `\"text\"` only creates *one* object (i.e., one \"bag\" of $0$s and $1$s modeling all characters).\n", "\n", - "This chapter, [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb), and [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_arrays_00_lecture.ipynb) introduce various \"complex\" data types. While some are mutable and others are not, they all share that they are primarily used to \"manage,\" or structure, the memory in a program. Unsurprisingly, computer scientists refer to the ideas and theories behind these data types as **[data structures](https://en.wikipedia.org/wiki/Data_structure)**.\n", + "This chapter, [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_lecture.ipynb), and [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_lecture.ipynb) introduce various \"complex\" data types. While some are mutable and others are not, they all share that they are primarily used to \"manage,\" or structure, the memory in a program. Unsurprisingly, computer scientists refer to the ideas and theories behind these data types as **[data structures](https://en.wikipedia.org/wiki/Data_structure)**.\n", "\n", "In this chapter, we focus on data types that model all kinds of sequential data. Examples of such data are [spreadsheets](https://en.wikipedia.org/wiki/Spreadsheet) or [matrices](https://en.wikipedia.org/wiki/Matrix_%28mathematics%29)/[vectors](https://en.wikipedia.org/wiki/Vector_%28mathematics_and_physics%29). Such formats share the property that they are composed of smaller units that come in a sequence of, for example, rows/columns/cells or elements/entries." ] @@ -47,16 +95,16 @@ } }, "source": [ - "[Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb#A-\"String\"-of-Characters) already describes the *sequence* properties of `str` objects. Here, we take a step back and study these properties on their own before looking at bigger ideas.\n", + "[Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb#A-\"String\"-of-Characters) already describes the **sequence** properties of `str` objects. In this section, we take a step back and study these properties one by one.\n", "\n", - "The [collections.abc](https://docs.python.org/3/library/collections.abc.html) module in the [standard library](https://docs.python.org/3/library/index.html) defines a variety of **abstract base classes** (ABCs). We saw ABCs already in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb#The-Numerical-Tower), where we use the ones from the [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) to classify Python's numeric data types according to mathematical ideas. Now, we take the ABCs from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module to classify the data types in this chapter and [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb) according to their behavior in various contexts.\n", + "The [collections.abc](https://docs.python.org/3/library/collections.abc.html) module in the [standard library](https://docs.python.org/3/library/index.html) defines a variety of **abstract base classes** (ABCs). We saw ABCs already in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb#The-Numerical-Tower), where we use the ones from the [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) to classify Python's numeric data types according to mathematical ideas. Now, we take the ABCs from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module to classify the data types in this chapter according to their behavior in various contexts.\n", "\n", "As an illustration, consider `numbers` and `text` below, two objects of *different* types." ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "slideshow": { "slide_type": "slide" @@ -65,7 +113,7 @@ "outputs": [], "source": [ "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]\n", - "text = \"Lorem ipsum dolor sit amet, ...\"" + "text = \"Lorem ipsum dolor sit amet.\"" ] }, { @@ -81,7 +129,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" @@ -103,10 +151,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -114,7 +162,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "L o r e m i p s u m d o l o r s i t a m e t , . . . " + "L o r e m i p s u m d o l o r s i t a m e t . " ] } ], @@ -138,7 +186,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "slideshow": { "slide_type": "slide" @@ -151,7 +199,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "slideshow": { "slide_type": "fragment" @@ -164,7 +212,7 @@ "collections.abc.Iterable" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -181,14 +229,14 @@ } }, "source": [ - "As in the context of *goose typing* in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb#Goose-Typing), we can use ABCs with the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to check if an object supports a behavior.\n", + "As seen in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb#Goose-Typing), we can use ABCs with the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to check if an object supports a behavior.\n", "\n", "So, let's \"ask\" Python if it can loop over `numbers` or `text`." ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "slideshow": { "slide_type": "slide" @@ -201,7 +249,7 @@ "True" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -212,10 +260,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -225,7 +273,7 @@ "True" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -247,10 +295,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -260,7 +308,7 @@ "False" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -282,7 +330,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "slideshow": { "slide_type": "skip" @@ -296,7 +344,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mdigit\u001b[0m \u001b[0;32min\u001b[0m \u001b[0;36m999\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdigit\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mdigit\u001b[0m \u001b[0;32min\u001b[0m \u001b[0;36m999\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdigit\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mTypeError\u001b[0m: 'int' object is not iterable" ] } @@ -324,7 +372,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": { "slideshow": { "slide_type": "slide" @@ -337,48 +385,13 @@ "False" ] }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "0 in numbers" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "\"l\" in text" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Alternatively, we could also check if `numbers` and `text` are `Container` types with [isinstance()](https://docs.python.org/3/library/functions.html#isinstance)." + "0 in numbers" ] }, { @@ -402,7 +415,18 @@ } ], "source": [ - "isinstance(numbers, abc.Container)" + "\"l\" in text" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Alternatively, we could also check if `numbers` and `text` are `Container` types with [isinstance()](https://docs.python.org/3/library/functions.html#isinstance)." ] }, { @@ -410,7 +434,7 @@ "execution_count": 13, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -425,6 +449,30 @@ "output_type": "execute_result" } ], + "source": [ + "isinstance(numbers, abc.Container)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "isinstance(text, abc.Container)" ] @@ -442,10 +490,10 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -455,7 +503,7 @@ "False" ] }, - "execution_count": 14, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -466,7 +514,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": { "slideshow": { "slide_type": "skip" @@ -480,7 +528,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;36m9\u001b[0m \u001b[0;32min\u001b[0m \u001b[0;36m999\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;36m9\u001b[0m \u001b[0;32min\u001b[0m \u001b[0;36m999\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: argument of type 'int' is not iterable" ] } @@ -502,7 +550,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": { "slideshow": { "slide_type": "slide" @@ -515,37 +563,13 @@ "12" ] }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(numbers)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "31" - ] - }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "len(text)" + "len(numbers)" ] }, { @@ -560,7 +584,7 @@ { "data": { "text/plain": [ - "True" + "27" ] }, "execution_count": 18, @@ -569,7 +593,7 @@ } ], "source": [ - "isinstance(numbers, abc.Sized)" + "len(text)" ] }, { @@ -577,7 +601,7 @@ "execution_count": 19, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -592,6 +616,30 @@ "output_type": "execute_result" } ], + "source": [ + "isinstance(numbers, abc.Sized)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "isinstance(text, abc.Sized)" ] @@ -609,10 +657,10 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -622,7 +670,7 @@ "False" ] }, - "execution_count": 20, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -633,7 +681,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": { "slideshow": { "slide_type": "skip" @@ -647,7 +695,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m999\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m999\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: object of type 'int' has no len()" ] } @@ -673,7 +721,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": { "slideshow": { "slide_type": "slide" @@ -686,7 +734,7 @@ "True" ] }, - "execution_count": 22, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -697,10 +745,10 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -710,7 +758,7 @@ "True" ] }, - "execution_count": 23, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -734,7 +782,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 25, "metadata": { "slideshow": { "slide_type": "slide" @@ -756,10 +804,10 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -767,7 +815,7 @@ "name": "stdout", "output_type": "stream", "text": [ - ". . . , t e m a t i s r o l o d m u s p i m e r o L " + ". t e m a t i s r o l o d m u s p i m e r o L " ] } ], @@ -778,7 +826,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": { "slideshow": { "slide_type": "fragment" @@ -791,7 +839,7 @@ "True" ] }, - "execution_count": 26, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -802,10 +850,10 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 28, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -815,7 +863,7 @@ "True" ] }, - "execution_count": 27, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -837,7 +885,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 29, "metadata": { "slideshow": { "slide_type": "slide" @@ -850,7 +898,7 @@ "True" ] }, - "execution_count": 28, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -861,10 +909,10 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 30, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -874,7 +922,7 @@ "True" ] }, - "execution_count": 29, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -895,7 +943,7 @@ "\n", "In Python-related documentations, the terms collection and sequence are heavily used, and the data science practitioner should always think of them in terms of the three or four behaviors they exhibit.\n", "\n", - "Data types that are collections but not sequences are covered in Chapter 8." + "Data types that are collections but not sequences are covered in [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_lecture.ipynb)." ] }, { @@ -922,7 +970,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 31, "metadata": { "slideshow": { "slide_type": "slide" @@ -935,10 +983,10 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 32, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -959,7 +1007,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 33, "metadata": { "slideshow": { "slide_type": "fragment" @@ -983,10 +1031,10 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 34, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -996,7 +1044,7 @@ "[[], 10, 20.0, 'Thirty', [40, 50]]" ] }, - "execution_count": 33, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } @@ -1018,20 +1066,20 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 35, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ { "data": { "text/plain": [ - "140417317434464" + "139941444092304" ] }, - "execution_count": 34, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } @@ -1042,10 +1090,10 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 36, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -1055,7 +1103,7 @@ "list" ] }, - "execution_count": 35, + "execution_count": 36, "metadata": {}, "output_type": "execute_result" } @@ -1072,14 +1120,14 @@ } }, "source": [ - "Alternatively, we use the [list()](https://docs.python.org/3/library/functions.html#func-list) built-in to create a `list` object out of an iterable we pass to it as the argument.\n", + "Alternatively, we use the built-in [list()](https://docs.python.org/3/library/functions.html#func-list) constructor to create a `list` object out of any (finite) *iterable* we pass to it as the argument.\n", "\n", "For example, we can wrap the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in with [list()](https://docs.python.org/3/library/functions.html#func-list): As described in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Containers-vs.-Iterables), `range` objects, like `range(1, 13)` below, are iterable and generate `int` objects \"on the fly\" (i.e., one by one). The [list()](https://docs.python.org/3/library/functions.html#func-list) around it acts like a `for`-loop and **materializes** twelve `int` objects in memory that then become the elements of the newly created `list` object. [PythonTutor](http://www.pythontutor.com/visualize.html#code=r%20%3D%20range%281,%2013%29%0Al%20%3D%20list%28range%281,%2013%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows this difference visually." ] }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 37, "metadata": { "slideshow": { "slide_type": "slide" @@ -1092,37 +1140,13 @@ "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]" ] }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(range(1, 13))" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "isinstance(range(1, 13), abc.Iterable)" + "list(range(1, 13))" ] }, { @@ -1233,7 +1257,7 @@ " - supports being looped over\n", " - works with the `for` or `while` statements\n", "- `Reversible`:\n", - " - the elements come in a *predictable* order that we may traverse in a forward or backward fashion\n", + " - the elements come in a *predictable* order that we may loop over in a forward or backward fashion\n", " - works with the [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in\n", "- `Sized`:\n", " - the number of elements is finite *and* known in advance\n", @@ -1291,7 +1315,7 @@ "execution_count": 41, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" } }, "outputs": [ @@ -1299,17 +1323,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "[] \t140417315676720 \t\n", - "10 \t94860849595456 \t\n", - "20.0 \t140417316476784 \t\n", - "Thirty \t140417315739568 \t\n", - "[40, 50] \t140417315720800 \t\n" + "[] 139941463482272 \n", + "10 94715524076608 \n", + "20.0 139941444613712 \n", + "Thirty 139941444470960 \n", + "[40, 50] 139941444068128 \n" ] } ], "source": [ "for element in nested:\n", - " print(element, id(element), type(element), sep=\" \\t\")" + " print(str(element).ljust(10), str(id(element)).ljust(18), type(element))" ] }, { @@ -1317,7 +1341,7 @@ "execution_count": 42, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" } }, "outputs": [ @@ -1409,7 +1433,7 @@ "execution_count": 45, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1464,7 +1488,7 @@ { "data": { "text/plain": [ - "10" + "[]" ] }, "execution_count": 46, @@ -1473,7 +1497,7 @@ } ], "source": [ - "nested[1]" + "nested[0]" ] }, { @@ -1492,7 +1516,7 @@ "execution_count": 47, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -1552,7 +1576,7 @@ "execution_count": 49, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1635,7 +1659,7 @@ "execution_count": 51, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1888,7 +1912,7 @@ "execution_count": 61, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1949,7 +1973,7 @@ "execution_count": 63, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -1986,7 +2010,7 @@ "execution_count": 64, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -2017,7 +2041,7 @@ { "data": { "text/plain": [ - "140417315676720" + "139941463482272" ] }, "execution_count": 65, @@ -2041,7 +2065,7 @@ { "data": { "text/plain": [ - "140417315676720" + "139941463482272" ] }, "execution_count": 66, @@ -2053,30 +2077,6 @@ "id(nested_copy[0])" ] }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "140417315676720" - ] - }, - "execution_count": 67, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "id(empty)" - ] - }, { "cell_type": "markdown", "metadata": { @@ -2096,7 +2096,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 67, "metadata": { "slideshow": { "slide_type": "skip" @@ -2109,7 +2109,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 68, "metadata": { "slideshow": { "slide_type": "skip" @@ -2122,7 +2122,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 69, "metadata": { "slideshow": { "slide_type": "skip" @@ -2135,7 +2135,7 @@ "True" ] }, - "execution_count": 70, + "execution_count": 69, "metadata": {}, "output_type": "execute_result" } @@ -2157,7 +2157,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 70, "metadata": { "slideshow": { "slide_type": "skip" @@ -2170,7 +2170,7 @@ "False" ] }, - "execution_count": 71, + "execution_count": 70, "metadata": {}, "output_type": "execute_result" } @@ -2179,6 +2179,30 @@ "nested[0] is nested_deep_copy[0]" ] }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "139941463482272" + ] + }, + "execution_count": 71, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "id(nested[0])" + ] + }, { "cell_type": "code", "execution_count": 72, @@ -2191,7 +2215,7 @@ { "data": { "text/plain": [ - "140417315676720" + "139941444435792" ] }, "execution_count": 72, @@ -2199,30 +2223,6 @@ "output_type": "execute_result" } ], - "source": [ - "id(nested[0])" - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "140417376809600" - ] - }, - "execution_count": 73, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "id(nested_deep_copy[0])" ] @@ -2262,7 +2262,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 73, "metadata": { "slideshow": { "slide_type": "slide" @@ -2275,10 +2275,10 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 74, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2288,7 +2288,7 @@ "[0, 10, 20.0, 'Thirty', [40, 50]]" ] }, - "execution_count": 75, + "execution_count": 74, "metadata": {}, "output_type": "execute_result" } @@ -2310,7 +2310,7 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 75, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2318,15 +2318,15 @@ }, "outputs": [], "source": [ - "nested[:4] = [100, 100, 100] # assign three elements where there were four before" + "nested[:4] = [100, 100, 100]" ] }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 76, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2336,7 +2336,7 @@ "[100, 100, 100, [40, 50]]" ] }, - "execution_count": 77, + "execution_count": 76, "metadata": {}, "output_type": "execute_result" } @@ -2347,10 +2347,10 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 77, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2360,7 +2360,7 @@ "4" ] }, - "execution_count": 78, + "execution_count": 77, "metadata": {}, "output_type": "execute_result" } @@ -2382,7 +2382,7 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 78, "metadata": { "slideshow": { "slide_type": "skip" @@ -2392,10 +2392,10 @@ { "data": { "text/plain": [ - "140417317434464" + "139941444092304" ] }, - "execution_count": 79, + "execution_count": 78, "metadata": {}, "output_type": "execute_result" } @@ -2417,7 +2417,7 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 79, "metadata": { "slideshow": { "slide_type": "slide" @@ -2430,7 +2430,7 @@ "[[], 10, 20.0, 'Thirty', [40, 50]]" ] }, - "execution_count": 80, + "execution_count": 79, "metadata": {}, "output_type": "execute_result" } @@ -2452,10 +2452,10 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 80, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -2465,10 +2465,10 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 81, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2478,7 +2478,7 @@ "[[], 10, 20.0, 'Thirty', [1, 2, 3]]" ] }, - "execution_count": 82, + "execution_count": 81, "metadata": {}, "output_type": "execute_result" } @@ -2500,7 +2500,7 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 82, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2513,7 +2513,7 @@ "[100, 100, 100, [1, 2, 3]]" ] }, - "execution_count": 83, + "execution_count": 82, "metadata": {}, "output_type": "execute_result" } @@ -2537,7 +2537,7 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 83, "metadata": { "slideshow": { "slide_type": "slide" @@ -2550,10 +2550,10 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 84, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2563,7 +2563,7 @@ "[100, 100, 100]" ] }, - "execution_count": 85, + "execution_count": 84, "metadata": {}, "output_type": "execute_result" } @@ -2585,7 +2585,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 85, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2598,10 +2598,10 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 86, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2611,7 +2611,7 @@ "[]" ] }, - "execution_count": 87, + "execution_count": 86, "metadata": {}, "output_type": "execute_result" } @@ -2628,33 +2628,7 @@ } }, "source": [ - "Mutability for sequences is formalized by the `MutableSequence` ABC in the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module.\n", - "\n", - "So, we can als \"ask\" Python if `nested` is mutable." - ] - }, - { - "cell_type": "code", - "execution_count": 88, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 88, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "isinstance(nested, abc.MutableSequence)" + "Mutability for sequences is formalized by the `MutableSequence` ABC in the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module." ] }, { @@ -2685,7 +2659,7 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 87, "metadata": { "slideshow": { "slide_type": "slide" @@ -2709,7 +2683,7 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 88, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2722,10 +2696,10 @@ }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 89, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2735,7 +2709,7 @@ "['Carl', 'Peter', 'Eckardt']" ] }, - "execution_count": 91, + "execution_count": 89, "metadata": {}, "output_type": "execute_result" } @@ -2757,10 +2731,10 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": 90, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" } }, "outputs": [], @@ -2770,10 +2744,10 @@ }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 91, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2783,7 +2757,7 @@ "['Carl', 'Peter', 'Eckardt', 'Karl', 'Oliver']" ] }, - "execution_count": 93, + "execution_count": 91, "metadata": {}, "output_type": "execute_result" } @@ -2805,10 +2779,10 @@ }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 92, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" } }, "outputs": [], @@ -2816,12 +2790,82 @@ "names.insert(1, \"Berthold\")" ] }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Carl', 'Berthold', 'Peter', 'Eckardt', 'Karl', 'Oliver']" + ] + }, + "execution_count": 93, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "`list` objects may be sorted *in place* with the [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) method. That is different from the built-in [sorted()](https://docs.python.org/3/library/functions.html#sorted) function that takes any *finite* and *iterable* object and returns a *new* `list` object with the iterable's elements sorted!" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Berthold', 'Carl', 'Eckardt', 'Karl', 'Oliver', 'Peter']" + ] + }, + "execution_count": 94, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(names)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "As the previous code cell created a *new* `list` object, `names` is still unsorted." + ] + }, { "cell_type": "code", "execution_count": 95, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2840,76 +2884,6 @@ "names" ] }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "`list` objects may be sorted *in place* with the [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) method. That is different from the built-in [sorted()](https://docs.python.org/3/library/functions.html#sorted) function that takes any *finite* and *iterable* object and returns a *new* `list` object with the iterable's elements sorted!" - ] - }, - { - "cell_type": "code", - "execution_count": 96, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Berthold', 'Carl', 'Eckardt', 'Karl', 'Oliver', 'Peter']" - ] - }, - "execution_count": 96, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sorted(names)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "As the previous code cell created a *new* `list` object, `names` is still unsorted." - ] - }, - { - "cell_type": "code", - "execution_count": 97, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Carl', 'Berthold', 'Peter', 'Eckardt', 'Karl', 'Oliver']" - ] - }, - "execution_count": 97, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names" - ] - }, { "cell_type": "markdown", "metadata": { @@ -2923,7 +2897,7 @@ }, { "cell_type": "code", - "execution_count": 98, + "execution_count": 96, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2936,10 +2910,10 @@ }, { "cell_type": "code", - "execution_count": 99, + "execution_count": 97, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2949,7 +2923,7 @@ "['Berthold', 'Carl', 'Eckardt', 'Karl', 'Oliver', 'Peter']" ] }, - "execution_count": 99, + "execution_count": 97, "metadata": {}, "output_type": "execute_result" } @@ -2971,7 +2945,7 @@ }, { "cell_type": "code", - "execution_count": 100, + "execution_count": 98, "metadata": { "slideshow": { "slide_type": "slide" @@ -2984,10 +2958,10 @@ }, { "cell_type": "code", - "execution_count": 101, + "execution_count": 99, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -2997,7 +2971,7 @@ "['Peter', 'Oliver', 'Karl', 'Eckardt', 'Carl', 'Berthold']" ] }, - "execution_count": 101, + "execution_count": 99, "metadata": {}, "output_type": "execute_result" } @@ -3025,7 +2999,7 @@ }, { "cell_type": "code", - "execution_count": 102, + "execution_count": 100, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3051,10 +3025,10 @@ }, { "cell_type": "code", - "execution_count": 103, + "execution_count": 101, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3064,7 +3038,7 @@ "['Karl', 'Carl', 'Peter', 'Oliver', 'Eckardt', 'Berthold']" ] }, - "execution_count": 103, + "execution_count": 101, "metadata": {}, "output_type": "execute_result" } @@ -3086,10 +3060,10 @@ }, { "cell_type": "code", - "execution_count": 104, + "execution_count": 102, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" } }, "outputs": [], @@ -3099,10 +3073,10 @@ }, { "cell_type": "code", - "execution_count": 105, + "execution_count": 103, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3112,7 +3086,7 @@ "['Berthold', 'Eckardt', 'Oliver', 'Peter', 'Carl', 'Karl']" ] }, - "execution_count": 105, + "execution_count": 103, "metadata": {}, "output_type": "execute_result" } @@ -3134,7 +3108,7 @@ }, { "cell_type": "code", - "execution_count": 106, + "execution_count": 104, "metadata": { "slideshow": { "slide_type": "slide" @@ -3147,10 +3121,10 @@ }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 105, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3160,7 +3134,7 @@ "'Karl'" ] }, - "execution_count": 107, + "execution_count": 105, "metadata": {}, "output_type": "execute_result" } @@ -3171,10 +3145,10 @@ }, { "cell_type": "code", - "execution_count": 108, + "execution_count": 106, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3184,7 +3158,7 @@ "['Berthold', 'Eckardt', 'Oliver', 'Peter', 'Carl']" ] }, - "execution_count": 108, + "execution_count": 106, "metadata": {}, "output_type": "execute_result" } @@ -3208,7 +3182,7 @@ }, { "cell_type": "code", - "execution_count": 109, + "execution_count": 107, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3221,10 +3195,10 @@ }, { "cell_type": "code", - "execution_count": 110, + "execution_count": 108, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3234,7 +3208,7 @@ "'Eckardt'" ] }, - "execution_count": 110, + "execution_count": 108, "metadata": {}, "output_type": "execute_result" } @@ -3245,10 +3219,10 @@ }, { "cell_type": "code", - "execution_count": 111, + "execution_count": 109, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3258,7 +3232,7 @@ "['Berthold', 'Oliver', 'Peter', 'Carl']" ] }, - "execution_count": 111, + "execution_count": 109, "metadata": {}, "output_type": "execute_result" } @@ -3280,7 +3254,7 @@ }, { "cell_type": "code", - "execution_count": 112, + "execution_count": 110, "metadata": { "slideshow": { "slide_type": "slide" @@ -3293,10 +3267,10 @@ }, { "cell_type": "code", - "execution_count": 113, + "execution_count": 111, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3306,7 +3280,7 @@ "['Berthold', 'Oliver', 'Carl']" ] }, - "execution_count": 113, + "execution_count": 111, "metadata": {}, "output_type": "execute_result" } @@ -3328,7 +3302,7 @@ }, { "cell_type": "code", - "execution_count": 114, + "execution_count": 112, "metadata": { "slideshow": { "slide_type": "skip" @@ -3342,7 +3316,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnames\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mremove\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Peter\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnames\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mremove\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Peter\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: list.remove(x): x not in list" ] } @@ -3364,7 +3338,7 @@ }, { "cell_type": "code", - "execution_count": 115, + "execution_count": 113, "metadata": { "slideshow": { "slide_type": "slide" @@ -3377,7 +3351,7 @@ "['Berthold', 'Oliver', 'Carl']" ] }, - "execution_count": 115, + "execution_count": 113, "metadata": {}, "output_type": "execute_result" } @@ -3388,10 +3362,10 @@ }, { "cell_type": "code", - "execution_count": 116, + "execution_count": 114, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3401,7 +3375,7 @@ "1" ] }, - "execution_count": 116, + "execution_count": 114, "metadata": {}, "output_type": "execute_result" } @@ -3412,10 +3386,10 @@ }, { "cell_type": "code", - "execution_count": 117, + "execution_count": 115, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3426,7 +3400,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnames\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Karl\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnames\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Karl\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: 'Karl' is not in list" ] } @@ -3448,7 +3422,7 @@ }, { "cell_type": "code", - "execution_count": 118, + "execution_count": 116, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3461,7 +3435,7 @@ "1" ] }, - "execution_count": 118, + "execution_count": 116, "metadata": {}, "output_type": "execute_result" } @@ -3472,7 +3446,7 @@ }, { "cell_type": "code", - "execution_count": 119, + "execution_count": 117, "metadata": { "slideshow": { "slide_type": "skip" @@ -3485,7 +3459,7 @@ "0" ] }, - "execution_count": 119, + "execution_count": 117, "metadata": {}, "output_type": "execute_result" } @@ -3509,10 +3483,10 @@ }, { "cell_type": "code", - "execution_count": 120, + "execution_count": 118, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [], @@ -3522,10 +3496,10 @@ }, { "cell_type": "code", - "execution_count": 121, + "execution_count": 119, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -3535,7 +3509,7 @@ "['Berthold', 'Oliver', 'Carl']" ] }, - "execution_count": 121, + "execution_count": 119, "metadata": {}, "output_type": "execute_result" } @@ -3557,10 +3531,10 @@ }, { "cell_type": "code", - "execution_count": 122, + "execution_count": 120, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [], @@ -3570,10 +3544,10 @@ }, { "cell_type": "code", - "execution_count": 123, + "execution_count": 121, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -3583,7 +3557,7 @@ "[]" ] }, - "execution_count": 123, + "execution_count": 121, "metadata": {}, "output_type": "execute_result" } @@ -3629,7 +3603,7 @@ }, { "cell_type": "code", - "execution_count": 124, + "execution_count": 122, "metadata": { "slideshow": { "slide_type": "slide" @@ -3642,7 +3616,7 @@ "['Berthold', 'Oliver', 'Carl']" ] }, - "execution_count": 124, + "execution_count": 122, "metadata": {}, "output_type": "execute_result" } @@ -3653,23 +3627,10 @@ }, { "cell_type": "code", - "execution_count": 125, + "execution_count": 123, "metadata": { "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "more_names = [\"Diedrich\", \"Yves\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 126, - "metadata": { - "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3679,21 +3640,21 @@ "['Berthold', 'Oliver', 'Carl', 'Diedrich', 'Yves']" ] }, - "execution_count": 126, + "execution_count": 123, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "names + more_names" + "names + [\"Diedrich\", \"Yves\"]" ] }, { "cell_type": "code", - "execution_count": 127, + "execution_count": 124, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3703,7 +3664,7 @@ "['Berthold', 'Oliver', 'Carl', 'Berthold', 'Oliver', 'Carl']" ] }, - "execution_count": 127, + "execution_count": 124, "metadata": {}, "output_type": "execute_result" } @@ -3712,30 +3673,6 @@ "2 * names" ] }, - { - "cell_type": "code", - "execution_count": 128, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Diedrich', 'Yves', 'Diedrich', 'Yves', 'Diedrich', 'Yves']" - ] - }, - "execution_count": 128, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "more_names * 3" - ] - }, { "cell_type": "markdown", "metadata": { @@ -3751,7 +3688,7 @@ }, { "cell_type": "code", - "execution_count": 129, + "execution_count": 125, "metadata": { "slideshow": { "slide_type": "slide" @@ -3764,7 +3701,7 @@ "['Achim', 'Berthold', 'Oliver', 'Carl', 'Xavier']" ] }, - "execution_count": 129, + "execution_count": 125, "metadata": {}, "output_type": "execute_result" } @@ -3786,7 +3723,7 @@ }, { "cell_type": "code", - "execution_count": 130, + "execution_count": 126, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3799,7 +3736,7 @@ "['Achim', 'Berthold', 'Oliver', 'Carl', 'Xavier']" ] }, - "execution_count": 130, + "execution_count": 126, "metadata": {}, "output_type": "execute_result" } @@ -3834,7 +3771,7 @@ }, { "cell_type": "code", - "execution_count": 131, + "execution_count": 127, "metadata": { "slideshow": { "slide_type": "slide" @@ -3847,7 +3784,7 @@ "['Berthold', 'Oliver', 'Carl']" ] }, - "execution_count": 131, + "execution_count": 127, "metadata": {}, "output_type": "execute_result" } @@ -3858,55 +3795,7 @@ }, { "cell_type": "code", - "execution_count": 132, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 132, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names == [\"Berthold\", \"Oliver\", \"Carl\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 133, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 133, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names != [\"Berthold\", \"Oliver\", \"Karl\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 134, + "execution_count": 128, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3919,21 +3808,21 @@ "True" ] }, - "execution_count": 134, + "execution_count": 128, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "names < [\"Berthold\", \"Oliver\", \"Karl\"]" + "names == [\"Berthold\", \"Oliver\", \"Carl\"]" ] }, { "cell_type": "code", - "execution_count": 135, + "execution_count": 129, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -3943,13 +3832,37 @@ "True" ] }, - "execution_count": 135, + "execution_count": 129, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "[\"Achim\", \"Oliver\", \"Carl\"] < names" + "names != [\"Berthold\", \"Oliver\", \"Karl\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 130, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names < [\"Berthold\", \"Oliver\", \"Karl\"]" ] }, { @@ -3960,15 +3873,15 @@ } }, "source": [ - "If two `list` objects have a different number of elements and all overlapping elements compare equal, the shorter `list` object is considered \"smaller.\" That rule is a common cause for *semantic* errors in a program." + "If two `list` objects have a different number of elements and all overlapping elements compare equal, the shorter `list` object is considered \"smaller.\"" ] }, { "cell_type": "code", - "execution_count": 136, + "execution_count": 131, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "fragment" } }, "outputs": [ @@ -3978,37 +3891,13 @@ "True" ] }, - "execution_count": 136, + "execution_count": 131, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "[\"Berthold\", \"Oliver\"] < names" - ] - }, - { - "cell_type": "code", - "execution_count": 137, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 137, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names < [\"Berthold\", \"Oliver\", \"Carl\", \"Xavier\"]" + "[\"Berthold\", \"Oliver\"] < names < [\"Berthold\", \"Oliver\", \"Carl\", \"Xavier\"]" ] }, { @@ -4037,7 +3926,7 @@ }, { "cell_type": "code", - "execution_count": 138, + "execution_count": 132, "metadata": { "slideshow": { "slide_type": "slide" @@ -4050,10 +3939,10 @@ }, { "cell_type": "code", - "execution_count": 139, + "execution_count": 133, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -4074,12 +3963,12 @@ "source": [ "While this function is being executed, two variables, namely `letters` in the global scope and `arg` inside the function's local scope, reference the *same* `list` object in memory. Furthermore, the passed in `arg` is also the return value.\n", "\n", - "So, after the function call, `letters_with_xyz` and `letters` are **aliases** as well, referencing the *same* object." + "So, after the function call, `letters_with_xyz` and `letters` are **aliases** as well, referencing the *same* object. We can also visualize that with [PythonTutor](http://www.pythontutor.com/visualize.html#code=letters%20%3D%20%5B%22a%22,%20%22b%22,%20%22c%22%5D%0A%0Adef%20add_xyz%28arg%29%3A%0A%20%20%20%20arg.extend%28%5B%22x%22,%20%22y%22,%20%22z%22%5D%29%0A%20%20%20%20return%20arg%0A%0Aletters_with_xyz%20%3D%20add_xyz%28letters%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)." ] }, { "cell_type": "code", - "execution_count": 140, + "execution_count": 134, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4092,10 +3981,10 @@ }, { "cell_type": "code", - "execution_count": 141, + "execution_count": 135, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -4105,7 +3994,7 @@ "['a', 'b', 'c', 'x', 'y', 'z']" ] }, - "execution_count": 141, + "execution_count": 135, "metadata": {}, "output_type": "execute_result" } @@ -4116,10 +4005,10 @@ }, { "cell_type": "code", - "execution_count": 142, + "execution_count": 136, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -4129,7 +4018,7 @@ "['a', 'b', 'c', 'x', 'y', 'z']" ] }, - "execution_count": 142, + "execution_count": 136, "metadata": {}, "output_type": "execute_result" } @@ -4148,14 +4037,14 @@ "source": [ "A better practice is to first create a copy of `arg` within the function that is then modified and returned. If we are sure that `arg` contains immutable elements only, we get away with a shallow copy. The downside of this approach is the higher amount of memory necessary.\n", "\n", - "The revised `add_xyz()` function below is more natural to reason about as it does *not* modify the passed in `arg` internally. This approach is following the **[functional programming](https://en.wikipedia.org/wiki/Functional_programming)** paradigm that is going through a \"renaissance\" currently. Two essential characteristics of functional programming are that a function *never* changes its inputs and *always* returns the same output given the same inputs.\n", + "The revised `add_xyz()` function below is more natural to reason about as it does *not* modify the passed in `arg` internally. [PythonTutor](http://www.pythontutor.com/visualize.html#code=letters%20%3D%20%5B%22a%22,%20%22b%22,%20%22c%22%5D%0A%0Adef%20add_xyz%28arg%29%3A%0A%20%20%20%20new_arg%20%3D%20arg%5B%3A%5D%0A%20%20%20%20new_arg.extend%28%5B%22x%22,%20%22y%22,%20%22z%22%5D%29%0A%20%20%20%20return%20new_arg%0A%0Aletters_with_xyz%20%3D%20add_xyz%28letters%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows that as well. This approach is following the **[functional programming](https://en.wikipedia.org/wiki/Functional_programming)** paradigm that is going through a \"renaissance\" currently. Two essential characteristics of functional programming are that a function *never* changes its inputs and *always* returns the same output given the same inputs.\n", "\n", "For a beginner, it is probably better to stick to this idea and not change any arguments as the original `add_xyz()` above. However, functions that modify and return the argument passed in are an important aspect of object-oriented programming, as explained in Chapter 10." ] }, { "cell_type": "code", - "execution_count": 143, + "execution_count": 137, "metadata": { "slideshow": { "slide_type": "slide" @@ -4168,24 +4057,24 @@ }, { "cell_type": "code", - "execution_count": 144, + "execution_count": 138, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], "source": [ "def add_xyz(arg):\n", " \"\"\"Create a new list from an existing one.\"\"\"\n", - " new_arg = arg[:] # a shallow copy is good enough here\n", + " new_arg = arg[:]\n", " new_arg.extend([\"x\", \"y\", \"z\"])\n", " return new_arg" ] }, { "cell_type": "code", - "execution_count": 145, + "execution_count": 139, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4198,11 +4087,11 @@ }, { "cell_type": "code", - "execution_count": 146, + "execution_count": 140, "metadata": { "scrolled": true, "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -4212,7 +4101,7 @@ "['a', 'b', 'c', 'x', 'y', 'z']" ] }, - "execution_count": 146, + "execution_count": 140, "metadata": {}, "output_type": "execute_result" } @@ -4223,10 +4112,10 @@ }, { "cell_type": "code", - "execution_count": 147, + "execution_count": 141, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -4236,7 +4125,7 @@ "['a', 'b', 'c']" ] }, - "execution_count": 147, + "execution_count": 141, "metadata": {}, "output_type": "execute_result" } @@ -4253,12 +4142,12 @@ } }, "source": [ - "If we want to modify the argument passed in, it is best to return `None` and not `arg`, as does the final version of `add_xyz()` below. Then, the user of our function cannot accidentally create two aliases to the same object. That is also why the list methods above all return `None`." + "If we want to modify the argument passed in, it is best to return `None` and not `arg`, as does the final version of `add_xyz()` below. Then, the user of our function cannot accidentally create two aliases to the same object. That is also why the list methods above all return `None`. [PythonTutor](http://www.pythontutor.com/visualize.html#code=letters%20%3D%20%5B%22a%22,%20%22b%22,%20%22c%22%5D%0A%0Adef%20add_xyz%28arg%29%3A%0A%20%20%20%20arg.extend%28%5B%22x%22,%20%22y%22,%20%22z%22%5D%29%0A%20%20%20%20return%0A%0Aadd_xyz%28letters%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows how there is only *one* reference to `letters` after the function call." ] }, { "cell_type": "code", - "execution_count": 148, + "execution_count": 142, "metadata": { "slideshow": { "slide_type": "slide" @@ -4271,10 +4160,10 @@ }, { "cell_type": "code", - "execution_count": 149, + "execution_count": 143, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -4282,12 +4171,12 @@ "def add_xyz(arg):\n", " \"\"\"Append letters to a list.\"\"\"\n", " arg.extend([\"x\", \"y\", \"z\"])\n", - " return # = None" + " return # None" ] }, { "cell_type": "code", - "execution_count": 150, + "execution_count": 144, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4300,10 +4189,10 @@ }, { "cell_type": "code", - "execution_count": 151, + "execution_count": 145, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -4313,7 +4202,7 @@ "['a', 'b', 'c', 'x', 'y', 'z']" ] }, - "execution_count": 151, + "execution_count": 145, "metadata": {}, "output_type": "execute_result" } @@ -4335,7 +4224,7 @@ }, { "cell_type": "code", - "execution_count": 152, + "execution_count": 146, "metadata": { "slideshow": { "slide_type": "skip" @@ -4348,7 +4237,7 @@ }, { "cell_type": "code", - "execution_count": 153, + "execution_count": 147, "metadata": { "slideshow": { "slide_type": "skip" @@ -4361,7 +4250,7 @@ "['a', 'b', 'c', 'x', 'y', 'z', 'x', 'y', 'z']" ] }, - "execution_count": 153, + "execution_count": 147, "metadata": {}, "output_type": "execute_result" } @@ -4405,7 +4294,7 @@ }, { "cell_type": "code", - "execution_count": 154, + "execution_count": 148, "metadata": { "slideshow": { "slide_type": "slide" @@ -4418,10 +4307,10 @@ }, { "cell_type": "code", - "execution_count": 155, + "execution_count": 149, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -4431,7 +4320,7 @@ "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" ] }, - "execution_count": 155, + "execution_count": 149, "metadata": {}, "output_type": "execute_result" } @@ -4453,10 +4342,10 @@ }, { "cell_type": "code", - "execution_count": 156, + "execution_count": 150, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [], @@ -4466,10 +4355,10 @@ }, { "cell_type": "code", - "execution_count": 157, + "execution_count": 151, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -4479,7 +4368,7 @@ "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" ] }, - "execution_count": 157, + "execution_count": 151, "metadata": {}, "output_type": "execute_result" } @@ -4499,6 +4388,150 @@ "As before, `numbers` is an object on its own." ] }, + { + "cell_type": "code", + "execution_count": 152, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "139941463332656" + ] + }, + "execution_count": 152, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "id(numbers)" + ] + }, + { + "cell_type": "code", + "execution_count": 153, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "tuple" + ] + }, + "execution_count": 153, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(numbers)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "While we could use empty parentheses `()` to create an empty `tuple` object ..." + ] + }, + { + "cell_type": "code", + "execution_count": 154, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "empty_tuple = ()" + ] + }, + { + "cell_type": "code", + "execution_count": 155, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "()" + ] + }, + "execution_count": 155, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "empty_tuple" + ] + }, + { + "cell_type": "code", + "execution_count": 156, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "tuple" + ] + }, + "execution_count": 156, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(empty_tuple)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "... we must use a *trailing comma* to create a `tuple` object holding one element. If we forget the comma, the parentheses are interpreted as the grouping operator and effectively useless!" + ] + }, + { + "cell_type": "code", + "execution_count": 157, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "one_tuple = (1,) # we could ommit the parentheses but not the comma" + ] + }, { "cell_type": "code", "execution_count": 158, @@ -4511,7 +4544,7 @@ { "data": { "text/plain": [ - "140417315626832" + "(1,)" ] }, "execution_count": 158, @@ -4520,7 +4553,7 @@ } ], "source": [ - "id(numbers)" + "one_tuple" ] }, { @@ -4544,18 +4577,7 @@ } ], "source": [ - "type(numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "While we could use empty parentheses `()` to create an empty `tuple` object ..." + "type(one_tuple)" ] }, { @@ -4568,7 +4590,7 @@ }, "outputs": [], "source": [ - "empty_tuple = ()" + "no_tuple = (1)" ] }, { @@ -4583,7 +4605,7 @@ { "data": { "text/plain": [ - "()" + "1" ] }, "execution_count": 161, @@ -4592,7 +4614,7 @@ } ], "source": [ - "empty_tuple" + "no_tuple" ] }, { @@ -4603,139 +4625,6 @@ "slide_type": "skip" } }, - "outputs": [ - { - "data": { - "text/plain": [ - "tuple" - ] - }, - "execution_count": 162, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(empty_tuple)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "... we must use a *trailing comma* to create a `tuple` object holding one element. If we forget the comma, the parentheses are interpreted as the grouping operator and effectively useless!" - ] - }, - { - "cell_type": "code", - "execution_count": 163, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "one_tuple = (1,) # we could ommit the parentheses but not the comma" - ] - }, - { - "cell_type": "code", - "execution_count": 164, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(1,)" - ] - }, - "execution_count": 164, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "one_tuple" - ] - }, - { - "cell_type": "code", - "execution_count": 165, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "tuple" - ] - }, - "execution_count": 165, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(one_tuple)" - ] - }, - { - "cell_type": "code", - "execution_count": 166, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "no_tuple = (1)" - ] - }, - { - "cell_type": "code", - "execution_count": 167, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 167, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "no_tuple" - ] - }, - { - "cell_type": "code", - "execution_count": 168, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, "outputs": [ { "data": { @@ -4743,7 +4632,7 @@ "int" ] }, - "execution_count": 168, + "execution_count": 162, "metadata": {}, "output_type": "execute_result" } @@ -4765,10 +4654,10 @@ }, { "cell_type": "code", - "execution_count": 169, + "execution_count": 163, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "slide" } }, "outputs": [ @@ -4778,7 +4667,7 @@ "(1,)" ] }, - "execution_count": 169, + "execution_count": 163, "metadata": {}, "output_type": "execute_result" } @@ -4789,7 +4678,7 @@ }, { "cell_type": "code", - "execution_count": 170, + "execution_count": 164, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4802,7 +4691,7 @@ "('i', 't', 'e', 'r', 'a', 'b', 'l', 'e')" ] }, - "execution_count": 170, + "execution_count": 164, "metadata": {}, "output_type": "execute_result" } @@ -4832,47 +4721,12 @@ "source": [ "Most operations involving `tuple` objects work in the same way as with `list` objects. The main difference is that `tuple` objects are *immutable*. So, if our program does not depend on mutability, we may and should use `tuple` and not `list` objects to model sequential data. That way, we avoid the pitfalls seen above.\n", "\n", - "`tuple` objects are *sequences* exhibiting the familiar *four* behaviors." + "`tuple` objects are *sequences* exhibiting the familiar *four* behaviors. So, `numbers` holds a *finite* number of elements ..." ] }, { "cell_type": "code", - "execution_count": 171, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 171, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "isinstance(numbers, abc.Sequence)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - " So, `numbers` holds a *finite* number of elements ..." - ] - }, - { - "cell_type": "code", - "execution_count": 172, + "execution_count": 165, "metadata": { "slideshow": { "slide_type": "slide" @@ -4885,7 +4739,7 @@ "12" ] }, - "execution_count": 172, + "execution_count": 165, "metadata": {}, "output_type": "execute_result" } @@ -4907,7 +4761,7 @@ }, { "cell_type": "code", - "execution_count": 173, + "execution_count": 166, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4929,10 +4783,10 @@ }, { "cell_type": "code", - "execution_count": 174, + "execution_count": 167, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -4962,7 +4816,7 @@ }, { "cell_type": "code", - "execution_count": 175, + "execution_count": 168, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4975,7 +4829,7 @@ "False" ] }, - "execution_count": 175, + "execution_count": 168, "metadata": {}, "output_type": "execute_result" } @@ -4986,31 +4840,7 @@ }, { "cell_type": "code", - "execution_count": 176, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 176, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1 in numbers" - ] - }, - { - "cell_type": "code", - "execution_count": 177, + "execution_count": 169, "metadata": { "slideshow": { "slide_type": "skip" @@ -5023,7 +4853,31 @@ "True" ] }, - "execution_count": 177, + "execution_count": 169, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 in numbers" + ] + }, + { + "cell_type": "code", + "execution_count": 170, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 170, "metadata": {}, "output_type": "execute_result" } @@ -5045,7 +4899,7 @@ }, { "cell_type": "code", - "execution_count": 178, + "execution_count": 171, "metadata": { "slideshow": { "slide_type": "slide" @@ -5058,7 +4912,7 @@ "7" ] }, - "execution_count": 178, + "execution_count": 171, "metadata": {}, "output_type": "execute_result" } @@ -5069,10 +4923,10 @@ }, { "cell_type": "code", - "execution_count": 179, + "execution_count": 172, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -5082,7 +4936,7 @@ "4" ] }, - "execution_count": 179, + "execution_count": 172, "metadata": {}, "output_type": "execute_result" } @@ -5093,10 +4947,10 @@ }, { "cell_type": "code", - "execution_count": 180, + "execution_count": 173, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -5106,7 +4960,7 @@ "(2, 6, 9, 10, 1, 4)" ] }, - "execution_count": 180, + "execution_count": 173, "metadata": {}, "output_type": "execute_result" } @@ -5128,10 +4982,10 @@ }, { "cell_type": "code", - "execution_count": 181, + "execution_count": 174, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -5142,7 +4996,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnumbers\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m99\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnumbers\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m99\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" ] } @@ -5159,49 +5013,12 @@ } }, "source": [ - "We can verify the immutability with the `MutableSequence` ABC from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module: [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) returns `False`. So, a data type that is a `Sequence` may be mutable or not. If it is a `MutableSequence`, it is mutable. If it is *not* a `MutableSequence`, it is *immutable*. There is *no* `ImmutableSequence` ABC." + "The `+` and `*` operators work with `tuple` objects as well: They always create *new* `tuple` objects." ] }, { "cell_type": "code", - "execution_count": 182, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 182, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "isinstance(numbers, abc.MutableSequence)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The `+` and `*` operators work with `tuple` objects as well. However, we should *not* do that as the whole point of immutability is to *not* mutate an object.\n", - "\n", - "So, instead of writing something like below, we should use a `list` object and call its `append()` method." - ] - }, - { - "cell_type": "code", - "execution_count": 183, + "execution_count": 175, "metadata": { "slideshow": { "slide_type": "skip" @@ -5214,7 +5031,7 @@ "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4, 99)" ] }, - "execution_count": 183, + "execution_count": 175, "metadata": {}, "output_type": "execute_result" } @@ -5225,7 +5042,7 @@ }, { "cell_type": "code", - "execution_count": 184, + "execution_count": 176, "metadata": { "slideshow": { "slide_type": "skip" @@ -5238,7 +5055,7 @@ "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4, 7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" ] }, - "execution_count": 184, + "execution_count": 176, "metadata": {}, "output_type": "execute_result" } @@ -5260,7 +5077,7 @@ }, { "cell_type": "code", - "execution_count": 185, + "execution_count": 177, "metadata": { "slideshow": { "slide_type": "skip" @@ -5273,7 +5090,7 @@ "0" ] }, - "execution_count": 185, + "execution_count": 177, "metadata": {}, "output_type": "execute_result" } @@ -5284,7 +5101,7 @@ }, { "cell_type": "code", - "execution_count": 186, + "execution_count": 178, "metadata": { "slideshow": { "slide_type": "skip" @@ -5297,7 +5114,7 @@ "10" ] }, - "execution_count": 186, + "execution_count": 178, "metadata": {}, "output_type": "execute_result" } @@ -5319,7 +5136,7 @@ }, { "cell_type": "code", - "execution_count": 187, + "execution_count": 179, "metadata": { "slideshow": { "slide_type": "skip" @@ -5332,7 +5149,7 @@ "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" ] }, - "execution_count": 187, + "execution_count": 179, "metadata": {}, "output_type": "execute_result" } @@ -5343,7 +5160,7 @@ }, { "cell_type": "code", - "execution_count": 188, + "execution_count": 180, "metadata": { "slideshow": { "slide_type": "skip" @@ -5356,7 +5173,7 @@ "True" ] }, - "execution_count": 188, + "execution_count": 180, "metadata": {}, "output_type": "execute_result" } @@ -5367,7 +5184,7 @@ }, { "cell_type": "code", - "execution_count": 189, + "execution_count": 181, "metadata": { "slideshow": { "slide_type": "skip" @@ -5380,7 +5197,7 @@ "True" ] }, - "execution_count": 189, + "execution_count": 181, "metadata": {}, "output_type": "execute_result" } @@ -5391,7 +5208,7 @@ }, { "cell_type": "code", - "execution_count": 190, + "execution_count": 182, "metadata": { "slideshow": { "slide_type": "skip" @@ -5404,7 +5221,7 @@ "True" ] }, - "execution_count": 190, + "execution_count": 182, "metadata": {}, "output_type": "execute_result" } @@ -5413,30 +5230,6 @@ "numbers < (99, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" ] }, - { - "cell_type": "code", - "execution_count": 191, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 191, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "(0, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4) < numbers" - ] - }, { "cell_type": "markdown", "metadata": { @@ -5445,17 +5238,17 @@ } }, "source": [ - "While `tuple` objects are immutable, this only relates to the references they hold. If a `tuple` object contains mutable objects, the entire nested structure is *not* immutable as a whole.\n", + "While `tuple` objects are immutable, this only relates to the references they hold. If a `tuple` object contains references to mutable objects, the entire nested structure is *not* immutable as a whole!\n", "\n", "Consider the following stylized example `not_immutable`: It contains *three* elements, `1`, `[2, ..., 11]`, and `12`, and the elements of the nested `list` object may be changed. While it is not practical to mix data types in a `tuple` object that is used as an \"immutable list,\" we want to make the point that the mere usage of the `tuple` type does *not* guarantee a nested object to be immutable as a whole." ] }, { "cell_type": "code", - "execution_count": 192, + "execution_count": 183, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [], @@ -5465,10 +5258,10 @@ }, { "cell_type": "code", - "execution_count": 193, + "execution_count": 184, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -5478,7 +5271,7 @@ "(1, [2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 12)" ] }, - "execution_count": 193, + "execution_count": 184, "metadata": {}, "output_type": "execute_result" } @@ -5489,10 +5282,10 @@ }, { "cell_type": "code", - "execution_count": 194, + "execution_count": 185, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [], @@ -5502,10 +5295,10 @@ }, { "cell_type": "code", - "execution_count": 195, + "execution_count": 186, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -5515,7 +5308,7 @@ "(1, [99, 99, 99], 12)" ] }, - "execution_count": 195, + "execution_count": 186, "metadata": {}, "output_type": "execute_result" } @@ -5550,7 +5343,7 @@ }, { "cell_type": "code", - "execution_count": 196, + "execution_count": 187, "metadata": { "slideshow": { "slide_type": "slide" @@ -5563,7 +5356,7 @@ }, { "cell_type": "code", - "execution_count": 197, + "execution_count": 188, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5576,7 +5369,7 @@ "7" ] }, - "execution_count": 197, + "execution_count": 188, "metadata": {}, "output_type": "execute_result" } @@ -5587,10 +5380,10 @@ }, { "cell_type": "code", - "execution_count": 198, + "execution_count": 189, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -5600,7 +5393,7 @@ "11" ] }, - "execution_count": 198, + "execution_count": 189, "metadata": {}, "output_type": "execute_result" } @@ -5611,10 +5404,10 @@ }, { "cell_type": "code", - "execution_count": 199, + "execution_count": 190, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -5624,7 +5417,7 @@ "8" ] }, - "execution_count": 199, + "execution_count": 190, "metadata": {}, "output_type": "execute_result" } @@ -5646,7 +5439,7 @@ }, { "cell_type": "code", - "execution_count": 200, + "execution_count": 191, "metadata": { "slideshow": { "slide_type": "skip" @@ -5660,7 +5453,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mn1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn6\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn7\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn8\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn11\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mn1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn6\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn7\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn8\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn11\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: too many values to unpack (expected 11)" ] } @@ -5671,7 +5464,7 @@ }, { "cell_type": "code", - "execution_count": 201, + "execution_count": 192, "metadata": { "slideshow": { "slide_type": "skip" @@ -5685,7 +5478,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mn1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn6\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn7\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn8\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn11\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn12\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn13\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mn1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn6\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn7\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn8\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn11\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn12\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn13\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: not enough values to unpack (expected 13, got 12)" ] } @@ -5709,7 +5502,7 @@ }, { "cell_type": "code", - "execution_count": 202, + "execution_count": 193, "metadata": { "slideshow": { "slide_type": "slide" @@ -5722,10 +5515,10 @@ }, { "cell_type": "code", - "execution_count": 203, + "execution_count": 194, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -5735,7 +5528,7 @@ "7" ] }, - "execution_count": 203, + "execution_count": 194, "metadata": {}, "output_type": "execute_result" } @@ -5746,10 +5539,10 @@ }, { "cell_type": "code", - "execution_count": 204, + "execution_count": 195, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -5759,21 +5552,21 @@ "[11, 8, 5, 3, 12, 2, 6, 9, 10, 1]" ] }, - "execution_count": 204, + "execution_count": 195, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "middle" + "middle # always a list!" ] }, { "cell_type": "code", - "execution_count": 205, + "execution_count": 196, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -5783,79 +5576,7 @@ "4" ] }, - "execution_count": 205, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "last" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "If we do not need the `middle` elements, we go with the underscore `_` convention and \"throw\" them away." - ] - }, - { - "cell_type": "code", - "execution_count": 206, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "first, *_, last = numbers" - ] - }, - { - "cell_type": "code", - "execution_count": 207, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "7" - ] - }, - "execution_count": 207, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "first" - ] - }, - { - "cell_type": "code", - "execution_count": 208, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "4" - ] - }, - "execution_count": 208, + "execution_count": 196, "metadata": {}, "output_type": "execute_result" } @@ -5879,10 +5600,10 @@ }, { "cell_type": "code", - "execution_count": 209, + "execution_count": 197, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [], @@ -5892,10 +5613,10 @@ }, { "cell_type": "code", - "execution_count": 210, + "execution_count": 198, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -5927,10 +5648,10 @@ }, { "cell_type": "code", - "execution_count": 211, + "execution_count": 199, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -5957,12 +5678,12 @@ } }, "source": [ - "Unpacking also works for nested objects. Below, we wrap [zip()](https://docs.python.org/3/library/functions.html#zip) with the [enumerate()](https://docs.python.org/3/library/functions.html#enumerate) built-in to have an index variable `i` inside the `for`-loop. In each iteration, a `tuple` object consisting of `i` and another `tuple` object is created. The inner one then holds the `name` and `position`." + "Unpacking also works for nested objects. Below, we wrap [zip()](https://docs.python.org/3/library/functions.html#zip) with the [enumerate()](https://docs.python.org/3/library/functions.html#enumerate) built-in to have an index variable `number` inside the `for`-loop. In each iteration, a `tuple` object consisting of `number` and another `tuple` object is created. The inner one then holds the `name` and `position`." ] }, { "cell_type": "code", - "execution_count": 212, + "execution_count": 200, "metadata": { "slideshow": { "slide_type": "skip" @@ -5973,15 +5694,15 @@ "name": "stdout", "output_type": "stream", "text": [ - "0 -> Berthold is a goalkeeper\n", - "1 -> Oliver is a defender\n", - "2 -> Carl is a midfielder\n" + "Berthold (jersey #1) is a goalkeeper\n", + "Oliver (jersey #2) is a defender\n", + "Carl (jersey #3) is a midfielder\n" ] } ], "source": [ - "for i, (name, position) in enumerate(zip(names, positions)):\n", - " print(i, \"->\", name, \"is a\", position)" + "for number, (name, position) in enumerate(zip(names, positions), start=1):\n", + " print(f\"{name} (jersey #{number}) is a {position}\")" ] }, { @@ -6010,7 +5731,7 @@ }, { "cell_type": "code", - "execution_count": 213, + "execution_count": 201, "metadata": { "slideshow": { "slide_type": "slide" @@ -6035,7 +5756,7 @@ }, { "cell_type": "code", - "execution_count": 214, + "execution_count": 202, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6045,31 +5766,57 @@ "source": [ "temp = a\n", "a = b\n", - "b = temp" + "b = temp\n", + "\n", + "del temp" ] }, { "cell_type": "code", - "execution_count": 215, + "execution_count": 203, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ - "(1, 0)" + "1" ] }, - "execution_count": 215, + "execution_count": 203, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "a, b" + "a" + ] + }, + { + "cell_type": "code", + "execution_count": 204, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 204, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b" ] }, { @@ -6085,7 +5832,7 @@ }, { "cell_type": "code", - "execution_count": 216, + "execution_count": 205, "metadata": { "slideshow": { "slide_type": "slide" @@ -6093,16 +5840,15 @@ }, "outputs": [], "source": [ - "a = 0\n", - "b = 1" + "a, b = 0, 1" ] }, { "cell_type": "code", - "execution_count": 217, + "execution_count": 206, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -6112,10 +5858,10 @@ }, { "cell_type": "code", - "execution_count": 218, + "execution_count": 207, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -6125,7 +5871,7 @@ "(1, 0)" ] }, - "execution_count": 218, + "execution_count": 207, "metadata": {}, "output_type": "execute_result" } @@ -6138,11 +5884,11 @@ "cell_type": "markdown", "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "slide" } }, "source": [ - "#### Example: [Fibonacci Numbers](https://en.wikipedia.org/wiki/Fibonacci_number) (revisited)" + "##### Example: [Fibonacci Numbers](https://en.wikipedia.org/wiki/Fibonacci_number) (revisited)" ] }, { @@ -6153,28 +5899,15 @@ } }, "source": [ - "Unpacking allows us to rewrite the iterative `fibonacci()` function from [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#\"Hard-at-first-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29) in a concise way, now also supporting *goose typing* with the [numbers](https://docs.python.org/3/library/numbers.html) module from the [standard library](https://docs.python.org/3/library/index.html)." + "Unpacking allows us to rewrite the iterative `fibonacci()` function from [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#\"Hard-at-first-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29) in a concise way." ] }, { "cell_type": "code", - "execution_count": 219, + "execution_count": 208, "metadata": { "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "import numbers" - ] - }, - { - "cell_type": "code", - "execution_count": 220, - "metadata": { - "slideshow": { - "slide_type": "skip" + "slide_type": "slide" } }, "outputs": [], @@ -6187,21 +5920,7 @@ "\n", " Returns:\n", " ith_fibonacci (int)\n", - "\n", - " Raises:\n", - " TypeError: if i is not an integer or not integer-like\n", - " ValueError: if i is not positive\n", " \"\"\"\n", - " if not isinstance(i, numbers.Integral):\n", - " if isinstance(i, numbers.Real):\n", - " if i != int(i):\n", - " raise TypeError(\"i is not an integer-like value; it has decimals\")\n", - " i = int(i)\n", - " else:\n", - " raise TypeError(\"i must be an integer\")\n", - " if i < 0:\n", - " raise ValueError(\"i must be non-negative\")\n", - "\n", " a, b = 0, 1\n", "\n", " for _ in range(i - 1):\n", @@ -6212,10 +5931,10 @@ }, { "cell_type": "code", - "execution_count": 221, + "execution_count": 209, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "fragment" } }, "outputs": [ @@ -6225,7 +5944,7 @@ "144" ] }, - "execution_count": 221, + "execution_count": 209, "metadata": {}, "output_type": "execute_result" } @@ -6234,67 +5953,6 @@ "fibonacci(12)" ] }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Because of the *goose typing*, we may pass `float` objects to `fibonacci()` as long as they contain no decimals." - ] - }, - { - "cell_type": "code", - "execution_count": 222, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "144" - ] - }, - "execution_count": 222, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fibonacci(12.0)" - ] - }, - { - "cell_type": "code", - "execution_count": 223, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "ename": "TypeError", - "evalue": "i is not an integer-like value; it has decimals", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfibonacci\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m12.3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mfibonacci\u001b[0;34m(i)\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mReal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"i is not an integer-like value; it has decimals\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m: i is not an integer-like value; it has decimals" - ] - } - ], - "source": [ - "fibonacci(12.3)" - ] - }, { "cell_type": "markdown", "metadata": { @@ -6323,7 +5981,7 @@ }, { "cell_type": "code", - "execution_count": 224, + "execution_count": 210, "metadata": { "slideshow": { "slide_type": "slide" @@ -6356,10 +6014,10 @@ }, { "cell_type": "code", - "execution_count": 225, + "execution_count": 211, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -6369,7 +6027,7 @@ "42" ] }, - "execution_count": 225, + "execution_count": 211, "metadata": {}, "output_type": "execute_result" } @@ -6391,10 +6049,10 @@ }, { "cell_type": "code", - "execution_count": 226, + "execution_count": 212, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -6404,7 +6062,7 @@ "100" ] }, - "execution_count": 226, + "execution_count": 212, "metadata": {}, "output_type": "execute_result" } @@ -6426,10 +6084,10 @@ }, { "cell_type": "code", - "execution_count": 227, + "execution_count": 213, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -6440,8 +6098,8 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mproduct\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mproduct\u001b[0;34m(*args)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mproduct\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"\"\"Multiply all arguments.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0marg\u001b[0m \u001b[0;32min\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mproduct\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mproduct\u001b[0;34m(*args)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mproduct\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"\"\"Multiply all arguments.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0marg\u001b[0m \u001b[0;32min\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mIndexError\u001b[0m: tuple index out of range" ] } @@ -6463,7 +6121,7 @@ }, { "cell_type": "code", - "execution_count": 228, + "execution_count": 214, "metadata": { "slideshow": { "slide_type": "slide" @@ -6476,10 +6134,10 @@ }, { "cell_type": "code", - "execution_count": 229, + "execution_count": 215, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -6489,13 +6147,13 @@ "[2, 5, 10]" ] }, - "execution_count": 229, + "execution_count": 215, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "product(one_hundred)" + "product(one_hundred) # a semantic error!" ] }, { @@ -6511,7 +6169,7 @@ }, { "cell_type": "code", - "execution_count": 230, + "execution_count": 216, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6524,7 +6182,7 @@ "100" ] }, - "execution_count": 230, + "execution_count": 216, "metadata": {}, "output_type": "execute_result" } @@ -6546,7 +6204,7 @@ }, { "cell_type": "code", - "execution_count": 231, + "execution_count": 217, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6559,7 +6217,7 @@ "100" ] }, - "execution_count": 231, + "execution_count": 217, "metadata": {}, "output_type": "execute_result" } @@ -6578,14 +6236,12 @@ "source": [ "In the \"*Packing & Unpacking with Functions*\" [exercise](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_02_exercises.ipynb#Packing-&-Unpacking-with-Functions) at the end of this chapter, we look at `product()` in more detail.\n", "\n", - "While we needed to unpack `one_hundred` above to avoid the semantic error, unpacking an argument in a function call may also be a convenience in general.\n", - "\n", - "For example, to print the elements of `one_hundred` in one line, we need to use a `for` statement, until now. With unpacking, we get away *without* a loop." + "While we needed to unpack `one_hundred` above to avoid the semantic error, unpacking an argument in a function call may also be a convenience in general. For example, to print the elements of `one_hundred` in one line, we need to use a `for` statement, until now. With unpacking, we get away *without* a loop." ] }, { "cell_type": "code", - "execution_count": 232, + "execution_count": 218, "metadata": { "slideshow": { "slide_type": "skip" @@ -6606,7 +6262,7 @@ }, { "cell_type": "code", - "execution_count": 233, + "execution_count": 219, "metadata": { "slideshow": { "slide_type": "skip" @@ -6628,7 +6284,7 @@ }, { "cell_type": "code", - "execution_count": 234, + "execution_count": 220, "metadata": { "slideshow": { "slide_type": "skip" @@ -6677,7 +6333,7 @@ }, { "cell_type": "code", - "execution_count": 235, + "execution_count": 221, "metadata": { "slideshow": { "slide_type": "slide" @@ -6703,10 +6359,10 @@ }, { "cell_type": "code", - "execution_count": 236, + "execution_count": 222, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" } }, "outputs": [], @@ -6727,10 +6383,10 @@ }, { "cell_type": "code", - "execution_count": 237, + "execution_count": 223, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [], @@ -6746,12 +6402,12 @@ } }, "source": [ - "The `Point` object is a so-called **class**. That is what it means if an object is of type `type`. It can be used as a **factory** to create *new* `tuple`-like objects of type `Point`." + "The `Point` object is a so-called **class**. That is what it means if an object is of type `type`. It can be used as a **factory** to create *new* `tuple`-like objects of type `Point`. In a way, [namedtuple()](https://docs.python.org/3/library/collections.html#collections.namedtuple) gives us a way to create our own custom **constructors**." ] }, { "cell_type": "code", - "execution_count": 238, + "execution_count": 224, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6761,24 +6417,24 @@ { "data": { "text/plain": [ - "140416708056240" + "94715539542800" ] }, - "execution_count": 238, + "execution_count": 224, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "id(Point) # classes are objects as well" + "id(Point)" ] }, { "cell_type": "code", - "execution_count": 239, + "execution_count": 225, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -6788,7 +6444,7 @@ "type" ] }, - "execution_count": 239, + "execution_count": 225, "metadata": {}, "output_type": "execute_result" } @@ -6810,10 +6466,10 @@ }, { "cell_type": "code", - "execution_count": 240, + "execution_count": 226, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -6823,7 +6479,7 @@ "__main__.Point" ] }, - "execution_count": 240, + "execution_count": 226, "metadata": {}, "output_type": "execute_result" } @@ -6845,7 +6501,7 @@ }, { "cell_type": "code", - "execution_count": 241, + "execution_count": 227, "metadata": { "slideshow": { "slide_type": "slide" @@ -6869,10 +6525,10 @@ }, { "cell_type": "code", - "execution_count": 242, + "execution_count": 228, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -6882,7 +6538,7 @@ "Point(x=4, y=2)" ] }, - "execution_count": 242, + "execution_count": 228, "metadata": {}, "output_type": "execute_result" } @@ -6904,7 +6560,7 @@ }, { "cell_type": "code", - "execution_count": 243, + "execution_count": 229, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6914,10 +6570,10 @@ { "data": { "text/plain": [ - "140417315422528" + "139941443365056" ] }, - "execution_count": 243, + "execution_count": 229, "metadata": {}, "output_type": "execute_result" } @@ -6928,10 +6584,10 @@ }, { "cell_type": "code", - "execution_count": 244, + "execution_count": 230, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -6941,7 +6597,7 @@ "__main__.Point" ] }, - "execution_count": 244, + "execution_count": 230, "metadata": {}, "output_type": "execute_result" } @@ -6963,7 +6619,7 @@ }, { "cell_type": "code", - "execution_count": 245, + "execution_count": 231, "metadata": { "slideshow": { "slide_type": "slide" @@ -6976,7 +6632,7 @@ "4" ] }, - "execution_count": 245, + "execution_count": 231, "metadata": {}, "output_type": "execute_result" } @@ -6987,10 +6643,10 @@ }, { "cell_type": "code", - "execution_count": 246, + "execution_count": 232, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "fragment" } }, "outputs": [ @@ -7000,7 +6656,7 @@ "2" ] }, - "execution_count": 246, + "execution_count": 232, "metadata": {}, "output_type": "execute_result" } @@ -7022,7 +6678,7 @@ }, { "cell_type": "code", - "execution_count": 247, + "execution_count": 233, "metadata": { "slideshow": { "slide_type": "skip" @@ -7036,7 +6692,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcurrent_position\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mz\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcurrent_position\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mz\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'Point' object has no attribute 'z'" ] } @@ -7055,41 +6711,17 @@ "source": [ "`current_position` continues to work like a `tuple` object! That is why we can use `namedtuple` as a replacement for `tuple`. The underlying implementations exhibit the *same* computational efficiencies and memory usages.\n", "\n", - "For example, we can index into or loop over `current_position` as it is still a sequence." + "For example, we can index into or loop over `current_position` as it is still a sequence with the familiar four properties." ] }, { "cell_type": "code", - "execution_count": 248, + "execution_count": 234, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 248, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "isinstance(current_position, abc.Sequence)" - ] - }, - { - "cell_type": "code", - "execution_count": 249, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, "outputs": [ { "data": { @@ -7097,7 +6729,7 @@ "4" ] }, - "execution_count": 249, + "execution_count": 234, "metadata": {}, "output_type": "execute_result" } @@ -7108,10 +6740,10 @@ }, { "cell_type": "code", - "execution_count": 250, + "execution_count": 235, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -7121,7 +6753,7 @@ "2" ] }, - "execution_count": 250, + "execution_count": 235, "metadata": {}, "output_type": "execute_result" } @@ -7132,7 +6764,7 @@ }, { "cell_type": "code", - "execution_count": 251, + "execution_count": 236, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7155,10 +6787,10 @@ }, { "cell_type": "code", - "execution_count": 252, + "execution_count": 237, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "fragment" } }, "outputs": [ @@ -7176,17 +6808,6 @@ " print(number)" ] }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "## The Map-Filter-Reduce Paradigm" - ] - }, { "cell_type": "markdown", "metadata": { @@ -7195,216 +6816,12 @@ } }, "source": [ - "Whenever we process sequential data, most tasks can be classified into one of the three categories **map**, **filter**, or **reduce**. This paradigm has caught attention in recent years as it enables **[parallel computing](https://en.wikipedia.org/wiki/Parallel_computing)**, and this gets important when dealing with big amounts of data.\n", - "\n", - "Let's look at a simple example." + "Because of that it has \"length.\"" ] }, { "cell_type": "code", - "execution_count": 253, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Mapping" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "**Mapping** refers to the idea of applying a transformation to every element in a sequence.\n", - "\n", - "For example, let's square each element in `numbers` and add `1` to it. In essence, we apply the transformation $y := x^2 + 1$ expressed as the `transform()` function below." - ] - }, - { - "cell_type": "code", - "execution_count": 254, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "def transform(element):\n", - " \"\"\"Map elements to their squares plus 1.\"\"\"\n", - " return (element ** 2) + 1" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "With the syntax we know so far, we revert to a `for`-loop that iteratively appends the transformed elements to the initially empty `transformed_numbers` list." - ] - }, - { - "cell_type": "code", - "execution_count": 255, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "transformed_numbers = []\n", - "\n", - "for old in numbers:\n", - " new = transform(old)\n", - " transformed_numbers.append(new)" - ] - }, - { - "cell_type": "code", - "execution_count": 256, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[50, 122, 65, 26, 10, 145, 5, 37, 82, 101, 2, 17]" - ] - }, - "execution_count": 256, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "transformed_numbers" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "As this kind of data processing is so common, Python provides the [map()](https://docs.python.org/3/library/functions.html#map) built-in. In its simplest usage form, it takes two arguments: A transformation function that takes one positional argument and an iterable.\n", - "\n", - "We call [map()](https://docs.python.org/3/library/functions.html#map) with the `transform()` function and the `numbers` list as the arguments and store the result in the variable `transformer` to inspect it." - ] - }, - { - "cell_type": "code", - "execution_count": 257, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "transformer = map(transform, numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "We might expect to get back a materialized sequence (i.e., all elements exist in memory), and a `list` object would feel the most natural because of the type of the `numbers` argument. However, `transformer` is an object of type `map`." - ] - }, - { - "cell_type": "code", - "execution_count": 258, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 258, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "transformer" - ] - }, - { - "cell_type": "code", - "execution_count": 259, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "map" - ] - }, - "execution_count": 259, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(transformer)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Like `range` objects, `map` objects generate a series of objects \"on the fly\" (i.e., one by one), and we use the built-in [next()](https://docs.python.org/3/library/functions.html#next) function to obtain the next object in line. So, we should think of a `map` object as a \"rule\" stored in memory that only knows how to calculate the next object of possibly *infinitely* many.\n", - "\n", - "It is essential to understand that by creating a `map` object with the [map()](https://docs.python.org/3/library/functions.html#map) built-in, nothing happens in memory except the creation of the `map` object. In particular, no second `list` object derived from `numbers` is created. Also, we may view `range` objects as a special case of `map` objects: They are constrained to generating `int` objects only, and the *iterable* argument is replaced with *start*, *stop*, and *step* arguments." - ] - }, - { - "cell_type": "code", - "execution_count": 260, + "execution_count": 238, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7414,4746 +6831,16 @@ { "data": { "text/plain": [ - "50" + "2" ] }, - "execution_count": 260, + "execution_count": 238, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "next(transformer)" - ] - }, - { - "cell_type": "code", - "execution_count": 261, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "122" - ] - }, - "execution_count": 261, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(transformer)" - ] - }, - { - "cell_type": "code", - "execution_count": 262, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "65" - ] - }, - "execution_count": 262, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(transformer)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "If we are sure that a `map` object generates a *finite* number of elements, we may materialize them into a `list` object with the [list()](https://docs.python.org/3/library/functions.html#func-list) built-in. In the example, this is the case as `transformer` is derived from a *finite* `list` object.\n", - "\n", - "In summary, instead of creating an empty list first and appending it in a `for`-loop as above, we write the following one-liner and obtain an equal `transformed_numbers` list." - ] - }, - { - "cell_type": "code", - "execution_count": 263, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "transformed_numbers = list(map(transform, numbers))" - ] - }, - { - "cell_type": "code", - "execution_count": 264, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[50, 122, 65, 26, 10, 145, 5, 37, 82, 101, 2, 17]" - ] - }, - "execution_count": 264, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "transformed_numbers" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Filtering" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "**Filtering** refers to the idea of creating a subset of a sequence with a **boolean filter** function that indicates if an element should be kept or not.\n", - "\n", - "In the example, let's only keep the even elements in `numbers`. The `is_even()` function implements that as a filter." - ] - }, - { - "cell_type": "code", - "execution_count": 265, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "def is_even(element):\n", - " \"\"\"Filter out odd numbers.\"\"\"\n", - " if element % 2 == 0:\n", - " return True\n", - " return False" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "As before, we must revert to a `for`-loop that appends the elements to be kept iteratively to an initially empty `even_numbers` list." - ] - }, - { - "cell_type": "code", - "execution_count": 266, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "even_numbers = []\n", - "\n", - "for number in transformed_numbers:\n", - " if is_even(number):\n", - " even_numbers.append(number)" - ] - }, - { - "cell_type": "code", - "execution_count": 267, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[50, 122, 26, 10, 82, 2]" - ] - }, - "execution_count": 267, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "even_numbers" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "As filtering is also a common task, we use the [filter()](https://docs.python.org/3/library/functions.html#filter) built-in that returns an object of type `filter` stored in the `evens` variable." - ] - }, - { - "cell_type": "code", - "execution_count": 268, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "evens = filter(is_even, transformed_numbers)" - ] - }, - { - "cell_type": "code", - "execution_count": 269, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 269, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "evens" - ] - }, - { - "cell_type": "code", - "execution_count": 270, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "filter" - ] - }, - "execution_count": 270, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(evens)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "`evens` works like `transformer` above, and we use the built-in [next()](https://docs.python.org/3/library/functions.html#next) function to obtain the even numbers one by one. So, the \"next\" element in line is simply the next even `int` object the `filter` object encounters." - ] - }, - { - "cell_type": "code", - "execution_count": 271, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[50, 122, 65, 26, 10, 145, 5, 37, 82, 101, 2, 17]" - ] - }, - "execution_count": 271, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "transformed_numbers # for quick reference" - ] - }, - { - "cell_type": "code", - "execution_count": 272, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "50" - ] - }, - "execution_count": 272, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(evens)" - ] - }, - { - "cell_type": "code", - "execution_count": 273, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "122" - ] - }, - "execution_count": 273, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(evens)" - ] - }, - { - "cell_type": "code", - "execution_count": 274, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "26" - ] - }, - "execution_count": 274, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(evens)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "As above, we must explicitly create a materialized `list` object with the [list()](https://docs.python.org/3/library/functions.html#func-list) built-in." - ] - }, - { - "cell_type": "code", - "execution_count": 275, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[50, 122, 26, 10, 82, 2]" - ] - }, - "execution_count": 275, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(filter(is_even, transformed_numbers))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "We may also chain mappings and filters based on the original `numbers` list." - ] - }, - { - "cell_type": "code", - "execution_count": 276, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[50, 122, 26, 10, 82, 2]" - ] - }, - "execution_count": 276, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(filter(is_even, map(transform, numbers)))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Using the [map()](https://docs.python.org/3/library/functions.html#map) and [filter()](https://docs.python.org/3/library/functions.html#filter) built-ins, we can quickly switch the order: Filter first and then transform the remaining elements. This variant equals the \"*A simple Filter*\" example from [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Example:-A-simple-Filter). On the contrary, code with `for`-loops and `if` statements is more tedious to adapt. Additionally, `map` and `filter` objects are optimized at the C level and, therefore, a lot faster as well." - ] - }, - { - "cell_type": "code", - "execution_count": 277, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[65, 145, 5, 37, 101, 17]" - ] - }, - "execution_count": 277, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(map(transform, filter(is_even, numbers)))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Reducing" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Lastly, **reducing** sequential data means to summarize the elements into a single statistic.\n", - "\n", - "A simple example is the built-in [sum()](https://docs.python.org/3/library/functions.html#sum) function." - ] - }, - { - "cell_type": "code", - "execution_count": 278, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "370" - ] - }, - "execution_count": 278, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum(map(transform, filter(is_even, numbers)))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Other straightforward examples are the built-in [min()](https://docs.python.org/3/library/functions.html#min) or [max()](https://docs.python.org/3/library/functions.html#max) functions." - ] - }, - { - "cell_type": "code", - "execution_count": 279, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "5" - ] - }, - "execution_count": 279, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "min(map(transform, filter(is_even, numbers)))" - ] - }, - { - "cell_type": "code", - "execution_count": 280, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "145" - ] - }, - "execution_count": 280, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "max(map(transform, filter(is_even, numbers)))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "[sum()](https://docs.python.org/3/library/functions.html#sum), [min()](https://docs.python.org/3/library/functions.html#min), and [max()](https://docs.python.org/3/library/functions.html#max) can be regarded as special cases.\n", - "\n", - "The generic way of reducing a sequence is to apply a function of *two* arguments on a rolling horizon: Its first argument is the reduction of the elements processed so far, and the second the next element to be reduced.\n", - "\n", - "For illustration, let's replicate [sum()](https://docs.python.org/3/library/functions.html#sum) as such a function, called `add()`. Its implementation only adds two numbers." - ] - }, - { - "cell_type": "code", - "execution_count": 281, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "def add(sum_so_far, next_number):\n", - " \"\"\"Reduce a sequence by addition.\"\"\"\n", - " return sum_so_far + next_number" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Further, we create a *new* `map` object derived from `numbers` ..." - ] - }, - { - "cell_type": "code", - "execution_count": 282, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "evens_transformed = map(transform, filter(is_even, numbers))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "... and loop over all *but* the first element it generates. That we capture separately as the initial `result` with the [next()](https://docs.python.org/3/library/functions.html#next) function. So, `map` objects must be *iterable* as we may loop over them.\n", - "\n", - "We know that `evens_transformed` generates *six* elements. That is why we see *five* growing `result` values resembling a [cumulative sum](http://mathworld.wolfram.com/CumulativeSum.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 283, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "65 210 215 252 353 " - ] - } - ], - "source": [ - "result = next(evens_transformed) # first element is the initial value\n", - "\n", - "for number in evens_transformed: # iterate over the remaining elements\n", - " print(result, end=\" \") # line added for didactical purposes\n", - " result = add(result, number)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The final `result` is the same `370` as above." - ] - }, - { - "cell_type": "code", - "execution_count": 284, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "370" - ] - }, - "execution_count": 284, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "result" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) function in the [functools](https://docs.python.org/3/library/functools.html) module in the [standard library](https://docs.python.org/3/library/index.html) provides more convenience replacing the `for`-loop. It takes two arguments in the same way as the [map()](https://docs.python.org/3/library/functions.html#map) and [filter()](https://docs.python.org/3/library/functions.html#filter) built-ins.\n", - "\n", - "[reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) is **[eager](https://en.wikipedia.org/wiki/Eager_evaluation)** meaning that all computations implied by the contained `map` and `filter` \"rules\" are executed right away, and the code cell returns `370`. On the contrary, [map()](https://docs.python.org/3/library/functions.html#map) and [filter()](https://docs.python.org/3/library/functions.html#filter) create **[lazy](https://en.wikipedia.org/wiki/Lazy_evaluation)** `map` and `filter` objects, and we have to use the [next()](https://docs.python.org/3/library/functions.html#next) function to obtain the elements." - ] - }, - { - "cell_type": "code", - "execution_count": 285, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "from functools import reduce" - ] - }, - { - "cell_type": "code", - "execution_count": 286, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "370" - ] - }, - "execution_count": 286, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "reduce(add, map(transform, filter(is_even, numbers)))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Lambda Expressions" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "[map()](https://docs.python.org/3/library/functions.html#map), [filter()](https://docs.python.org/3/library/functions.html#filter), and [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) take a `function` object as their first argument, and we defined `transform()`, `is_even()`, and `add()` to be used precisely for that.\n", - "\n", - "Often, such functions are used *only once* in a program. However, the primary purpose of functions is to *reuse* them. In such cases, it makes more sense to define them \"anonymously\" right at the position where the first argument goes.\n", - "\n", - "As mentioned in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Anonymous-Functions), Python provides `lambda` expressions to create `function` objects *without* a name referencing them.\n", - "\n", - "So, the above `add()` function could be rewritten as a `lambda` expression like so ..." - ] - }, - { - "cell_type": "code", - "execution_count": 287, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(sum_so_far, next_number)>" - ] - }, - "execution_count": 287, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "lambda sum_so_far, next_number: sum_so_far + next_number" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "... or even shorter." - ] - }, - { - "cell_type": "code", - "execution_count": 288, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(x, y)>" - ] - }, - "execution_count": 288, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "lambda x, y: x + y" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "With the new concepts in this section, we can rewrite the entire example in just a few lines of code *without* any `for`, `if`, and `def` statements. The resulting code is concise, easy to read, quick to modify, and even faster in execution. Most importantly, it is optimized to handle big amounts of data as *no* temporary `list` objects are materialized in memory." - ] - }, - { - "cell_type": "code", - "execution_count": 289, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "370" - ] - }, - "execution_count": 289, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]\n", - "evens = filter(lambda x: x % 2 == 0, numbers)\n", - "transformed = map(lambda x: (x ** 2) + 1, evens)\n", - "sum(transformed)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "If `numbers` comes as a sorted sequence of whole numbers, we may use the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in and get away *without any* `list` object in memory at all!" - ] - }, - { - "cell_type": "code", - "execution_count": 290, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "370" - ] - }, - "execution_count": 290, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numbers = range(1, 13)\n", - "evens = filter(lambda x: x % 2 == 0, numbers)\n", - "transformed = map(lambda x: (x ** 2) + 1, evens)\n", - "sum(transformed)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "To additionally save the temporary variables, `numbers`, `evens`, and `transformed`, we write the entire computation as *one* expression." - ] - }, - { - "cell_type": "code", - "execution_count": 291, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "370" - ] - }, - "execution_count": 291, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum(map(lambda x: (x ** 2) + 1, filter(lambda x: x % 2 == 0, range(1, 13))))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "PythonTutor visualizes the differences in the number of computational steps and memory usage:\n", - "- [Version 1](http://pythontutor.com/visualize.html#code=def%20is_even%28element%29%3A%0A%20%20%20%20if%20element%20%25%202%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20True%0A%20%20%20%20return%20False%0A%0Adef%20transform%28element%29%3A%0A%20%20%20%20return%20%28element%20**%202%29%20%2B%201%0A%0Anumbers%20%3D%20list%28range%281,%2013%29%29%0A%0Aevens%20%3D%20%5B%5D%0Afor%20number%20in%20numbers%3A%0A%20%20%20%20if%20is_even%28number%29%3A%0A%20%20%20%20%20%20%20%20evens.append%28number%29%0A%0Atransformed%20%3D%20%5B%5D%0Afor%20number%20in%20evens%3A%0A%20%20%20%20transformed.append%28transform%28number%29%29%0A%0Aresult%20%3D%20sum%28transformed%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false): With `for`-loops, `if` statements, and named functions -> **116** steps\n", - "- [Version 2](http://pythontutor.com/visualize.html#code=numbers%20%3D%20range%281,%2013%29%0Aevens%20%3D%20filter%28lambda%20x%3A%20x%20%25%202%20%3D%3D%200,%20numbers%29%0Atransformed%20%3D%20map%28lambda%20x%3A%20%28x%20**%202%29%20%2B%201,%20evens%29%0Aresult%20%3D%20sum%28transformed%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false): With named `map` and `filter` objects -> **58** steps\n", - "- [Version 3](http://pythontutor.com/visualize.html#code=result%20%3D%20sum%28map%28lambda%20x%3A%20%28x%20**%202%29%20%2B%201,%20filter%28lambda%20x%3A%20x%20%25%202%20%3D%3D%200,%20range%281,%2013%29%29%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false): Everything in *one* expression -> **55** steps\n", - "\n", - "Versions 2 and 3 are the same, except for the three additional steps required to create the temporary variables. The *major* downside of Version 1 is that, in the worst case, it may need *three times* the memory as compared to the other two versions!\n", - "\n", - "An experienced Pythonista would probably go with Version 2 in a production system to keep the code readable and maintainable." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### List Comprehensions" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "For [map()](https://docs.python.org/3/library/functions.html#map) and [filter()](https://docs.python.org/3/library/functions.html#filter), Python provides a nice syntax appealing to people who like mathematics.\n", - "\n", - "Consider again the \"*A simple Filter*\" example from [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Example:-A-simple-Filter), written with combined `for` and `if` statements. So, the mapping and filtering steps happen simultaneously." - ] - }, - { - "cell_type": "code", - "execution_count": 292, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - { - "cell_type": "code", - "execution_count": 293, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "evens_transformed = []\n", - "\n", - "for number in numbers:\n", - " if number % 2 == 0:\n", - " evens_transformed.append((number ** 2) + 1)" - ] - }, - { - "cell_type": "code", - "execution_count": 294, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[65, 145, 5, 37, 101, 17]" - ] - }, - "execution_count": 294, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "evens_transformed" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "**List comprehensions**, or **listcomps** for short, are *expressions* to derive *new* `list` objects out of *existing* ones (cf., [reference](https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries)). A single *expression* like below can replace the compound `for` *statement* from above." - ] - }, - { - "cell_type": "code", - "execution_count": 295, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[65, 145, 5, 37, 101, 17]" - ] - }, - "execution_count": 295, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[(n ** 2) + 1 for n in numbers if n % 2 == 0]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "A list comprehension may be used in place of any `list` object.\n", - "\n", - "For example, let's add up all the elements with [sum()](https://docs.python.org/3/library/functions.html#sum). The code below *materializes* all elements in memory *before* summing them up. So, this code might cause a `MemoryError` when executed with a bigger `numbers` list. [PythonTutor](http://pythontutor.com/visualize.html#code=numbers%20%3D%20range%281,%2013%29%0Aresult%20%3D%20sum%28%5B%28n%20**%202%29%20%2B%201%20for%20n%20in%20numbers%20if%20n%20%25%202%20%3D%3D%200%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows how a `list` object exists in memory at step 17 and then \"gets lost\" right after. " - ] - }, - { - "cell_type": "code", - "execution_count": 296, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "370" - ] - }, - "execution_count": 296, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum([(n ** 2) + 1 for n in numbers if n % 2 == 0])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "#### Example: Nested Lists" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "List comprehensions may come with several `for`'s and `if`'s.\n", - "\n", - "The cell below creates a `list` object that contains other `list` objects with numbers in them. The starting number in each inner `list` object is offset by `1`." - ] - }, - { - "cell_type": "code", - "execution_count": 297, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "nested_numbers = [list(range(x, y + 1)) for x, y in zip([1, 2, 3], [7, 8, 9])]" - ] - }, - { - "cell_type": "code", - "execution_count": 298, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[[1, 2, 3, 4, 5, 6, 7], [2, 3, 4, 5, 6, 7, 8], [3, 4, 5, 6, 7, 8, 9]]" - ] - }, - "execution_count": 298, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "nested_numbers" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "To do something meaningful with the numbers, we have to get rid of the inner layer of `list` objects and flatten the data.\n", - "\n", - "Without list comprehensions, we would probably write two nested `for`-loops." - ] - }, - { - "cell_type": "code", - "execution_count": 299, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "flat_numbers = []\n", - "\n", - "for inner_numbers in nested_numbers:\n", - " for number in inner_numbers:\n", - " flat_numbers.append(number)" - ] - }, - { - "cell_type": "code", - "execution_count": 300, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 8, 3, 4, 5, 6, 7, 8, 9]" - ] - }, - "execution_count": 300, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "flat_numbers" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "That translates into a list comprehension like below. The order of the `for`'s may be confusing at first but is the *same* as writing out the nested `for`-loops." - ] - }, - { - "cell_type": "code", - "execution_count": 301, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 8, 3, 4, 5, 6, 7, 8, 9]" - ] - }, - "execution_count": 301, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[number for inner_numbers in nested_numbers for number in inner_numbers]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Now, we may use the `list` object resulting from the list comprehension in any context we want.\n", - "\n", - "As an example, we add up the flattened numbers with [sum()](https://docs.python.org/3/library/functions.html#sum). The same caveat holds as before: The `list` object passed into [sum()](https://docs.python.org/3/library/functions.html#sum) is *materialized* before the sum is calculated!" - ] - }, - { - "cell_type": "code", - "execution_count": 302, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "105" - ] - }, - "execution_count": 302, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum([number for inner_numbers in nested_numbers for number in inner_numbers])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "In this particular example, however, we can exploit the fact that any sum of numbers can be expressed as the sum of sums of mutually exclusive and collectively exhaustive subsets of these numbers and get away with just *one* `for` in the list comprehension." - ] - }, - { - "cell_type": "code", - "execution_count": 303, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "105" - ] - }, - "execution_count": 303, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum([sum(inner_numbers) for inner_numbers in nested_numbers])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "#### Example: Cartesian Products" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "A popular use case of nested list comprehensions is applying a transformation to each $2$-tuple of the [Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product) of two iterables.\n", - "\n", - "For example, let's add `1` to each quotient obtained by taking the numerator from `[10, 20, 30]` and the denominator from `[40, 50, 60]`, and then find the product of all quotients. The table below visualizes the calculations: The result is the product of *nine* entries.\n", - "\n", - "||**10**|**20**|**30**|\n", - "|-|-|-|-|\n", - "|**40**|1.25|1.50|1.75|\n", - "|**50**|1.20|1.40|1.60|\n", - "|**60**|1.17|1.33|1.50|\n", - "\n", - "To express that in Python, we start by creating two `list` objects, `first` and `second`." - ] - }, - { - "cell_type": "code", - "execution_count": 304, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "first = [10, 20, 30]\n", - "second = [40, 50, 60]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "For a Cartesian product, we loop over *all* possible $2$-tuples where one element is drawn from `first` and the other from `second`. That is equivalent to two nested `for`-loops." - ] - }, - { - "cell_type": "code", - "execution_count": 305, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[1.25, 1.2, 1.1666666666666667, 1.5, 1.4, 1.3333333333333333, 1.75, 1.6, 1.5]" - ] - }, - "execution_count": 305, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cartesian_product = []\n", - "\n", - "for numerator in first:\n", - " for denominator in second:\n", - " quotient = numerator / denominator\n", - " cartesian_product.append(quotient + 1)\n", - "\n", - "cartesian_product" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "We translate the two `for`-loops into one list comprehensions with two `for`'s in it and use `x` and `y` as shorter variable names." - ] - }, - { - "cell_type": "code", - "execution_count": 306, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[1.25, 1.2, 1.1666666666666667, 1.5, 1.4, 1.3333333333333333, 1.75, 1.6, 1.5]" - ] - }, - "execution_count": 306, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[(x / y) + 1 for x in first for y in second]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The order of the `for`'s is *important*: The list comprehension above divides numbers from `first` by numbers from `second`, whereas the list comprehension below does the opposite." - ] - }, - { - "cell_type": "code", - "execution_count": 307, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[5.0, 3.0, 2.333333333333333, 6.0, 3.5, 2.666666666666667, 7.0, 4.0, 3.0]" - ] - }, - "execution_count": 307, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[(x / y) + 1 for x in second for y in first]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "To find the overall product, we *unpack* the first list comprehension right into the `product()` function from the \"*Packing & Unpacking*\" section above." - ] - }, - { - "cell_type": "code", - "execution_count": 308, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "20.58" - ] - }, - "execution_count": 308, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "product(*[(x / y) + 1 for x in first for y in second])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Alternatively, we use a `lambda` expression with the [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) function from the [functools](https://docs.python.org/3/library/functools.html) module." - ] - }, - { - "cell_type": "code", - "execution_count": 309, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "20.58" - ] - }, - "execution_count": 309, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "reduce(lambda x, y: x * y, [(x / y) + 1 for x in first for y in second])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "While this example is stylized, Cartesian products are hidden in many applications, and it shows how the various language features introduced in this chapter can be seamlessly combined to process sequential data." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Generator Expressions" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Pythonistas would forgo materialized `list` objects, and, thus, also list comprehensions, all together, and use a more memory-efficient approach with **[generator expressions](https://docs.python.org/3/reference/expressions.html#generator-expressions)**, or **genexps** for short. Syntactically, they work like list comprehensions except that parentheses replace the brackets.\n", - "\n", - "Let's go back to the original example in this section and find the transformation $y := x^2 + 1$ of all even elements in `numbers`." - ] - }, - { - "cell_type": "code", - "execution_count": 310, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "To filter and transform `numbers`, we wrote this list comprehension above ..." - ] - }, - { - "cell_type": "code", - "execution_count": 311, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[65, 145, 5, 37, 101, 17]" - ] - }, - "execution_count": 311, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[(n ** 2) + 1 for n in numbers if n % 2 == 0]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "... that now becomes a generator expression." - ] - }, - { - "cell_type": "code", - "execution_count": 312, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - " at 0x7fb57436f3d0>" - ] - }, - "execution_count": 312, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "((n ** 2) + 1 for n in numbers if n % 2 == 0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "We can think of it as yet another \"rule\" in memory that knows how to generate the individual objects in a series one by one. Whereas a list comprehension materializes its elements in memory *when* it is evaluated, the opposite holds for generator expressions, and *no* object is created in memory except the \"rule\" itself. Because of this behavior, we describe generator expressions as *lazy* and list comprehensions as *eager*.\n", - "\n", - "So, to materialize all elements specified by a generator expression, we revert to the [list()](https://docs.python.org/3/library/functions.html#func-list) built-in." - ] - }, - { - "cell_type": "code", - "execution_count": 313, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[65, 145, 5, 37, 101, 17]" - ] - }, - "execution_count": 313, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(((n ** 2) + 1 for n in numbers if n % 2 == 0))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Whenever a generator expression is the only argument to a function, we may leave out the parentheses." - ] - }, - { - "cell_type": "code", - "execution_count": 314, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[65, 145, 5, 37, 101, 17]" - ] - }, - "execution_count": 314, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list((n ** 2) + 1 for n in numbers if n % 2 == 0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "A common use case is to reduce the elements into a single object instead, for example, by adding them up with [sum()](https://docs.python.org/3/library/functions.html#sum). [PythonTutor](http://pythontutor.com/visualize.html#code=numbers%20%3D%20range%281,%2013%29%0Asum_with_list%20%3D%20sum%28%5B%28n%20**%202%29%20%2B%201%20for%20n%20in%20numbers%20if%20n%20%25%202%20%3D%3D%200%5D%29%0Asum_with_gen%20%3D%20sum%28%28n%20**%202%29%20%2B%201%20for%20n%20in%20numbers%20if%20n%20%25%202%20%3D%3D%200%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows how the code cell below does *not* create a temporary `list` object in memory, whereas a list comprehension would (cf., step 17)." - ] - }, - { - "cell_type": "code", - "execution_count": 315, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "370" - ] - }, - "execution_count": 315, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum((n ** 2) + 1 for n in numbers if n % 2 == 0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Let's assign the object returned from a generator expression to a variable and inspect it." - ] - }, - { - "cell_type": "code", - "execution_count": 316, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "gen = ((n ** 2) + 1 for n in numbers if n % 2 == 0)" - ] - }, - { - "cell_type": "code", - "execution_count": 317, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - " at 0x7fb57436f650>" - ] - }, - "execution_count": 317, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gen" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Unsurprisingly, generator expressions create objects of type `generator`." - ] - }, - { - "cell_type": "code", - "execution_count": 318, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "generator" - ] - }, - "execution_count": 318, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(gen)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "With the [next()](https://docs.python.org/3/library/functions.html#next) function, we can retrieve the generated elements one by one." - ] - }, - { - "cell_type": "code", - "execution_count": 319, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "65" - ] - }, - "execution_count": 319, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(gen)" - ] - }, - { - "cell_type": "code", - "execution_count": 320, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "145" - ] - }, - "execution_count": 320, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(gen)" - ] - }, - { - "cell_type": "code", - "execution_count": 321, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "5" - ] - }, - "execution_count": 321, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(gen)" - ] - }, - { - "cell_type": "code", - "execution_count": 322, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "37" - ] - }, - "execution_count": 322, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(gen)" - ] - }, - { - "cell_type": "code", - "execution_count": 323, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "101" - ] - }, - "execution_count": 323, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(gen)" - ] - }, - { - "cell_type": "code", - "execution_count": 324, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "17" - ] - }, - "execution_count": 324, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(gen)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Once a `generator` object runs out of elements, it raises a `StopIteration` exception. We say that the `generator` object is **exhausted**, and to loop over its elements again, we must create a *new* one." - ] - }, - { - "cell_type": "code", - "execution_count": 325, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "ename": "StopIteration", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgen\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mStopIteration\u001b[0m: " - ] - } - ], - "source": [ - "next(gen)" - ] - }, - { - "cell_type": "code", - "execution_count": 326, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "ename": "StopIteration", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgen\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mStopIteration\u001b[0m: " - ] - } - ], - "source": [ - "next(gen)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Calling the [next()](https://docs.python.org/3/library/functions.html#next) function repeatedly with the *same* `generator` object as the argument is essentially what a `for`-loop automates for us. So, `generator` objects are *iterable*." - ] - }, - { - "cell_type": "code", - "execution_count": 327, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "65 145 5 37 101 17 " - ] - } - ], - "source": [ - "for number in ((n ** 2) + 1 for n in numbers if n % 2 == 0):\n", - " print(number, end=\" \")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "#### Example: Nested Lists (revisited)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "If we are only interested in a *reduction* of `nested_numbers` into a single statistic, as the overall sum in the \"*Nested Lists*\" example, we should replace lists or list comprehensions with generator expressions wherever possible.\n", - "\n", - "The result is the *same*, but no intermediate lists are materialized! That makes our code scale to larger amounts of data and uses the available hardware more efficiently.\n", - "\n", - "Let's adapt the example but keep `nested_numbers` unchanged for now." - ] - }, - { - "cell_type": "code", - "execution_count": 328, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "nested_numbers = [list(range(x, y + 1)) for x, y in zip([1, 2, 3], [7, 8, 9])]" - ] - }, - { - "cell_type": "code", - "execution_count": 329, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[[1, 2, 3, 4, 5, 6, 7], [2, 3, 4, 5, 6, 7, 8], [3, 4, 5, 6, 7, 8, 9]]" - ] - }, - "execution_count": 329, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "nested_numbers" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "We leave out the brackets and keep everything else as-is: The argument to [sum()](https://docs.python.org/3/library/functions.html#sum), a list comprehension in the initial implementation above, becomes a generator expression." - ] - }, - { - "cell_type": "code", - "execution_count": 330, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "105" - ] - }, - "execution_count": 330, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum(number for inner_numbers in nested_numbers for number in inner_numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "That also holds for the alternative formulation as a sum of sums." - ] - }, - { - "cell_type": "code", - "execution_count": 331, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "105" - ] - }, - "execution_count": 331, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum(sum(inner_numbers) for inner_numbers in nested_numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Because `nested_numbers` has an internal structure, we can make it **memoryless** by expressing it as a generator expression derived from `range` objects. [PythonTutor](http://pythontutor.com/visualize.html#code=nested_numbers%20%3D%20%28%28range%28x,%20y%20%2B%201%29%29%20for%20x,%20y%20in%20zip%28range%281,%204%29,%20range%287,%2010%29%29%29%0Aresult%20%3D%20sum%28number%20for%20inner_numbers%20in%20nested_numbers%20for%20number%20in%20inner_numbers%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) confirms that no `list` object materializes at any point in time." - ] - }, - { - "cell_type": "code", - "execution_count": 332, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "nested_numbers = ((range(x, y + 1)) for x, y in zip(range(1, 4), range(7, 10)))" - ] - }, - { - "cell_type": "code", - "execution_count": 333, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - " at 0x7fb57436fad0>" - ] - }, - "execution_count": 333, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "nested_numbers" - ] - }, - { - "cell_type": "code", - "execution_count": 334, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "105" - ] - }, - "execution_count": 334, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum(number for inner_numbers in nested_numbers for number in inner_numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "We must be careful when assigning a `generator` object to a variable: If we use `nested_numbers` again, for example, in the alternative formulation below, [sum()](https://docs.python.org/3/library/functions.html#sum) returns `0` because `nested_numbers` is exhausted after executing the previous code cell. [PythonTutor](http://pythontutor.com/visualize.html#code=nested_numbers%20%3D%20%28%28range%28x,%20y%20%2B%201%29%29%20for%20x,%20y%20in%20zip%28range%281,%204%29,%20range%287,%2010%29%29%29%0Aresult%20%3D%20sum%28number%20for%20inner_numbers%20in%20nested_numbers%20for%20number%20in%20inner_numbers%29%0Ano_result%20%3D%20sum%28sum%28inner_numbers%29%20for%20inner_numbers%20in%20nested_numbers%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) also shows that." - ] - }, - { - "cell_type": "code", - "execution_count": 335, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 335, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum(sum(inner_numbers) for inner_numbers in nested_numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "#### Example: Cartesian Products (revisited)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Let's also rewrite the \"*Cartesian Products*\" example from above with generator expressions.\n", - "\n", - "As a first optimization, we replace the materialized `list` objects, `first` and `second`, with memoryless `range` objects." - ] - }, - { - "cell_type": "code", - "execution_count": 336, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "first = range(10, 31, 10) # = [10, 20, 30]\n", - "second = range(40, 61, 10) # = [40, 50, 60]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Now, the first of the two alternatives may be more appealing to many readers. In general, many practitioners seem to dislike `lambda` expressions.\n", - "\n", - "The code cell below *unpacks* the elements produced by `((x / y) + 1 for x in first for y in second)` into the `product()` function from the \"*Packing & Unpacking*\" section above. However, inside `product()`, the elements are *packed* into `args`, a materialized `tuple` object. So, all the memory efficiency gained with the generator expression is voided! [PythonTutor](http://pythontutor.com/visualize.html#code=def%20product%28*args%29%3A%0A%20%20%20%20result%20%3D%20args%5B0%5D%0A%20%20%20%20for%20arg%20in%20args%5B1%3A%5D%3A%0A%20%20%20%20%20%20%20%20result%20*%3D%20arg%0A%20%20%20%20return%20result%0A%0Afirst%20%3D%20range%2810,%2031,%2010%29%0Asecond%20%3D%20range%2840,%2061,%2010%29%0A%0Aresult%20%3D%20product%28*%28%28x%20/%20y%29%20%2B%201%20for%20x%20in%20first%20for%20y%20in%20second%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows how a `tuple` object exists in steps 38-58." - ] - }, - { - "cell_type": "code", - "execution_count": 337, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "20.58" - ] - }, - "execution_count": 337, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "product(*((x / y) + 1 for x in first for y in second))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "On the contrary, the solution with the [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) function from the [functools](https://docs.python.org/3/library/functools.html) module and the `lambda` expression works *without* all elements materialized at the same time, and [PythonTutor](http://pythontutor.com/visualize.html#code=from%20functools%20import%20reduce%0A%0Afirst%20%3D%20range%2810,%2031,%2010%29%0Asecond%20%3D%20range%2840,%2061,%2010%29%0A%0Aresult%20%3D%20reduce%28%0A%20%20%20%20lambda%20x,%20y%3A%20x%20*%20y,%0A%20%20%20%20%28%28x%20/%20y%29%20%2B%201%20for%20x%20in%20first%20for%20y%20in%20second%29%0A%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) confirms that. So, only the second alternative is truly memory-efficient." - ] - }, - { - "cell_type": "code", - "execution_count": 338, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "20.58" - ] - }, - "execution_count": 338, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "reduce(lambda x, y: x * y, ((x / y) + 1 for x in first for y in second))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "In summary, we learn from this example that unpacking generator expressions *may* be a *bad* idea." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "### Tuple Comprehensions" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "There is no syntax to derive *new* `tuple` objects out of existing ones. However, we can mimic such a construct by combining the [tuple()](https://docs.python.org/3/library/functions.html#func-tuple) built-in with a generator expression.\n", - "\n", - "So, to convert the list comprehension `[(n ** 2) + 1 for n in numbers if n % 2 == 0]` from above into a \"tuple comprehension,\" we write the following." - ] - }, - { - "cell_type": "code", - "execution_count": 339, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(65, 145, 5, 37, 101, 17)" - ] - }, - "execution_count": 339, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tuple((n ** 2) + 1 for n in numbers if n % 2 == 0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### Boolean Reducers" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Besides [min()](https://docs.python.org/3/library/functions.html#min), [max()](https://docs.python.org/3/library/functions.html#max), and [sum()](https://docs.python.org/3/library/functions.html#sum), Python provides two boolean reduce functions: [all()](https://docs.python.org/3/library/functions.html#all) and [any()](https://docs.python.org/3/library/functions.html#any).\n", - "\n", - "Let's look at straightforward examples involving `numbers` again." - ] - }, - { - "cell_type": "code", - "execution_count": 340, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "[all()](https://docs.python.org/3/library/functions.html#all) takes an *iterable* argument and returns `True` if *all* elements are *truthy*.\n", - "\n", - "For example, let's check if the square of each element in `numbers` is below `100` or `150`, respectively. We express the computation with a generator expression passed as the only argument to [all()](https://docs.python.org/3/library/functions.html#all)." - ] - }, - { - "cell_type": "code", - "execution_count": 341, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 341, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "all(x ** 2 < 100 for x in numbers)" - ] - }, - { - "cell_type": "code", - "execution_count": 342, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 342, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "all(x ** 2 < 150 for x in numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "[all()](https://docs.python.org/3/library/functions.html#all) can be viewed as syntactic sugar replacing a `for`-loop: Internally, [all()](https://docs.python.org/3/library/functions.html#all) implements the *short-circuiting* strategy from [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb#Short-Circuiting), and we mimic that by testing for the *opposite* condition in the `if` statement and leaving the `for`-loop early with the `break` statement. In the worst case, if `threshold` were, for example, `150`, we would loop over *all* elements in the *iterable*, which must be *finite* for the code to work. So, [all()](https://docs.python.org/3/library/functions.html#all) is a *linear search* in disguise." - ] - }, - { - "cell_type": "code", - "execution_count": 343, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 343, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "threshold = 100\n", - "\n", - "for number in numbers:\n", - " if number ** 2 >= threshold: # = the opposite of what we are checking for\n", - " all_below_threshold = False\n", - " break\n", - "else:\n", - " all_below_threshold = True\n", - "\n", - "all_below_threshold" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The documentation of [all()](https://docs.python.org/3/library/functions.html#all) shows in another way what it does with code: By placing a `return` statement inside the `for`-loop of a function's body, iteration is stopped prematurely once an element does *not* meet the condition. That is the familiar *early exit* pattern at work." - ] - }, - { - "cell_type": "code", - "execution_count": 344, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "def all_alt(iterable):\n", - " \"\"\"Alternative implementation of the built-in all() function.\"\"\"\n", - " for element in iterable:\n", - " if not element: # = the opposite of what we are checking for\n", - " return False\n", - " return True" - ] - }, - { - "cell_type": "code", - "execution_count": 345, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 345, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "all_alt(x ** 2 < 100 for x in numbers)" - ] - }, - { - "cell_type": "code", - "execution_count": 346, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 346, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "all_alt(x ** 2 < 150 for x in numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Similarly, [any()](https://docs.python.org/3/library/functions.html#any) checks if *at least* one element in the *iterable* argument is *truthy*.\n", - "\n", - "To continue the example, let's check if the square of *any* element in `numbers` is above `100` or `150`, respectively." - ] - }, - { - "cell_type": "code", - "execution_count": 347, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 347, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "any(x ** 2 > 100 for x in numbers)" - ] - }, - { - "cell_type": "code", - "execution_count": 348, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 348, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "any(x ** 2 > 150 for x in numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Expressed with a `for`-loop, the implementation below reveals that [any()](https://docs.python.org/3/library/functions.html#any) follows the *short-circuiting* strategy as well. Here, we do *not* need to check for the opposite condition." - ] - }, - { - "cell_type": "code", - "execution_count": 349, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 349, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "threshold = 100\n", - "\n", - "for number in numbers:\n", - " if number ** 2 > threshold:\n", - " any_above_threshold = True\n", - " break\n", - "else:\n", - " any_above_threshold = False\n", - "\n", - "any_above_threshold" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The alternative formulation in the documentation of [any()](https://docs.python.org/3/library/functions.html#any) is straightforward." - ] - }, - { - "cell_type": "code", - "execution_count": 350, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "def any_alt(iterable):\n", - " \"\"\"Alternative implementation of the built-in any() function.\"\"\"\n", - " for element in iterable:\n", - " if element:\n", - " return True\n", - " return False" - ] - }, - { - "cell_type": "code", - "execution_count": 351, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 351, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "any_alt(x ** 2 > 100 for x in numbers)" - ] - }, - { - "cell_type": "code", - "execution_count": 352, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 352, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "any_alt(x ** 2 > 150 for x in numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "### Example: Averaging Even Numbers (revisited)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "With the new concepts in this chapter, let's rewrite the book's introductory \"*Averaging Even Numbers*\" example in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Example:-Averaging-Even-Numbers) such that it efficiently handles a large sequence of numbers.\n", - "\n", - "We assume the `average_evens()` function below is called with a *finite* and *iterable* object, which generates a \"stream\" of numeric objects that can be cast as `int` objects because the idea of even and odd numbers only makes sense in the context of whole numbers.\n", - "\n", - "The generator expression `(int(n) for n in numbers)` implements the type casting, and when it is evaluated, *nothing* happens except that a `generator` object is stored in `integers`. Then, with the [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) function from the [functools](https://docs.python.org/3/library/functools.html) module, we *simultaneously* add up *and* count the even numbers produced by the inner generator expression `((n, 1) for n in integers if n % 2 == 0)`. That results in a `generator` object producing `tuple` objects consisting of the next *even* number in line and `1`. Two such `tuple` objects are then iteratively passed to the `lambda` expression as the `x` and `y` arguments. `x` represents the total and the count of the even numbers processed so far, while `y`'s first element, `y[0]`, is the next even number to be added to the running total. The result of the [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) function is again a `tuple` object, namely the final `total` and `count`. Lastly, we calculate the simple average.\n", - "\n", - "In summary, the implementation of `average_evens()` does *not* keep materialized `list` objects internally like its predecessors from [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb), but processes the elements of the `numbers` argument on a one-by-one basis." - ] - }, - { - "cell_type": "code", - "execution_count": 353, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "def average_evens(numbers):\n", - " \"\"\"Calculate the average of all even integers.\n", - "\n", - " Args:\n", - " numbers (iterable): a finite stream of numbers;\n", - " may be integers or floats; floats are truncated\n", - "\n", - " Returns:\n", - " float: average\n", - " \"\"\"\n", - " integers = (int(n) for n in numbers)\n", - " total, count = reduce(\n", - " lambda x, y: (x[0] + y[0], x[1] + y[1]),\n", - " ((n, 1) for n in integers if n % 2 == 0)\n", - " )\n", - " return total / count" - ] - }, - { - "cell_type": "code", - "execution_count": 354, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "7.0" - ] - }, - "execution_count": 354, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "average_evens([7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "An argument generating `float` objects works as well." - ] - }, - { - "cell_type": "code", - "execution_count": 355, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "7.0" - ] - }, - "execution_count": 355, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "average_evens([7., 11., 8., 5., 3., 12., 2., 6., 9., 10., 1., 4.])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "To show that `average_evens()` can process a **stream** of data, we simulate `10_000_000` randomly drawn integers between `0` and `100` with the [randint()](https://docs.python.org/3/library/random.html#random.randint) function from the [random](https://docs.python.org/3/library/random.html) module. We use a generator expression derived from a `range` object as the `numbers` argument. So, at *no* point in time is there a materialized `list` or `tuple` object in memory. The result approaching `50` tells us that [randint()](https://docs.python.org/3/library/random.html#random.randint) must be based on a uniform distribution." - ] - }, - { - "cell_type": "code", - "execution_count": 356, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "import random" - ] - }, - { - "cell_type": "code", - "execution_count": 357, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "random.seed(42)" - ] - }, - { - "cell_type": "code", - "execution_count": 358, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "49.994081434519636" - ] - }, - "execution_count": 358, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "average_evens(random.randint(0, 100) for _ in range(10_000_000))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "To show that `average_evens()` filters out odd numbers, we simulate another stream of `10_000_000` randomly drawn odd integers between `1` and `99`. As no function in the [random](https://docs.python.org/3/library/random.html) module does that \"out of the box,\" we must be creative: Doubling a number drawn from `random.randint(0, 49)` results in an even number between `0` and `98`, and adding `1` makes it odd. Then, `average_evens()` raises a `TypeError`, essentially because `(int(n) for n in numbers)` does not generate any element." - ] - }, - { - "cell_type": "code", - "execution_count": 359, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "ename": "TypeError", - "evalue": "reduce() of empty sequence with no initial value", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0maverage_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m49\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0m_\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10_000_000\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36maverage_evens\u001b[0;34m(numbers)\u001b[0m\n\u001b[1;32m 12\u001b[0m total, count = reduce(\n\u001b[1;32m 13\u001b[0m \u001b[0;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 14\u001b[0;31m \u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mintegers\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;36m2\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 15\u001b[0m )\n\u001b[1;32m 16\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mtotal\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mcount\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m: reduce() of empty sequence with no initial value" - ] - } - ], - "source": [ - "average_evens(2 * random.randint(0, 49) + 1 for _ in range(10_000_000))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "## Iterators vs. Iterables" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "In the \"*Collections vs. Sequences*\" section above, we studied the three and four *behaviors* of collections and sequences. The latter two are *abstract* ideas, and we mainly use them to classify *concrete* data types.\n", - "\n", - "Similarly, we have introduced data types in this chapter that all share the \"behavior\" of modeling some \"rule\" in memory to generate objects \"on the fly:\" They are the `map`, `filter`, and `generator` types. Their main commonality is supporting the built-in [next()](https://docs.python.org/3/library/functions.html#next) function. In computer science terminology, such data types are called **[iterators](https://en.wikipedia.org/wiki/Iterator)**, and the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module formalizes them with the `Iterator` ABC.\n", - "\n", - "So, an example of an iterator is `evens_transformed` below, an object of type `generator`." - ] - }, - { - "cell_type": "code", - "execution_count": 360, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - { - "cell_type": "code", - "execution_count": 361, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "evens_transformed = ((x ** 2) + 1 for x in numbers if x % 2 == 0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Let's first confirm that `evens_transformed` is indeed an `Iterator`, \"abstractly speaking.\"" - ] - }, - { - "cell_type": "code", - "execution_count": 362, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 362, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "isinstance(evens_transformed, abc.Iterator)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "In Python, iterators are *always* also iterables. The reverse does *not* hold! To be precise, iterators are *specializations* of iterables. That is what the \"Inherits from\" columns means in the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module's documentation." - ] - }, - { - "cell_type": "code", - "execution_count": 363, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 363, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "isinstance(evens_transformed, abc.Iterable)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Furthermore, we revise our definition of *iterables* from above: Just as we defined an *iterator* to be an object that supports the [next()](https://docs.python.org/3/library/functions.html#next) function, we define an *iterable* to be an object that supports the built-in [iter()](https://docs.python.org/3/library/functions.html#iter) function.\n", - "\n", - "The confused reader may now be wondering how the two concepts relate to each other.\n", - "\n", - "In short, the [iter()](https://docs.python.org/3/library/functions.html#iter) function is the general way to create an *iterator* object out of a given *iterable* object. In real-world code, we hardly ever see [iter()](https://docs.python.org/3/library/functions.html#iter) as Python calls it for us in the background. Then, the *iterator* object manages the iteration over the *iterable* object.\n", - "\n", - "For illustration, let's do that ourselves and create *two* iterators out of the iterable `numbers` and see what we can do with them." - ] - }, - { - "cell_type": "code", - "execution_count": 364, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "iterator1 = iter(numbers)" - ] - }, - { - "cell_type": "code", - "execution_count": 365, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "iterator2 = iter(numbers)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "`iterator1` and `iterator2` are of type `list_iterator`." - ] - }, - { - "cell_type": "code", - "execution_count": 366, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "list_iterator" - ] - }, - "execution_count": 366, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(iterator1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "*Iterators* are useful for only *one* operation: Get the next object from the associated *iterable*.\n", - "\n", - "By calling [next()](https://docs.python.org/3/library/functions.html#next) three times with `iterator1` as the argument, we obtain the first three elements of `numbers`." - ] - }, - { - "cell_type": "code", - "execution_count": 367, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(7, 11, 8)" - ] - }, - "execution_count": 367, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(iterator1), next(iterator1), next(iterator1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "`iterator1` and `iterator2` keep their *states* separate. So, we could \"manually\" loop over an *iterable* in parallel." - ] - }, - { - "cell_type": "code", - "execution_count": 368, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(5, 7)" - ] - }, - "execution_count": 368, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(iterator1), next(iterator2)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "We can also play a \"trick\" and exchange some elements in `numbers`. `iterator1` and `iterator2` do *not* see these changes and present us with the new elements. So, *iterators* not only have state on their own but also keep this separate from the underlying *iterable*." - ] - }, - { - "cell_type": "code", - "execution_count": 369, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "numbers[1], numbers[4] = 99, 99" - ] - }, - { - "cell_type": "code", - "execution_count": 370, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(99, 99)" - ] - }, - "execution_count": 370, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(iterator1), next(iterator2)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Let's re-assign the elements in `numbers` so that they are in order. Now, the numbers returned from [next()](https://docs.python.org/3/library/functions.html#next) also tell us how often [next()](https://docs.python.org/3/library/functions.html#next) was called with `iterator1` or `iterator2`. We conclude that `list_iterator` objects must be keeping track of the *last* index obtained from the underlying *iterable*." - ] - }, - { - "cell_type": "code", - "execution_count": 371, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "numbers[:] = list(range(1, 13))" - ] - }, - { - "cell_type": "code", - "execution_count": 372, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]" - ] - }, - "execution_count": 372, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numbers" - ] - }, - { - "cell_type": "code", - "execution_count": 373, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(6, 3)" - ] - }, - "execution_count": 373, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(iterator1), next(iterator2)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "With the concepts introduced in this section, we can now understand the first sentence in the documentation on the [zip()](https://docs.python.org/3/library/functions.html#zip) built-in better: \"Make an *iterator* that aggregates elements from each of the *iterables*.\"\n", - "\n", - "Because *iterators* are always also *iterables*, we pass `iterator1` and `iterator2` as arguments to [zip()](https://docs.python.org/3/library/functions.html#zip).\n", - "\n", - "The returned `zipper` object is of type `zip` and, \"abstractly speaking,\" an `Iterator` as well." - ] - }, - { - "cell_type": "code", - "execution_count": 374, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "zipper = zip(iterator1, iterator2)" - ] - }, - { - "cell_type": "code", - "execution_count": 375, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 375, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "zipper" - ] - }, - { - "cell_type": "code", - "execution_count": 376, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "zip" - ] - }, - "execution_count": 376, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(zipper)" - ] - }, - { - "cell_type": "code", - "execution_count": 377, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 377, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "isinstance(zipper, abc.Iterator)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "So far, we have always used [zip()](https://docs.python.org/3/library/functions.html#zip) with a `for` statement and looped over it. That was our earlier definition of an *iterable*. Our revised definition in this section states that an *iterable* is an object that supports the [iter()](https://docs.python.org/3/library/functions.html#iter) function. So, let's see what happens if we pass `zipper` to [iter()](https://docs.python.org/3/library/functions.html#iter)." - ] - }, - { - "cell_type": "code", - "execution_count": 378, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "zipper_iterator = iter(zipper)" - ] - }, - { - "cell_type": "code", - "execution_count": 379, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 379, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "zipper_iterator" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "`zipper_iterator` references the *same* object as `zipper`! That holds for *iterators* in general: Any *iterator* created from an existing *iterator* with [iter()](https://docs.python.org/3/library/functions.html#iter) is the *iterator* itself." - ] - }, - { - "cell_type": "code", - "execution_count": 380, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 380, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "zipper is zipper_iterator" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The Python core developers made that design decision so that *iterators* may also be looped over.\n", - "\n", - "The `for`-loop below prints out *six* more `tuple` objects derived from the now ordered `numbers` because the `iterator1` object hidden inside `zipper` already returned the first *six* elements. So, the respective first elements of the `tuple` objects printed range from `7` to `12`. Similarly, as `iterator2` already provided *three* elements from `numbers`, we see the respective second elements in the range from `4` to `9`." - ] - }, - { - "cell_type": "code", - "execution_count": 381, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "7 > 4 8 > 5 9 > 6 10 > 7 11 > 8 12 > 9 " - ] - } - ], - "source": [ - "for x, y in zipper:\n", - " print(x, \">\", y, end=\" \")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "`zipper` is now *exhausted*. So, the `for`-loop below does *not* make any iteration at all." - ] - }, - { - "cell_type": "code", - "execution_count": 382, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "for x, y in zipper:\n", - " print(x, \">\", y, end=\" \")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "We verify that `iterator1` is exhausted by passing it to [next()](https://docs.python.org/3/library/functions.html#next) again, which raises a `StopIteration` exception." - ] - }, - { - "cell_type": "code", - "execution_count": 383, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "ename": "StopIteration", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0miterator1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mStopIteration\u001b[0m: " - ] - } - ], - "source": [ - "next(iterator1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "On the contrary, `iterator2` is *not* yet exhausted." - ] - }, - { - "cell_type": "code", - "execution_count": 384, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "10" - ] - }, - "execution_count": 384, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "next(iterator2)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Understanding *iterators* and *iterables* is helpful for any data science practitioner that deals with large amounts of data. Even without that, these two terms occur everywhere in Python-related texts and documentation." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### The `for` Statement (revisited)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "In [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#The-for-Statement), we argue that the `for` statement is syntactic sugar, replacing the `while` statement in many scenarios. In particular, a `for`-loop saves us two tasks: Managing an index variable *and* obtaining the individual elements by indexing. In this sub-section, we look at a more realistic picture, using the new terminology as well.\n", - "\n", - "Let's print out the elements of a `list` object as the *iterable* to be looped over." - ] - }, - { - "cell_type": "code", - "execution_count": 385, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "iterable = [0, 1, 2, 3, 4]" - ] - }, - { - "cell_type": "code", - "execution_count": 386, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 1 2 3 4 " - ] - } - ], - "source": [ - "for element in iterable:\n", - " print(element, end=\" \")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Our previous and equivalent formulation with a `while` statement is like so." - ] - }, - { - "cell_type": "code", - "execution_count": 387, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 1 2 3 4 " - ] - } - ], - "source": [ - "index = 0\n", - "while index < len(iterable):\n", - " element = iterable[index]\n", - " print(element, end=\" \")\n", - " index += 1\n", - "del index" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "What happens behind the scenes in the Python interpreter is shown below.\n", - "\n", - "First, Python calls [iter()](https://docs.python.org/3/library/functions.html#iter) with the `iterable` to be looped over, and obtains an `iterator`. That contains the entire logic of how the `iterable` is looped over. In particular, the `iterator` may or may not pick the `iterable`'s elements in a predictable order. That is up to the \"rule\" it models.\n", - "\n", - "Second, Python enters an *indefinite* `while`-loop. It tries to obtain the next element with [next()](https://docs.python.org/3/library/functions.html#next). If that succeeds, the `for`-loop's code block is executed. Below, that code is placed within the `else`-clause that runs only if *no* exception is raised in the `try`-clause. Then, Python jumps into the next iteration and tries to obtain the next element from the `iterator`, and so on. Once the `iterator` is exhausted, it raises a `StopIteration` exception, and Python leaves the `while`-loop with the `break` statement." - ] - }, - { - "cell_type": "code", - "execution_count": 388, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 1 2 3 4 " - ] - } - ], - "source": [ - "iterator = iter(iterable)\n", - "\n", - "while True:\n", - " try:\n", - " element = next(iterator)\n", - " except StopIteration:\n", - " break\n", - " else:\n", - " print(element, end=\" \")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### sorted() vs. reversed()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Now that we know the concept of an *iterator*, let's compare some of the built-ins introduced in this chapter in detail and make sure we understand what is going on in memory. This sub-section is thus a great summary of this chapter as well.\n", - "\n", - "We use two simple examples, `numbers` and `memoryless`, to guide us through the discussion. `numbers` creates *thirteen* objects in memory and `memoryless` only *one* (cf., [PythonTutor](http://www.pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0Amemoryless%20%3D%20range%281,%2013%29&cumulative=false&curInstr=2&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false))." - ] - }, - { - "cell_type": "code", - "execution_count": 389, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - { - "cell_type": "code", - "execution_count": 390, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "memoryless = range(1, 13)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The [sorted()](https://docs.python.org/3/library/functions.html#sorted) function takes a *finite* and *iterable* object as its argument and *materializes* its elements into a *new* `list` object that is returned.\n", - "\n", - "The argument may already be materialized, as is the case with `numbers`, but may also be an *iterable* without any objects in it, such as `memoryless`. In both cases, we end up with materialized `list` objects with the elements sorted in *forward* order (cf., [PythonTutor](http://www.pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0Amemoryless%20%3D%20range%281,%2013%29%0Aresult1%20%3D%20sorted%28numbers%29%0Aresult2%20%3D%20sorted%28memoryless%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false))." - ] - }, - { - "cell_type": "code", - "execution_count": 391, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]" - ] - }, - "execution_count": 391, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sorted(numbers)" - ] - }, - { - "cell_type": "code", - "execution_count": 392, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]" - ] - }, - "execution_count": 392, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sorted(memoryless)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "By adding a keyword-only argument `reverse=True`, the materialized `list` objects are sorted in *reverse* order (cf., [PythonTutor](http://www.pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0Amemoryless%20%3D%20range%281,%2013%29%0Aresult1%20%3D%20sorted%28numbers,%20reverse%3DTrue%29%0Aresult2%20%3D%20sorted%28memoryless,%20reverse%3DTrue%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false))." - ] - }, - { - "cell_type": "code", - "execution_count": 393, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]" - ] - }, - "execution_count": 393, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sorted(numbers, reverse=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 394, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]" - ] - }, - "execution_count": 394, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sorted(memoryless, reverse=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The order in `numbers` remains *unchanged*, and `memoryless` is still *not* materialized." - ] - }, - { - "cell_type": "code", - "execution_count": 395, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - "execution_count": 395, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numbers" - ] - }, - { - "cell_type": "code", - "execution_count": 396, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "range(1, 13)" - ] - }, - "execution_count": 396, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "memoryless" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in takes a *sequence* object as its argument and returns an *iterator*. The argument must be *finite* and *reversible* (i.e., *iterable* in *reverse* order) as otherwise [reversed()](https://docs.python.org/3/library/functions.html#reversed) could neither determine the last element that becomes the first nor loop in a *predictable* backward fashion. [PythonTutor](http://www.pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0Amemoryless%20%3D%20range%281,%2013%29%0Aiterator1%20%3D%20reversed%28numbers%29%0Aiterator2%20%3D%20reversed%28memoryless%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) confirms that [reversed()](https://docs.python.org/3/library/functions.html#reversed) does *not* materialize any elements but only returns an *iterator*.\n", - "\n", - "**Side Note**: Even though `range` objects, like `memoryless` here, do *not* \"contain\" references to other objects, they count as *sequence* types, and as such, they are also *container* types. The `in` operator works with `range` objects because we can always cast the object to be checked as an `int` and check if that lies within the `range` object's *start* and *stop* values, taking a potential *step* value into account (cf., this [blog post](https://treyhunner.com/2018/02/python-range-is-not-an-iterator/) for more details on the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in)." - ] - }, - { - "cell_type": "code", - "execution_count": 397, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 397, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "reversed(numbers)" - ] - }, - { - "cell_type": "code", - "execution_count": 398, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 398, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "reversed(memoryless)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "To materialize the elements, we can pass the returned *iterators* to, for example, the [list()](https://docs.python.org/3/library/functions.html#func-list) or [tuple()](https://docs.python.org/3/library/functions.html#func-tuple) built-ins. That creates *new* `list` and `tuple` objects (cf., [PythonTutor](http://www.pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0Amemoryless%20%3D%20range%281,%2013%29%0Aresult1%20%3D%20list%28reversed%28numbers%29%29%0Aresult2%20%3D%20tuple%28reversed%28memoryless%29%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)).\n", - "\n", - "To reiterate some more new terminology from this chapter, we describe [reversed()](https://docs.python.org/3/library/functions.html#reversed) as *lazy*, whereas [list()](https://docs.python.org/3/library/functions.html#func-list) and [tuple()](https://docs.python.org/3/library/functions.html#func-tuple) are *eager*. The former has no significant side effect in memory, while the latter may require a lot of memory." - ] - }, - { - "cell_type": "code", - "execution_count": 399, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[4, 1, 10, 9, 6, 2, 12, 3, 5, 8, 11, 7]" - ] - }, - "execution_count": 399, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(reversed(numbers))" - ] - }, - { - "cell_type": "code", - "execution_count": 400, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)" - ] - }, - "execution_count": 400, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tuple(reversed(memoryless))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Of course, we can also loop over the returned *iterators* instead.\n", - "\n", - "That works because *iterators* are always *iterables*; in particular, as the previous \"*The for Statement (revisited)*\" sub-section explains, the `for`-loops below call `iter(reversed(numbers))` and `iter(reversed(memoryless))` behind the scenes. However, the *iterators* returned by [iter()](https://docs.python.org/3/library/functions.html#iter) are the *same* as the `reversed(numbers)` and `reversed(memoryless)` iterators passed in! In summary, the `for`-loops below involve many subtleties that together make Python the expressive language it is." - ] - }, - { - "cell_type": "code", - "execution_count": 401, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4 1 10 9 6 2 12 3 5 8 11 7 " - ] - } - ], - "source": [ - "for number in reversed(numbers):\n", - " print(number, end=\" \")" - ] - }, - { - "cell_type": "code", - "execution_count": 402, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12 11 10 9 8 7 6 5 4 3 2 1 " - ] - } - ], - "source": [ - "for element in reversed(memoryless):\n", - " print(element, end=\" \")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "As with [sorted()](https://docs.python.org/3/library/functions.html#sorted), the [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in does *not* mutate its argument." - ] - }, - { - "cell_type": "code", - "execution_count": 403, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - "execution_count": 403, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numbers" - ] - }, - { - "cell_type": "code", - "execution_count": 404, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "range(1, 13)" - ] - }, - "execution_count": 404, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "memoryless" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "To point out the potentially obvious, we compare the results of *sorting* `numbers` in *reverse* order with *reversing* it: These are *different* concepts!" - ] - }, - { - "cell_type": "code", - "execution_count": 405, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - "execution_count": 405, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numbers" - ] - }, - { - "cell_type": "code", - "execution_count": 406, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]" - ] - }, - "execution_count": 406, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sorted(numbers, reverse=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 407, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[4, 1, 10, 9, 6, 2, 12, 3, 5, 8, 11, 7]" - ] - }, - "execution_count": 407, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(reversed(numbers))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Whereas both [sorted()](https://docs.python.org/3/library/functions.html#sorted) and [reversed()](https://docs.python.org/3/library/functions.html#reversed) do *not* mutate their arguments, the *mutable* `list` type comes with two methods, [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) and `reverse()`, that implement the same logic but mutate an object, like `numbers` below, *in place*. To indicate that all changes occur *in place*, the [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) and `reverse()` methods always return `None`, which is not shown." - ] - }, - { - "cell_type": "code", - "execution_count": 408, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" - ] - }, - "execution_count": 408, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numbers" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The `reverse()` method is *eager*, as opposed to the *lazy* [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in. That means the mutations causes by the `reverse()` method are written into memory right away." - ] - }, - { - "cell_type": "code", - "execution_count": 409, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "numbers.reverse()" - ] - }, - { - "cell_type": "code", - "execution_count": 410, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[4, 1, 10, 9, 6, 2, 12, 3, 5, 8, 11, 7]" - ] - }, - "execution_count": 410, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numbers" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "*Sorting* `numbers` in *reverse* order below is of course still *different* from simply *reversing* it above." - ] - }, - { - "cell_type": "code", - "execution_count": 411, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "numbers.sort(reverse=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 412, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]" - ] - }, - "execution_count": 412, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numbers" - ] - }, - { - "cell_type": "code", - "execution_count": 413, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "numbers.sort()" - ] - }, - { - "cell_type": "code", - "execution_count": 414, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]" - ] - }, - "execution_count": 414, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numbers" + "len(current_position)" ] }, { @@ -12189,13 +6876,7 @@ "\n", "`list` objects are **mutable**. That means we can change the references to the other objects it contains, and, in particular, re-assign them.\n", "\n", - "On the contrary, `tuple` objects are like **immutable** lists: We can use them in place of any `list` object as long as we do *not* need to mutate it. Often, `tuple` objects are also used to model **records** of related **fields**.\n", - "\n", - "The tasks we do with sequential data follow the **map-filter-reduce paradigm**: We apply the same transformation to all elements, filter some of them out, and calculate summary statistics from the remaining ones.\n", - "\n", - "An essential idea in this chapter is that, in many situations, we need *not* have all the data **materialized** in memory. Instead, **iterators** allow us to process sequential data on a one-by-one basis.\n", - "\n", - "Examples for iterators are the `map`, `filter`, and `generator` types." + "On the contrary, `tuple` objects are like **immutable** lists: We can use them in place of any `list` object as long as we do *not* need to mutate it. Often, `tuple` objects are also used to model **records** of related **fields**." ] } ], diff --git a/07_sequences_01_review.ipynb b/07_sequences_01_review.ipynb index d374b3c..7e9e5da 100644 --- a/07_sequences_01_review.ipynb +++ b/07_sequences_01_review.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", "# Chapter 7: Sequential Data" ] }, @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb) of the book. Then, work through the questions below." + "The questions below assume that you have read [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb) in the book.\n", + "\n", + "Be concise in your answers! Most questions can be answered in *one* sentence." ] }, { @@ -47,7 +48,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -61,7 +62,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -75,7 +76,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -89,7 +90,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -103,7 +104,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -117,7 +118,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -133,7 +134,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -147,7 +148,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -161,104 +162,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q9**: With the [map()](https://docs.python.org/3/library/functions.html#map) and [filter()](https://docs.python.org/3/library/functions.html#filter) built-ins and the [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) function from the [functools](https://docs.python.org/3/library/functools.html) module in the [standard library](https://docs.python.org/3/library/index.html), we can replace many tedious `for`-loops and `if` statements. What are some advantages of doing so?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q10**: Looking at the `lambda` expression inside [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) below, what \"simple\" [built-in function](https://docs.python.org/3/library/functions.html) is mimicked here?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```python\n", - "from functools import reduce\n", - "\n", - "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]\n", - "\n", - "reduce(lambda x, y: x if x > y else y, numbers)\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q11**: What is the primary use case of **list comprehensions**? Why do we describe them as **eager**?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q12**: **Generator expressions** may replace `list` objects and list comprehensions in many scenarios. When evaluated, they create a **lazy** `generator` object that does *not* **materialize** its elements right away. What do we mean by that? What does it mean for a `generator` object to be **exhausted**?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q13**: What does it mean for the **boolean reducers**, the built-in [all()](https://docs.python.org/3/library/functions.html#all) and [any()](https://docs.python.org/3/library/functions.html#any) functions, to follow the **short-circuiting** strategy?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q14**: What is an **iterator**? How does it relate to an **iterable**?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " + " < your answer >" ] }, { @@ -279,84 +183,42 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q15**: `sequence` objects are *not* part of core Python but may be imported from the [standard library](https://docs.python.org/3/library/index.html)." + "**Q9**: `sequence` objects are *not* part of core Python but may be imported from the [standard library](https://docs.python.org/3/library/index.html)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q16**: The built-in [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) function takes a *finite* **iterable** as its argument an returns a *new* `list` object. On the contrary, the [sorted()](https://docs.python.org/3/library/functions.html#sorted) method on `list` objects *mutates* them *in place*." + "**Q10**: The built-in [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) function takes a *finite* **iterable** as its argument an returns a *new* `list` object. On the contrary, the [sorted()](https://docs.python.org/3/library/functions.html#sorted) method on `list` objects *mutates* them *in place*." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q17**: Passing **mutable** objects as arguments to functions is not problematic because functions operate in a **local** scope without affecting the **global** scope." + "**Q11**: Passing **mutable** objects as arguments to functions is not problematic because functions operate in a **local** scope without affecting the **global** scope." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q18**: `lambda` expressions are useful in the context of the **map-filter-reduce** paradigm, where we often do *not* re-use a `function` object more than once." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q19**: Using **generator expressions** in place of **list comprehensions** wherever possible is a good practice as it makes our programs use memory more efficiently." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q20**: Just as **list comprehensions** create `list` objects, **tuple comprehensions** create `tuple` objects." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " + " < your answer >" ] } ], diff --git a/07_sequences_02_exercises.ipynb b/07_sequences_02_exercises.ipynb index daad5e0..b8d0a7b 100644 --- a/07_sequences_02_exercises.ipynb +++ b/07_sequences_02_exercises.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", "# Chapter 7: Sequential Data" ] }, @@ -19,7 +18,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb) of the book. Then, work through the exercises below." + "The exercises below assume that you have read [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb) in the book.\n", + "\n", + "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." ] }, { @@ -54,7 +55,19 @@ "outputs": [], "source": [ "def nested_sum(list_of_lists):\n", - " ..." + " \"\"\"Add up numbers in nested lists.\n", + " \n", + " Args:\n", + " list_of_lists (list): A list containing the lists with the numbers\n", + " \n", + " Returns:\n", + " sum (int or float)\n", + " \"\"\"\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " return ..." ] }, { @@ -70,27 +83,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q1.2**: Provide a one-line expression to obtain the *same* result as `nested_sum()`!\n", + "**Q1.2**: Generalize `nested_sum()` into a function `mixed_sum()` that can process a \"mixed\" `list` object, which contains numbers and other `list` objects with numbers! Use `mixed_numbers` below for testing!\n", "\n", - "Hints: Use a *list comprehension*, or maybe even a *generator expression*. You may want to use the built-in [sum()](https://docs.python.org/3/library/functions.html#sum) function several times." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q1.3**: Generalize `nested_sum()` into a function `mixed_sum()` that can process a \"mixed\" `list` object, which contains numbers and other `list` objects with numbers! Use `mixed_numbers` below for testing!\n", - "\n", - "Hints: Use the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to check how an element is to be processed. Get extra credit for adhering to *goose typing*, as explained in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb#Goose-Typing)." + "Hints: Use the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to check how an element is to be processed. Get extra credit for adhering to *goose typing*, as explained in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb#Goose-Typing): Use some appropriate abstract base class (ABC) from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module in the [standard library](https://docs.python.org/3/library/index.html)." ] }, { @@ -117,8 +112,24 @@ "metadata": {}, "outputs": [], "source": [ - "def mixed_sum(list_of_lists):\n", - " ..." + "def mixed_sum(list_of_lists_or_numbers):\n", + " \"\"\"Add up numbers in nested lists.\n", + " \n", + " Args:\n", + " list_of_lists_or_numbers (list): A list containing both numbers and\n", + " lists with numbers\n", + " \n", + " Returns:\n", + " sum (int or float)\n", + " \"\"\"\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " return ..." ] }, { @@ -134,7 +145,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q1.4.1**: Write a function `cum_sum()` that takes a `list` object with numbers as its argument and returns a *new* `list` object with the **cumulative sums** of these numbers! So, `sum_up` below, `[1, 2, 3, 4, 5]`, should return `[1, 3, 6, 10, 15]`.\n", + "**Q1.3.1**: Write a function `cum_sum()` that takes a `list` object with numbers as its argument and returns a *new* `list` object with the **cumulative sums** of these numbers! So, `sum_up` below, `[1, 2, 3, 4, 5]`, should return `[1, 3, 6, 10, 15]`.\n", "\n", "Hint: The idea behind is similar to the [cumulative distribution function](https://en.wikipedia.org/wiki/Cumulative_distribution_function) from statistics." ] @@ -155,7 +166,23 @@ "outputs": [], "source": [ "def cum_sum(numbers):\n", - " ..." + " \"\"\"Create the cumulative sums for some numbers.\n", + "\n", + " Args:\n", + " numbers (list): A list with numbers for that the cumulative sums\n", + " are calculated\n", + " \n", + " Returns:\n", + " cum_sums (list): A list with all the cumulative sums\n", + " \"\"\"\n", + " ...\n", + " ...\n", + "\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " return ..." ] }, { @@ -171,7 +198,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q1.4.2**: We should always make sure that our functions also work in corner cases. What happens if your implementation of `cum_sum()` is called with an empty list `[]`? Make sure it handles that case *without* crashing! What would be a good return value in this corner case? Describe everything in the docstring.\n", + "**Q1.3.2**: We should always make sure that our functions also work in corner cases. What happens if your implementation of `cum_sum()` is called with an empty list `[]`? Make sure it handles that case *without* crashing! What would be a good return value in this corner case?\n", "\n", "Hint: It is possible to write this without any extra input validation." ] @@ -185,6 +212,13 @@ "cum_sum([])" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " < your answer >" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -228,7 +262,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -283,7 +317,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -322,7 +356,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -386,7 +420,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -425,7 +459,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -504,7 +538,10 @@ "source": [ "def product(*args, ...):\n", " \"\"\"Multiply all arguments.\"\"\"\n", - " ..." + " ...\n", + " ...\n", + "\n", + " return ..." ] }, { @@ -609,7 +646,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " + " < your answer >" ] }, { @@ -638,7 +675,13 @@ "source": [ "def product(*args, ...):\n", " \"\"\"Multiply all arguments.\"\"\"\n", - " ..." + " ...\n", + " ...\n", + "\n", + " ...\n", + " ...\n", + "\n", + " return ..." ] }, { @@ -697,7 +740,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Side Note**: Above, we make `product()` work with a single *collection* type argument instead of a *sequence* type to keep it more generic: For example, we can pass in a `set` object, like `{2, 5, 10}` below, and `product()` continues to work correctly. The `set` type is introducted in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb#The-set-Type), and one essential difference to the `list` type is that objects of type `set` have *no* order regarding their elements. So, even though `[2, 5, 10]` and `{2, 5, 10}` look almost the same, the order implied in the literal notation gets lost in memory!" + "**Side Note**: Above, we make `product()` work with a single *collection* type argument instead of a *sequence* type to keep it more generic: For example, we can pass in a `set` object, like `{2, 5, 10}` below, and `product()` continues to work correctly. The `set` type is introducted in [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_lecture.ipynb#The-set-Type), and one essential difference to the `list` type is that objects of type `set` have *no* order regarding their elements. So, even though `[2, 5, 10]` and `{2, 5, 10}` look almost the same, the order implied in the literal notation gets lost in memory!" ] }, { @@ -706,7 +749,7 @@ "metadata": {}, "outputs": [], "source": [ - "product([2, 5, 10]) # the argument is a special collection type, namely a sequence" + "product([2, 5, 10]) # the argument is a collection that is also a sequence" ] }, { @@ -758,7 +801,15 @@ "source": [ "def product(*args, ...):\n", " \"\"\"Multiply all arguments.\"\"\"\n", - " ..." + " ...\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " ...\n", + " ...\n", + "\n", + " return ..." ] }, { @@ -769,1011 +820,6 @@ "source": [ "product()" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we have an implementation of `product()` that is convenient to use for the caller of our function. In particular, we can pass it a *collection* with or without *unpacking* it.\n", - "\n", - "However, this version of `product()` suffers from one more flaw: We cannot pass it a *stream* of data, as modeled, for example, with an *iterator* object that produces elements on a one-by-one basis.\n", - "\n", - "Let's look at an example. The [*stream.py*](https://github.com/webartifex/intro-to-python/blob/master/stream.py) module in the repository provides a `make_finite_stream()` function. It is a *factory* function creating objects of type `generator` that we use to model *streaming* data." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from stream import make_finite_stream" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "stream = make_finite_stream()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "stream" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "type(stream)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Being a `generator`, `stream` is also an `Iterator` in the abstract sense." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "isinstance(stream, abc.Iterator)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "*Iterators* are good for only *one* thing: Giving us the \"next\" element in a line of many." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "next(stream)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "They themselves have *no* idea of how many elements they produce eventually: The built-in [len()](https://docs.python.org/3/library/functions.html#len) function raises a `TypeError`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "len(stream)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can use the [list()](https://docs.python.org/3/library/functions.html#func-list) built-in to *materialize* the elements. However, in a real-world scenario, these may *not* fit into our machine's memory!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "list(stream)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To be more realistic, `make_finite_stream()` creates `generator` objects producing a varying number of elements." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "list(make_finite_stream())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "list(make_finite_stream())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "list(make_finite_stream())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's see what happens if we pass an *iterator*, as created by `make_finite_stream()`, instead of a materialized *collection*, like `one_hundred`, to `product()`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "product(make_finite_stream())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q2.11**: What line causes the `TypeError`? What line is really the problem in the latest implementation of `product()`? Describe what happens on each line in the function's body until the exception is raised!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q2.12**: Adapt `product()` one last time to make it work with *iterators* as well!\n", - "\n", - "Hints: This task is as easy as replacing `Collection` with something else. Which of the three behaviors of *collections* do *iterators* also exhibit? You may want to look at the documentations on the built-in [max()](https://docs.python.org/3/library/functions.html#max), [min()](https://docs.python.org/3/library/functions.html#min), and [sum()](https://docs.python.org/3/library/functions.html#sum) functions: What kind of argument do they take?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def product(*args, ...):\n", - " \"\"\"Multiply all arguments.\"\"\"\n", - " ..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The final version of `product()` behaves like built-ins in edge cases, ..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "product()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... works with the arguments passed either as independent *positional* arguments, *packed* into a single *collection* argument, or *unpacked*, ..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "product(42)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "product(2, 5, 10)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "product([2, 5, 10])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "product(*[2, 5, 10])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... and can handle *streaming* data with *indefinite* \"length.\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "product(make_finite_stream())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In real-world projects, the data science practitioner must decide if it is worthwhile to make a function usable in various different forms as we did in this exercise, or if that is over-engineered.\n", - "\n", - "Yet, two lessons are important to take away:\n", - "- It is always a good idea to *mimic* the behavior of *built-ins* when in doubt.\n", - "- Make functions capable of working with *streaming* data." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Removing Outliers in Streaming Data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's say we are given a `list` object with random integers like `sample` below, and we want to calculate some basic statistics on them." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample = [\n", - " 45, 46, 40, 49, 36, 53, 49, 42, 25, 40, 39, 36, 38, 40, 40, 52, 36, 52, 40, 41,\n", - " 35, 29, 48, 43, 42, 30, 29, 33, 55, 33, 38, 50, 39, 56, 52, 28, 37, 56, 45, 37,\n", - " 41, 41, 37, 30, 51, 32, 23, 40, 53, 40, 45, 39, 99, 42, 34, 42, 34, 39, 39, 53,\n", - " 43, 37, 46, 36, 45, 42, 32, 38, 57, 34, 36, 44, 47, 51, 46, 39, 28, 40, 35, 46,\n", - " 41, 51, 41, 23, 46, 40, 40, 51, 50, 32, 47, 36, 38, 29, 32, 53, 34, 43, 39, 41,\n", - " 40, 34, 44, 40, 41, 43, 47, 57, 50, 42, 38, 25, 45, 41, 58, 37, 45, 55, 44, 53,\n", - " 82, 31, 45, 33, 32, 39, 46, 48, 42, 47, 40, 45, 51, 35, 31, 46, 40, 44, 61, 57,\n", - " 40, 36, 35, 55, 40, 56, 36, 35, 86, 36, 51, 40, 54, 50, 49, 36, 41, 37, 48, 41,\n", - " 42, 44, 40, 43, 51, 47, 46, 50, 40, 23, 40, 39, 28, 38, 42, 46, 46, 42, 46, 31,\n", - " 32, 40, 48, 27, 40, 40, 30, 32, 25, 31, 30, 43, 44, 29, 45, 41, 63, 32, 33, 58,\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "len(sample)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.1**: `list` objects are **sequences**. What *four* behaviors do they always come with?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.2**: Write a function `mean()` that calculates the simple arithmetic mean of a given `sequence` with numbers!\n", - "\n", - "Hints: You can solve this task with [built-in functions](https://docs.python.org/3/library/functions.html) only. A `for`-loop is *not* needed." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def mean(sequence):\n", - " ..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample_mean = mean(sample)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample_mean" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.3**: Write a function `std()` that calculates the [standard deviation](https://en.wikipedia.org/wiki/Standard_deviation) of a `sequence` of numbers! Integrate your `mean()` version from before and the [sqrt()](https://docs.python.org/3/library/math.html#math.sqrt) function from the [math](https://docs.python.org/3/library/math.html) module in the [standard library](https://docs.python.org/3/library/index.html) provided to you below. Make sure `std()` calls `mean()` only *once* internally! Repeated calls to `mean()` would be a waste of computational resources.\n", - "\n", - "Hints: Parts of the code are probably too long to fit within the suggested 79 characters per line. So, use *temporary variables* inside your function. Instead of a `for`-loop, you may want to use a *list comprehension* or, even better, a memoryless *generator expression*." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from math import sqrt" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def std(sequence):\n", - " ..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample_std = std(sample)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample_std" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.4**: Complete `standardize()` below that takes a `sequence` of numbers and returns a `list` object with the **[z-scores](https://en.wikipedia.org/wiki/Standard_score)** of these numbers! A z-score is calculated by subtracting the mean and dividing by the standard deviation. Re-use `mean()` and `std()` from before. Again, ensure that `standardize()` calls `mean()` and `std()` only *once*! Further, round all z-scores with the built-in [round()](https://docs.python.org/3/library/functions.html#round) function and pass on the keyword-only argument `digits` to it.\n", - "\n", - "Hint: You may want to use a *list comprehension* instead of a `for`-loop." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def standardize(sequence, *, digits=3):\n", - " ..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "z_scores = standardize(sample)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The [pprint()](https://docs.python.org/3/library/pprint.html#pprint.pprint) function from the [pprint](https://docs.python.org/3/library/pprint.html) module in the [standard library](https://docs.python.org/3/library/index.html) allows us to \"pretty print\" long `list` objects compactly." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from pprint import pprint" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pprint(z_scores, compact=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We know that `standardize()` works correctly if the resulting z-scores' mean and standard deviation approach `0` and `1` for a long enough `sequence`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mean(z_scores), std(z_scores)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Even though `standardize()` calls `mean()` and `std()` only once each, `mean()` is called *twice*! That is so because `std()` internally also re-uses `mean()`!\n", - "\n", - "**Q3.5.1**: Rewrite `std()` to take an optional keyword-only argument `seq_mean`, defaulting to `None`. If provided, `seq_mean` is used instead of the result of calling `mean()`. Otherwise, the latter is called.\n", - "\n", - "Hint: You must check if `seq_mean` is still the default value." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def std(sequence, *, seq_mean=None):\n", - " ..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`std()` continues to work as before." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample_std = std(sample)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample_std" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.5.2**: Now, rewrite `standardize()` to pass on the return value of `mean()` to `std()`! In summary, `standardize()` calculates the z-scores for the numbers in the `sequence` with as few computational steps as possible." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def standardize(sequence, *, digits=3):\n", - " ..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "z_scores = standardize(sample)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mean(z_scores), std(z_scores)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.6**: With both `sample` and `z_scores` being materialized `list` objects, we can loop over pairs consisting of a number from `sample` and its corresponding z-score. Write a `for`-loop that prints out all the \"outliers,\" as which we define numbers with an absolute z-score above `1.96`. There are *four* of them in the `sample`.\n", - "\n", - "Hint: Use the [abs()](https://docs.python.org/3/library/functions.html#abs) and [zip()](https://docs.python.org/3/library/functions.html#zip) built-ins." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We provide a `stream` module with a `data` object that models an *infinite* **stream** of data (cf., the [*stream.py*](https://github.com/webartifex/intro-to-python/blob/master/stream.py) file in the repository)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from stream import data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`data` is of type `generator` and has *no* length." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "type(data)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "len(data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Being a `generator`, it is an `Iterator` in the abstract sense ..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import collections.abc as abc" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "isinstance(data, abc.Iterator)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... and so the only thing we can do with it is to pass it to the built-in [next()](https://docs.python.org/3/library/functions.html#next) function and go over the numbers it streams one by one." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "next(data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.7**: What happens if you call `mean()` with `data` as the argument? What is the problem?\n", - "\n", - "Hints: If you try it out, you may have to press the \"Stop\" button in the toolbar at the top. Your computer should *not* crash, but you will *have to* restart this Jupyter notebook with \"Kernel\" > \"Restart\" and import `data` again." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mean(data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.8**: Write a function `take_sample()` that takes an `iterator` as its argument, like `data`, and creates a *materialized* `list` object out of its first `n` elements, defaulting to `1_000`!\n", - "\n", - "Hints: [next()](https://docs.python.org/3/library/functions.html#next) and the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in may be helpful. You may want to use a *list comprehension* instead of a `for`-loop and write a one-liner. Audacious students may want to look at [isclice()](https://docs.python.org/3/library/itertools.html#itertools.islice) in the [itertools](https://docs.python.org/3/library/itertools.html) module in the [standard library](https://docs.python.org/3/library/index.html)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def take_sample(iterator, *, n=1_000):\n", - " ..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We take a `new_sample` from the stream of `data`, and its statistics are similar to the initial `sample`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "new_sample = take_sample(data)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "len(new_sample)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mean(new_sample)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "std(new_sample)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.9**: Convert `standardize()` into a *new* function `standardized()` that implements the *same* logic but works on a possibly *infinite* stream of data, provided as an `iterable`, instead of a *finite* `sequence`.\n", - "\n", - "To calculate a z-score, we need the stream's overall mean and standard deviation, and that is *impossible* to calculate if we do not know how long the stream is, and, in particular, if it is *infinite*. So, `standardized()` first takes a sample from the `iterable` internally, and uses the sample's mean and standard deviation to calculate the z-scores.\n", - "\n", - "Hint: `standardized()` *must* return a `generator` object. So, use a *generator expression* as the return value; unless you know about the `yield` statement already (cf., [reference](https://docs.python.org/3/reference/simple_stmts.html#the-yield-statement))." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def standardized(iterable, *, digits=3):\n", - " ..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`standardized()` works almost like `standardize()` except that we use it with [next()](https://docs.python.org/3/library/functions.html#next) to obtain the z-scores one by one." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "z_scores = standardized(data)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "z_scores" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "type(z_scores)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "next(z_scores)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.10.1**: `standardized()` allows us to go over an *infinite* stream of z-scores. What we want to do instead is to loop over the stream's raw numbers and skip the outliers. In the remainder of this exercise, you look at the parts that make up the `skip_outliers()` function below to achieve precisely that.\n", - "\n", - "The first steps in `skip_outliers()` are the same as in `standardized()`: We take a `sample` from the stream of `data` and calculate its statistics." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample = ...\n", - "seq_mean = ...\n", - "seq_std = ..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.10.2**: Just as in `standardized()`, write a *generator expression* that produces z-scores one by one! However, instead of just generating a z-score, the resulting `generator` object should produce `tuple` objects consisting of a \"raw\" number from `data` and its z-score.\n", - "\n", - "Hint: Look at the revisited \"*Averaging Even Numbers*\" example in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Example:-Averaging-Even-Numbers-%28revisited%29) for some inspiration, which also contains a generator expression producing `tuple` objects." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "standardizer = (... for ... in data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`standardizer` should produce `tuple` objects." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "next(standardizer)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.10.3**: Write another generator expression that loops over `standardizer`. It contains an `if`-clause that keeps only numbers with an absolute z-score below the `threshold_z`. If you fancy, use *tuple unpacking*." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "threshold_z = 1.96" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "no_outliers = (... for ... in standardizer if ...)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`no_outliers` should produce `int` objects." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "next(no_outliers)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.10.4**: Lastly, put everything together in the `skip_outliers()` function! Make sure you refer to `iterable` inside the function and not the global `data`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def skip_outliers(iterable, *, threshold_z=1.96):\n", - " sample = ...\n", - " seq_mean = ...\n", - " seq_std = ...\n", - " standardizer = ...\n", - " no_outliers = ...\n", - " return no_outliers" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we can create a `generator` object and loop over the `data` in the stream with outliers skipped. Instead of the default `1.96`, we use a `threshold_z` of only `0.05`: That filters out all numbers except `42`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "skipper = skip_outliers(data, threshold_z=0.05)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "skipper" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "type(skipper)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "next(skipper)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Q3.11**: You implemented the functions `mean()`, `std()`, `standardize()`, `standardized()`, and `skip_outliers()`. Which of them are **eager**, and which are **lazy**? How do these two concepts relate to **finite** and **infinite** data?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " " - ] } ], "metadata": { diff --git a/README.md b/README.md index 5c2c6e3..b46a9ff 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,3 @@ -**Important**: The content is being updated and amended throughout the -spring semester of 2020! - # An Introduction to Python and Programming The purpose of this repository is to serve as an interactive "book" for a @@ -17,41 +14,56 @@ They can be viewed in a plain web browser with the help of [nbviewer](https://nbviewer.jupyter.org/): - *Introduction*: Start up - ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb) + ([video](https://www.youtube.com/watch?v=YTU8jaG27Xk) + | [lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb) | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_01_review.ipynb) | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_02_exercises.ipynb)) - **Part A: Expressing Logic** - *Chapter 1*: Elements of a Program - ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb) + ([video](https://www.youtube.com/watch?v=v0lk1Qfaw8Y) + | [lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb) | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_01_review.ipynb) | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_02_exercises.ipynb)) - *Chapter 2*: Functions & Modularization - ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb) + ([video](https://www.youtube.com/watch?v=j4Xn8QFysmc) + | [lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb) | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_01_review.ipynb) | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_02_exercises.ipynb)) - *Chapter 3*: Conditionals & Exceptions - ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb) + ([video](https://www.youtube.com/watch?v=aDbblINzuGQ) + | [lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb) | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_01_review.ipynb) | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_02_exercises.ipynb)) - *Chapter 4*: Recursion & Looping - ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) + ([video](https://www.youtube.com/watch?v=jT6hr4vOJks) + | [lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_01_review.ipynb) - | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_02_exercises.ipynb)) + | [exercises 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_02_exercises.ipynb) + | [exercises 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_03_exercises.ipynb)) - **Part B: Managing Data and Memory** - - *Chapter 5*: Bits & Numbers - ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb) + - *Chapter 5*: Numbers & Bits + ([video](https://www.youtube.com/watch?v=nB00WGCnVjg) + | [lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb) | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_01_review.ipynb) | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_02_exercises.ipynb)) - - *Chapter 6*: Bytes & Text - ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb) + - *Chapter 6*: Text & Bytes + ([video](https://www.youtube.com/watch?v=3WTRlgN09sM) + | [lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb) | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_01_review.ipynb) - | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_02_exercises.ipynb))) + | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_02_exercises.ipynb)) - *Chapter 7*: Sequential Data - ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb) + ([video](https://www.youtube.com/watch?v=nx2sCDoeC3I) + | [lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb) | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_01_review.ipynb) | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_02_exercises.ipynb)) - - *Chapter 8*: Mappings & Sets - ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb) + - *Chapter 8*: Map, Filter, & Reduce + ([video](https://www.youtube.com/watch?v=ePzzq2YBWjY) + | [lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_lecture.ipynb) + | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_01_review.ipynb) + | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_02_exercises.ipynb)) + - *Chapter 9*: Mappings & Sets + ([video](https://www.youtube.com/watch?v=vbp0svA35TE) + | [lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb) | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_01_review.ipynb) | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_02_exercises.ipynb)) @@ -62,11 +74,16 @@ Precise **installation instructions** are either in the [00th notebook]( https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb) or further below. +A playlist with all video presentations of the individiual chapters can be found [here](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f). + Feedback is encouraged and will be incorporated. Open an issue in the [issues tracker](https://github.com/webartifex/intro-to-python/issues) or initiate a [pull request](https://help.github.com/en/articles/about-pull-requests) if you are familiar with the concept. +A "Show HN" post about this introduction was made on [Hacker News](https://news.ycombinator.com/item?id=22669084) +and some ideas for improvement were discussed there. + ## Prerequisites diff --git a/pyproject.toml b/pyproject.toml index 63ec6ae..d4c3c99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "intro-to-python" -version = "0.6.7" +version = "0.6.8" description = "An introduction to Python and programming for wanna-be data scientists" authors = ["Alexander Hess "] license = "MIT" diff --git a/sample_module.py b/sample_module.py index b16e7b2..3a097e1 100644 --- a/sample_module.py +++ b/sample_module.py @@ -43,7 +43,7 @@ def average(numbers, *, scalar=1): scalar (float, optional): multiplies the average; defaults to 1 Returns: - float: (scaled) average + scaled_average (float) """ return _scaled_average(_round_all(numbers), scalar) @@ -57,7 +57,7 @@ def average_evens(numbers, *, scalar=1): scalar (float, optional): multiplies the average; defaults to 1 Returns: - float: (scaled) average + scaled_average (float) """ return _scaled_average([n for n in _round_all(numbers) if n % 2 == 0], scalar) @@ -71,6 +71,6 @@ def average_odds(numbers, *, scalar=1): scalar (float, optional): multiplies the average; defaults to 1 Returns: - float: (scaled) average + scaled_average (float) """ return _scaled_average([n for n in _round_all(numbers) if n % 2 != 0], scalar)