diff --git a/Python/Module1_GettingStartedWithPython/GettingStartedWithPython.md b/Python/Module1_GettingStartedWithPython/GettingStartedWithPython.md index ed1f2f1a..08c6ce40 100644 --- a/Python/Module1_GettingStartedWithPython/GettingStartedWithPython.md +++ b/Python/Module1_GettingStartedWithPython/GettingStartedWithPython.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -15,7 +15,7 @@ jupyter: .. meta:: :description: Topic: Basic description of the Python programming language, Difficulty: Easy, Category: Background - :keywords: python, install, basics, scripts, interpreter, foundations + :keywords: python, install, basics, scripts, interpreter, foundations, versions @@ -144,6 +144,62 @@ As such, Python is a language that is conducive to rapidly prototyping and testi We will be relying heavily on Python and a library for doing optimized numerical computations, called NumPy, throughout this course. + +## Understanding Different Versions of Python + +New versions of Python come out periodically, bringing new features and fixes. +You can keep track of what's new in Python by [bookmarking and checking this page every few months](https://docs.python.org/3/whatsnew/index.html). +As we take on coding projects in Python, whether it be for work, school, or a personal hobby, it is important that we remain aware of +the ways in which the language is changing, and that we take care to write code that will remain functional in the future. + +All Python version numbers use the `A.B.C` format, in accordance with [semantic versioning](https://semver.org/). +The three numbers denote major releases, minor releases, and patches. +For example, as of writing this, the current release of Python is version `3.9.1`. + +The first number denotes major releases to the language. +When a major release comes out, it means that older code will not necessarily work with the new release, and vice versa. +For example, the following code worked in Python 2 but no longer works because the `xrange` function was removed from the language +upon the release of Python 3. + +```python +# `xrange` was a frequently-used function in Python 2, but +# was removed from the language in Python 3 in favor of `range`. +# Thus the following code does not work in any version of Python 3. +count = 0 +for i in xrange(10): + count = count + 1 +``` + +The most current major release is Python 3; Python 2 is no longer supported by any bug or security fixes and should not be used. +All releases in the near future will be improvements to Python 3, and thus they will come in the form of minor releases and patches. + +The second number denotes a minor release. +A minor release will be compatible with code from the preceding release, but it might add new features to the language that are not backwards-compatible. +For example, Python 3.6 introduced [formatted string literals](https://docs.python.org/3/whatsnew/3.6.html#pep-498-formatted-string-literals), which are +commonly referred to as "f-strings". +Thus as of Python 3.6 you could write code like + +```python +# Python 3.6 introduced the "f-string" feature, which is not +# backwards compatible with Python 3.5 +>>> f"one plus two is {1 + 2}" +'one plus two is 3' +``` + +but this code would not run in Python 3.5.X. + +The third and final number denotes a patch, which generally means bug fixes and performance improvements. +All code within the same minor release will run on all other patches within that minor release +For example, all Python 3.7.8 code is compatible with a Python 3.7.1 interpreter, and vice versa. +Patches are released fairly often, and their changes only occur 'under the hood'. +[Here is a list of changes](https://docs.python.org/3/whatsnew/changelog.html#python-3-9-1-final) were introduced by the patch level increment from Python 3.9.0 to Python 3.9.1; +few of these would affect our day-to-day experience with using Python (which isn't to say that they aren't important!). + +In simpler terms, major releases are neither backward nor forward compatible. +Minor releases are forward compatible but not necessarily fully backward compatible, and patches are both forward and backward compatible. + + + ## Summary - Python is a programming language - it provides us with a simple set of grammatical rules that allow us to write human-readable text, which can be translated unambiguously to instruct a computer to perform tasks. diff --git a/Python/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.md b/Python/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.md index 2390a6b2..d780d32f 100644 --- a/Python/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.md +++ b/Python/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -39,41 +39,51 @@ First and foremost, a good IDE will provide a text editor that will: An IDE also often provides debugging tools so that you can test your code; it will also typically interface with version-control software, like Git, so that you can keep track of versions of your code as you modify it. We will not discuss these useful, but more advanced features here. -### Recommended IDEs +## Recommended IDEs There are many excellent IDEs that can be configured to work well with Python. Two IDEs that we endorse are: -[PyCharm](https://www.jetbrains.com/pycharm/download): A powerful IDE dedicated to Python. +### PyCharm + +[PyCharm](https://www.jetbrains.com/pycharm/download) is a powerful and highly-polished IDE dedicated to developing Python code. **Pros** -- works well out-of-the-box -- long-supported by professionals and thus is very reliable -- highly configurable -- fully-featured, with an excellent debugger, context-dependent "intellisense", type-inference, and more -- the free "community version" is extremely robust and feature-rich. +- Works well out-of-the-box. +- Long-supported by professionals and thus is very reliable. +- Highly configurable. +- Fully-featured, with an excellent debugger, context-dependent "intellisense", type-inference, and more. +- The free "community version" is extremely robust and feature-rich. +- Generally provides an extremely high-quality and responsive experience for doing Python development. **Cons** - - can be resource-heavy, especially for a laptop - - may be overwhelming to new users (but has good documentation and tutorials) - - Jupyter notebook support requires the premium version of PyCharm, making it inaccessible to newcomers + - Can be resource-heavy, especially for a laptop. + - May be overwhelming to new users (but has good documentation and tutorials). + - Jupyter notebook support requires the premium version of PyCharm, making it inaccessible to newcomers. -[Visual Studio Code](https://code.visualstudio.com/) with the [Python extension](https://code.visualstudio.com/docs/languages/python): A lightweight, highly customizable IDE. +### Visual Studio Code + +[Visual Studio Code](https://code.visualstudio.com/) (with the [Python extension](https://code.visualstudio.com/docs/languages/python)) is a lightweight, highly customizable IDE that works with many different languages. + +Note: if you decide to use VSCode to do Python development, it is highly recommended that you install Microsoft's [PyLance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) +extension. +This adds many useful features to the IDE that will make writing Python code a more delightful experience. **Pros** -- lightweight and elegant -- completely free -- works with many different languages, so you only need to familiarize yourself with one IDE if you are a polyglot programmer -- a huge number of extensions can be downloaded to add functionality to the editor; these are created by a large community of open-source developers. -- [has native support for Jupyter notebooks](https://code.visualstudio.com/docs/python/jupyter-support), meaning that you get VSCode's intellisense, debugger, and ability to inspect variables, all in a notebook. +- Lightweight and elegant. +- Completely free. +- Works with many different languages, so you only need to familiarize yourself with one IDE if you are a polyglot programmer. +- Offers a huge number of extensions that can be downloaded to add functionality to the editor; these are created by a large community of open-source developers. +- [Has native support for Jupyter notebooks](https://code.visualstudio.com/docs/python/jupyter-support), meaning that you get VSCode's intellisense, debugger, and ability to inspect variables, all in a notebook. +- Provides incredibly robust [remote coding](https://code.visualstudio.com/docs/remote/remote-overview) and [collaborative coding](https://visualstudio.microsoft.com/services/live-share/) capabilities. **Cons** -- configuring VSCode for python development can have a moderate learning curve for newcomers -- many features, like context-aware intellisense and type-inference, are simply more polished and powerful in PyCharm +- Configuring VSCode for Python development can have a moderate learning curve for newcomers. +- Some features, like context-aware intellisense and type-inference, are simply more polished and powerful in PyCharm. + -
**Takeaway**: diff --git a/Python/Module1_GettingStartedWithPython/Informal_Intro_Python.md b/Python/Module1_GettingStartedWithPython/Informal_Intro_Python.md index d098134a..4ae9a5e3 100644 --- a/Python/Module1_GettingStartedWithPython/Informal_Intro_Python.md +++ b/Python/Module1_GettingStartedWithPython/Informal_Intro_Python.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -19,6 +19,39 @@ jupyter: # An Informal Introduction to Python + +
+ +**Before You Start This Section**: + +In the following section we will be using IPython or a Jupyter notebook to run our code. +Presently, there is an incompatibility with these programs and a Python package called `jedi`, which typically is responsible for performing auto-completions in our code (when prompted by hitting ``, which we will be doing below). +It is really useful! + +First, let's check to see if we have an incompatible version of `jedi` installed. +In your terminal (before starting a Python/IPython/Jupyter session), run + +``` +conda list +``` + +And look for the line that starts with `jedi` + +``` +jedi 0.18.0 +``` + +If you see that you have version `0.18.0` installed (as above), then you will want to downgrade it. +In the same terminal, run the following command + +``` +conda install jedi=0.17.2 +``` +You should be all set once you have followed the prompts and the installation has completed! + +Note that you will need to repeat this process if you [create a new conda environment](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html#A-Brief-Introduction-to-Conda-Environments) with IPython/Jupter installed in it. +
+ Now that you have the Anaconda distribution of Python installed on your machine, let's write some simple Python code! We are going to forego writing a full Python script for now, and instead make use of a convenient tool for doing quick code scratchwork. The IPython console was installed as a part of Anaconda; it will allow us to build incrementally off of snippets of code, instead of having to execute an entire script all at once. Let's open an IPython console. Open your terminal if you are a Mac/Linux user, or start `cmd.exe` if you are a Windows user. Now type `ipython` into the console and hit ``. You should see the following display on your screen: diff --git a/Python/Module1_GettingStartedWithPython/Installing_Python.md b/Python/Module1_GettingStartedWithPython/Installing_Python.md index c415deee..67a21a98 100644 --- a/Python/Module1_GettingStartedWithPython/Installing_Python.md +++ b/Python/Module1_GettingStartedWithPython/Installing_Python.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module1_GettingStartedWithPython/Jupyter_Notebooks.md b/Python/Module1_GettingStartedWithPython/Jupyter_Notebooks.md index 0bb42a42..cf817578 100644 --- a/Python/Module1_GettingStartedWithPython/Jupyter_Notebooks.md +++ b/Python/Module1_GettingStartedWithPython/Jupyter_Notebooks.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -19,19 +19,57 @@ jupyter: # Jupyter Notebooks -In recent years, the Jupyter Notebook has become a massively popular tool for doing research-oriented work in Python and other languages alike. Its emergence marked a paradigm shift in the way data science is conducted. -A Jupyter notebook is similar to the IPython console, but, instead of only being able to work with a single line of code at a time, you can easily edit and re-execute *any* code that had been written in a notebook. Furthermore, you can save a notebook, and thus return to it later. Additionally, a notebook provides many terrific features. For instance, you can embed visualizations of data within a notebook, and write blocks of nicely-formatted text (using the [Markdown syntax](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)), for presenting and explaining the contents of the notebook. +
+ +**Before You Start This Section**: + +In the following section we will be using IPython or a Jupyter notebook to run our code. +Presently, there is an incompatibility with these programs and a Python package called `jedi`, which typically is responsible for performing auto-completions in our code (when prompted by hitting ``, which we will be doing below). +It is really useful! + +First, let's check to see if we have an incompatible version of `jedi` installed. +In your terminal (before starting a Python/IPython/Jupyter session), run + +``` +conda list +``` + +And look for the line that starts with `jedi` + +``` +jedi 0.18.0 +``` + +If you see that you have version `0.18.0` installed (as above), then you will want to downgrade it. +In the same terminal, run the following command + +``` +conda install jedi=0.17.2 +``` +You should be all set once you have followed the prompts and the installation has completed! + +Note that you will need to repeat this process if you [create a new conda environment](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html#A-Brief-Introduction-to-Conda-Environments) with IPython/Jupter installed in it. +
+ +In recent years, the Jupyter Notebook has become a massively popular tool for doing research-oriented work in Python and other languages alike. +Its emergence marked a paradigm shift in the way data science is conducted. + +A Jupyter notebook is similar to the IPython console, but, instead of only being able to work with a single line of code at a time, you can easily edit and re-execute *any* code that had been written in a notebook. Furthermore, you can save a notebook, and thus return to it later. +Additionally, a notebook provides many terrific features. For instance, you can embed visualizations of data within a notebook, and write blocks of nicely-formatted text (using the [Markdown syntax](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)), for presenting and explaining the contents of the notebook. In this way, the Jupyter Notebook stands out as an excellent tool for many practical applications. You could work on a notebook while you are working through sections of this website, for instance, testing out snippets of code, and answering reading-comprehension questions as you proceed through the text, and using markdown-headers to visually separate different portions of the notebook. When I do research, I am always creating Jupyter notebooks in which I write code that analyzes data, I plot various results, presented in different ways, and I write detailed markdown-text blocks to document my work. The end result is something that I can share with my labmates, and easily revisit months later without having to struggle to recall what I had done. ## Jupyter Lab -[Jupyter lab](https://jupyterlab.readthedocs.io/) is a new web interface from Project Jupyter that provides a rich web-based interface for managing and running Jupyter notebooks, console terminals, and text editors, all within your browser. Among its useful features and polished user interface - compared to that a Jupyter notebook server - Jupyter lab provides moveable panes for viewing data, images, and code output apart from the rest of the notebook. This is facilitates effective data science work flows. +[Jupyter lab](https://jupyterlab.readthedocs.io/) is a new web interface from Project Jupyter that provides a rich web-based interface for managing and running Jupyter notebooks, console terminals, and text editors, all within your browser. +Among its useful features and polished user interface, Jupyter lab provides moveable panes for viewing data, images, and code output apart from the rest of the notebook. +This is facilitates effective data science work flows. It is recommended that you peruse the [Jupyter lab documentation](https://jupyterlab.readthedocs.io/en/stable/getting_started/overview.html) to get a feel for all of its added capabilities. -The following instructions are laid out for running a Jupyter notebook server. That being said, the process for running a Jupyter lab server and working with notebooks therein is nearly identical. Both Jupyter notebook and Jupyter lab should already be [installed via Anaconda](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html). +The following instructions are laid out for running a Jupyter notebook server. That being said, the process for running a Jupyter lab server and working with notebooks therein is nearly identical. +Both Jupyter notebook and Jupyter lab should already be [installed via Anaconda](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html). ## Running a Notebook Server & Creating a Notebook @@ -100,7 +138,7 @@ import numpy as np import matplotlib.pyplot as plt # this tells Jupyter to embed matplotlib plots in the notebook -%matplotlib notebook +%matplotlib inline ``` ```python @@ -186,4 +224,4 @@ The Jupyter Notebook does not work exclusively with Python. A "kernel" can be de The ever-growing list of available kernels for use with Jupyter can be found [here](https://github.com/jupyter/jupyter/wiki/Jupyter-kernels). It should be noted that these efforts are not all equally mature. For instance, whereas the Python and Julia kernels are robust, the Haskell kernel cannot run natively on Windows machines, and the C++ kernel is still in early development, as of writing this. ### Jupyter Notebook Support in Visual Studio Code -Native Jupyter notebook support was [recently added to Visual Studio Code](https://devblogs.microsoft.com/python/announcing-support-for-native-editing-of-jupyter-notebooks-in-vs-code/). This means that you can now edit Jupyter notebooks within the [Visual Studio Code IDE](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html), and that you will benefit from added features like code-completion, debugging, and variable inspection. \ No newline at end of file +Native Jupyter notebook support was [recently added to Visual Studio Code](https://devblogs.microsoft.com/python/announcing-support-for-native-editing-of-jupyter-notebooks-in-vs-code/). This means that you can now edit Jupyter notebooks within the [Visual Studio Code IDE](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html), and that you will benefit from added features like code-completion, debugging, and variable inspection. diff --git a/Python/Module1_GettingStartedWithPython/Numerical_Work_In_Python.md b/Python/Module1_GettingStartedWithPython/Numerical_Work_In_Python.md index f68dab65..fab7fe1c 100644 --- a/Python/Module1_GettingStartedWithPython/Numerical_Work_In_Python.md +++ b/Python/Module1_GettingStartedWithPython/Numerical_Work_In_Python.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module1_GettingStartedWithPython/SiteFormatting.md b/Python/Module1_GettingStartedWithPython/SiteFormatting.md index 0f38f692..482651ca 100644 --- a/Python/Module1_GettingStartedWithPython/SiteFormatting.md +++ b/Python/Module1_GettingStartedWithPython/SiteFormatting.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -65,8 +65,36 @@ We can spend some time talking about `my_func` and then see it in action: ``` Lastly, the input and output of an iPython console and a Jupyter notebook alike is displayed as follows: - ```python 2 + 3 ``` + +## Running Code Snippets from this Site + +In PLYMI, we typically precede every code snippet with one or more commented lines. +This is useful because it makes a page more "skimmable", since the code snippets essentially come with +descriptive, self-explanatory captions. +That being said, there is a downside to this. + +Python terminals don't like having multiple comment lines precede an input-prompt. +E.g. if you paste and run the following code into a terminal + +```python +# demonstrating the distinction of +# input and output via >>> + +>>> x = 1 +``` + +you will get a syntax error. +To fix this issue, simply exclude the comments when you copy this block to your clipboard. +Running + +```python +>>> x = 1 +``` + +will work without any issue. +Keep this in mind if you ever find yourself having trouble running code that you copied from this site. + diff --git a/Python/Module2_EssentialsOfPython/Basic_Objects.md b/Python/Module2_EssentialsOfPython/Basic_Objects.md index 5a6dd54c..fcb69895 100644 --- a/Python/Module2_EssentialsOfPython/Basic_Objects.md +++ b/Python/Module2_EssentialsOfPython/Basic_Objects.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/ConditionalStatements.md b/Python/Module2_EssentialsOfPython/ConditionalStatements.md index b6192abb..9abff3a2 100644 --- a/Python/Module2_EssentialsOfPython/ConditionalStatements.md +++ b/Python/Module2_EssentialsOfPython/ConditionalStatements.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -227,11 +227,11 @@ if 3 < len(x): # bool(3 < 2) returns False, this code # block is skipped print("`x` has more than three items in it") -elif len(x) == 2 +elif len(x) == 2: # bool(len(x) == 2) returns True # this code block is executed print("`x` has two items in it") -elif len(x) == 1 +elif len(x) == 1: # this statement is never reached print("`x` has one items in it") else: @@ -332,6 +332,8 @@ That is: Python supports a syntax for writing a restricted version of if-else statements in a single line. The following code: ```python +num = 2 + if num >= 0: sign = "positive" else: @@ -353,7 +355,7 @@ This is suggestive of the general underlying syntax for inline if-else statement The expression `A if else B` returns `A` if `bool()` evaluates to `True`, otherwise this expression will return `B`.
-This syntax is highly restricted compared to the full "if-elif-else" expressions - no "elif" statement is permitted by this inline syntax, nor are muli-line code blocks within the if/else clauses. +This syntax is highly restricted compared to the full "if-elif-else" expressions - no "elif" statement is permitted by this inline syntax, nor are multi-line code blocks within the if/else clauses. Inline if-else statements can be used anywhere, not just on the right side of an assignment statement, and can be quite convenient: ```python diff --git a/Python/Module2_EssentialsOfPython/DataStructures.md b/Python/Module2_EssentialsOfPython/DataStructures.md index 81631b47..6fc26338 100644 --- a/Python/Module2_EssentialsOfPython/DataStructures.md +++ b/Python/Module2_EssentialsOfPython/DataStructures.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.md b/Python/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.md index c399d068..7290ca04 100644 --- a/Python/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.md +++ b/Python/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.md b/Python/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.md index 1b7d4d7a..a01d8831 100644 --- a/Python/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.md +++ b/Python/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/ForLoops.md b/Python/Module2_EssentialsOfPython/ForLoops.md index 821c4d40..b447734f 100644 --- a/Python/Module2_EssentialsOfPython/ForLoops.md +++ b/Python/Module2_EssentialsOfPython/ForLoops.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -14,7 +14,7 @@ jupyter: .. meta:: - :description: Topic: Contorl flow with for-loops and while-loops, Difficulty: Easy, Category: Section + :description: Topic: Control flow with for-loops and while-loops, Difficulty: Easy, Category: Section :keywords: for-loop, while-loop, break, control flow, basic programming diff --git a/Python/Module2_EssentialsOfPython/Functions.md b/Python/Module2_EssentialsOfPython/Functions.md index c57eb4c2..4b7d1cc9 100644 --- a/Python/Module2_EssentialsOfPython/Functions.md +++ b/Python/Module2_EssentialsOfPython/Functions.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -137,7 +137,7 @@ Write a function named `count_even`. It should accept one input argument, named ## The `return` Statement -In general, any Python object can follow a function's `return` statement. Furthermore, an **empty** `return` statement can be specified, or the **return** statement of a function can be omitted altogether. In both of these cases, *the function will return the `None` object*. +In general, any Python object can follow a function's `return` statement. Furthermore, an **empty** `return` statement can be specified, or the **return** statement of a function can be omitted altogether. In both of these cases, *the function will return the* `None` *object*. ```python # this function returns `None` @@ -244,7 +244,7 @@ This should be used sparingly, for exceedingly simple functions that can be easi ## Arguments -A sequence of comma-separated variable names can specified in the function signature to indicated *positional* arguments for the function. For example, the following specifies `x`, `lower`, and `upper` as input arguments to a function, `is_bounded`: +A sequence of comma-separated variable names can be specified in the function signature to indicated *positional* arguments for the function. For example, the following specifies `x`, `lower`, and `upper` as input arguments to a function, `is_bounded`: ```python def is_bounded(x, lower, upper): diff --git a/Python/Module2_EssentialsOfPython/Generators_and_Comprehensions.md b/Python/Module2_EssentialsOfPython/Generators_and_Comprehensions.md index 3f6b9a2d..d18a4dfa 100644 --- a/Python/Module2_EssentialsOfPython/Generators_and_Comprehensions.md +++ b/Python/Module2_EssentialsOfPython/Generators_and_Comprehensions.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -544,12 +544,12 @@ Use a tuple-comprehension to extract comma-separated numbers from a string, conv Replicate the functionality of the the following code by writing a list comprehension. ```python # skip all non-lowercased letters (including punctuation) -# append 1 if lowercase letter is "o" +# append 1 if lowercase letter is equal to "o" # append 0 if lowercase letter is not "o" out = [] for i in "Hello. How Are You?": if i.islower(): - out.append(1 if i is "o" else 0) + out.append(1 if i == "o" else 0) ``` @@ -653,7 +653,7 @@ or **Translating a For-Loop: Solution** ```python ->>> out = [(1 if i is "o" else 0) for i in "Hello. How Are You?" if i.islower()] +>>> out = [(1 if i == "o" else 0) for i in "Hello. How Are You?" if i.islower()] >>> out [0, 0, 0, 1, 1, 0, 0, 0, 1, 0] ``` diff --git a/Python/Module2_EssentialsOfPython/Introduction.md b/Python/Module2_EssentialsOfPython/Introduction.md index 7f48f672..98e40d26 100644 --- a/Python/Module2_EssentialsOfPython/Introduction.md +++ b/Python/Module2_EssentialsOfPython/Introduction.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/Iterables.md b/Python/Module2_EssentialsOfPython/Iterables.md index 2a53dcd7..ce3e4fdc 100644 --- a/Python/Module2_EssentialsOfPython/Iterables.md +++ b/Python/Module2_EssentialsOfPython/Iterables.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/Itertools.md b/Python/Module2_EssentialsOfPython/Itertools.md index c4efa8f4..05febea0 100644 --- a/Python/Module2_EssentialsOfPython/Itertools.md +++ b/Python/Module2_EssentialsOfPython/Itertools.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/Problems/DifferenceFanout.md b/Python/Module2_EssentialsOfPython/Problems/DifferenceFanout.md index 6bebd45f..a362d832 100644 --- a/Python/Module2_EssentialsOfPython/Problems/DifferenceFanout.md +++ b/Python/Module2_EssentialsOfPython/Problems/DifferenceFanout.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/Problems/EncodeAsString.md b/Python/Module2_EssentialsOfPython/Problems/EncodeAsString.md index 1b90cf5a..a7b63234 100644 --- a/Python/Module2_EssentialsOfPython/Problems/EncodeAsString.md +++ b/Python/Module2_EssentialsOfPython/Problems/EncodeAsString.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/Problems/MarginPercentage.md b/Python/Module2_EssentialsOfPython/Problems/MarginPercentage.md index ddce8aeb..1d7f7f91 100644 --- a/Python/Module2_EssentialsOfPython/Problems/MarginPercentage.md +++ b/Python/Module2_EssentialsOfPython/Problems/MarginPercentage.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/Problems/MergeMaxDicts.md b/Python/Module2_EssentialsOfPython/Problems/MergeMaxDicts.md index 95f9be13..096d983c 100644 --- a/Python/Module2_EssentialsOfPython/Problems/MergeMaxDicts.md +++ b/Python/Module2_EssentialsOfPython/Problems/MergeMaxDicts.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/Problems/Palindrome.md b/Python/Module2_EssentialsOfPython/Problems/Palindrome.md index 098fa12b..3f9bd182 100644 --- a/Python/Module2_EssentialsOfPython/Problems/Palindrome.md +++ b/Python/Module2_EssentialsOfPython/Problems/Palindrome.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/Scope.md b/Python/Module2_EssentialsOfPython/Scope.md index 15b6b594..afc6f8d8 100644 --- a/Python/Module2_EssentialsOfPython/Scope.md +++ b/Python/Module2_EssentialsOfPython/Scope.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module2_EssentialsOfPython/SequenceTypes.md b/Python/Module2_EssentialsOfPython/SequenceTypes.md index 2ada1cdd..1e8a1149 100644 --- a/Python/Module2_EssentialsOfPython/SequenceTypes.md +++ b/Python/Module2_EssentialsOfPython/SequenceTypes.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -320,7 +320,7 @@ The basic syntax for slicing is: `seq[start:stop:step]`, using colons to separat >>> seq[1:4:1] 'bcd' -# start:1, stop:5, step:2 +# start:0, stop:5, step:2 >>> seq[0:5:2] # get every other entry within [start, stop) 'ace' diff --git a/Python/Module2_EssentialsOfPython/Variables_and_Assignment.md b/Python/Module2_EssentialsOfPython/Variables_and_Assignment.md index 0869b676..0e9c5fc3 100644 --- a/Python/Module2_EssentialsOfPython/Variables_and_Assignment.md +++ b/Python/Module2_EssentialsOfPython/Variables_and_Assignment.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.md b/Python/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.md index af775e97..79c5e8f3 100644 --- a/Python/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.md +++ b/Python/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module3_IntroducingNumpy/AdvancedIndexing.md b/Python/Module3_IntroducingNumpy/AdvancedIndexing.md index 64df9ccc..2dcb7a2f 100644 --- a/Python/Module3_IntroducingNumpy/AdvancedIndexing.md +++ b/Python/Module3_IntroducingNumpy/AdvancedIndexing.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module3_IntroducingNumpy/ArrayTraversal.md b/Python/Module3_IntroducingNumpy/ArrayTraversal.md index 98c255a4..d7979257 100644 --- a/Python/Module3_IntroducingNumpy/ArrayTraversal.md +++ b/Python/Module3_IntroducingNumpy/ArrayTraversal.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module3_IntroducingNumpy/BasicArrayAttributes.md b/Python/Module3_IntroducingNumpy/BasicArrayAttributes.md index 8cd241a3..30f1130b 100644 --- a/Python/Module3_IntroducingNumpy/BasicArrayAttributes.md +++ b/Python/Module3_IntroducingNumpy/BasicArrayAttributes.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module3_IntroducingNumpy/BasicIndexing.md b/Python/Module3_IntroducingNumpy/BasicIndexing.md index 74a6fde4..12fe7a0d 100644 --- a/Python/Module3_IntroducingNumpy/BasicIndexing.md +++ b/Python/Module3_IntroducingNumpy/BasicIndexing.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -202,18 +202,16 @@ Basic indexing is triggered whenever a tuple of: integer, `slice`, `numpy.newaxi
- - + **Reading Comprehension: Ellipsis** Given a $N$-dimensional array, `x`, index into `x` such that you access entry-0 of axis-0, the last entry of axis-$N-1$, slicing along all intermediate dimensions. $N$ is at least $2$.
- -
- +
+ **Reading Comprehension: Basic Indexing** Given a shape-(4, 3) array, @@ -291,9 +289,9 @@ False Thus updating a variable `subarray` via `subarray = subarray + 2` does *not* overwrite the original data referenced by `subarray`. Rather, `subarray + 2` assigns that new array to the variable `subarray`. NumPy does provide mechanisms for performing mathematical operations to directly update the underlying data of an array without having to create a distinct array. We will discuss these mechanisms in the next subsection. -
- +
+ **Reading Comprehension: Views** Given, diff --git a/Python/Module3_IntroducingNumpy/Broadcasting.md b/Python/Module3_IntroducingNumpy/Broadcasting.md index 0f8c47d1..c11e0503 100644 --- a/Python/Module3_IntroducingNumpy/Broadcasting.md +++ b/Python/Module3_IntroducingNumpy/Broadcasting.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -486,16 +486,16 @@ Performing this computation using for-loops proceeds as follows: def pairwise_dists_looped(x, y): """ Computing pairwise distances using for-loops - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" # `dists[i, j]` will store the Euclidean # distance between `x[i]` and `y[j]` dists = np.empty((5, 6)) @@ -514,6 +514,16 @@ def pairwise_dists_looped(x, y): ``` Be sure to step through this code and see that `dists` stores each pair of Euclidean distances between the rows of `x` and `y`. + +```python +# produces a shape-(5, 6) result +>>> pairwise_dists_looped(x, y) +array([[ 3.678 , 8.4524, 10.3057, 7.3711, 6.2152, 5.5548], + [10.1457, 5.8793, 2.9274, 4.1114, 3.9098, 5.2259], + [ 7.3219, 0.8439, 6.8734, 4.5687, 7.3283, 4.8216], + [10.339 , 7.032 , 7.4745, 7.0633, 3.5999, 4.0107], + [ 8.2878, 3.5468, 6.336 , 4.9014, 4.1858, 2.0257]]) +``` @@ -545,26 +555,34 @@ Voilà! We have produced the distances in a vectorized way. Let's write this out def pairwise_dists_crude(x, y): """ Computing pairwise distances using vectorization. - This method uses memory-inefficient broadcasting. - - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) - - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + This method uses memory-inefficient broadcasting. + + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) + + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" # The use of `np.newaxis` here is equivalent to our # use of the `reshape` function return np.sqrt(np.sum((x[:, np.newaxis] - y[np.newaxis])**2, axis=2)) ``` - +```python +# produces a shape-(5, 6) result +>>> pairwise_dists_crude(x, y) +array([[ 3.678 , 8.4524, 10.3057, 7.3711, 6.2152, 5.5548], + [10.1457, 5.8793, 2.9274, 4.1114, 3.9098, 5.2259], + [ 7.3219, 0.8439, 6.8734, 4.5687, 7.3283, 4.8216], + [10.339 , 7.032 , 7.4745, 7.0633, 3.5999, 4.0107], + [ 8.2878, 3.5468, 6.336 , 4.9014, 4.1858, 2.0257]]) +``` Regrettably, there is a glaring issue with the vectorized computation that we just performed. Consider the largest sized array that is created in the for-loop computation, compared to that of this vectorized computation. The for-loop version need only create a shape-$(M, N)$ array, whereas the vectorized computation creates an intermediate array (i.e. `diffs`) of shape-$(M, N, D)$. This intermediate array is even created in the one-line version of the code. This will create a massive array if $D$ is a large number! -Suppose, for instance, that you are finding the Euclidean between pairs of RGB images that each have a resolution of $32 \times 32$ (in order to see if the images resemble one another). Thus in this scenario, each image is comprised of $D = 32 \times 32 \times 3 = 3072$ numbers ($32^2$ pixels, and each pixel has 3 values: a red, blue, and green-color value). Computing all the distances between a stack of 5000 images with a stack of 100 images would form an intermediate array of shape-$(5000, 100, 3072)$. Even though this large array only exists temporarily, it would have to consume over 6GB of RAM! The for-loop version requires $\frac{1}{3027}$ as much memory (about 2MB). +Suppose, for instance, that you are finding the Euclidean between pairs of RGB images that each have a resolution of $32 \times 32$ (in order to see if the images resemble one another). Thus in this scenario, each image is comprised of $D = 32 \times 32 \times 3 = 3072$ numbers ($32^2$ pixels, and each pixel has 3 values: a red, blue, and green-color value). Computing all the distances between a stack of 5000 images with a stack of 100 images would form an intermediate array of shape-$(5000, 100, 3072)$. Even though this large array only exists temporarily, it would have to consume over 6GB of RAM! The for-loop version requires $\frac{1}{3072}$ as much memory (about 2MB). Is our goose cooked? Are we doomed to pick between either slow for-loops, or a memory-inefficient use of vectorization? No! We can refactor the mathematical form of the Euclidean distance in order to avoid the creation of that bloated intermediate array. @@ -611,7 +629,7 @@ Thus the third term in our equation, $-2\sum_{i=0}^{D-1}{x_{i} y_{i}}$, for all ```python # computing the third term in the distance # equation, for all pairs of rows ->>> x_y_prod = -2 * np.matmul(x, y.T) # `np.dot` can also be used to the same effect +>>> x_y_prod = 2 * np.matmul(x, y.T) # `np.dot` can also be used to the same effect >>> x_y_prod.shape (5, 6) ``` @@ -620,34 +638,106 @@ Having accounted for all three terms, we can finally compute the Euclidean dista ```python # computing all the distances ->>> dists = np.sqrt(x_y_sqrd + x_y_prod) +>>> dists = np.sqrt(x_y_sqrd - x_y_prod) >>> dists.shape (5, 6) ``` -In total, we have successfully used vectorization to compute the all pairs of distances, while only requiring an array of shape-$(M, N)$ to do so! This is the memory-efficient, vectorized form - the stuff that dreams are made of. Let's write the function that performs this computation in full. + +#### A Subtle Issue with Floating-point Precision + +There is one more important and very subtle detail that we have to deal with. +In terms of pure mathematics, `x_y_sqrd - x_y_prod` must be a strictly non-negative value (i.e. its smallest possible value is $0$), since it is equivalent to + +\begin{equation} +\sum_{i=0}^{D-1}{(x_{i} - y_{i})^2} +\end{equation} + +That being said, are working with floating-point numbers, which do not always behave exactly like rational numbers when we do arithmetic with them. +Indeed, we saw earlier that the [quirks of floating-point arithmetic](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Understanding-Numerical-Precision) can lead to surprising results. +Here, the strange behavior is that `x_y_sqrd - x_y_prod` **can produce negative numbers**! + +Let's see this in action. +We'll take the following shape-(2, 3) array ```python -def pairwise_dists(x, y): - """ Computing pairwise distances using memory-efficient - vectorization. +# A carefully-selected input that will trigger surprising +# floating-point precision issues in our distance calculation +>>> x = np.array([[4.700867387959219, 4.700867387959219, 4.700867387959219], +... [4.700867387959219, 4.700867387959219, 4.700867387959219]]) +``` - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) +And compute the square distance between all combinations of rows `x`; the result should simply be a shape-(2, 2) array of zeros. - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" - dists = -2 * np.matmul(x, y.T) - dists += np.sum(x**2, axis=1)[:, np.newaxis] - dists += np.sum(y**2, axis=1) - return np.sqrt(dists) +```python +# The square-distances should be exactly zero, but they +# will instead be (*very* small) negative numbers! +>>> sqr_dists = -2 * np.matmul(x, x.T) # `x_x_prod` +>>> sqr_dists += np.sum(x**2, axis=1)[:, np.newaxis] +>>> sqr_dists += np.sum(x**2, axis=1) +>>> sqr_dists +array([[-2.842170943040401e-14, -2.842170943040401e-14], + [-2.842170943040401e-14, -2.842170943040401e-14]]) ``` +These values are *very* close to being zero, so it is not as if the magnitude of our result is wildly off, but the critical issue here is that the quirks of floating-point arithmetic produced (very small) negative numbers. +We are going to be in for a rude awakening when we take the square-root of these values to get our final distances: +```python +# Taking the square-root of negative floats will produce NaNs +>>> np.sqrt(sqr_dists) +array([[nan, nan], + [nan, nan]]) +``` + +`nan` stands for "Not a Number", which is to say that the square-root of a negative number cannot produce a real-valued float (the result will be an [imaginary number](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Complex-Numbers), but NumPy will not swap out real numbers for imaginary ones unless we explicitly permit it to). + +The solution to this problem comes from the realization that this occurrence is truly an edge-case, and that it will only manifest when the result *ought* to have been zero and indeed is very close to zero. +Thus we can [clip](https://numpy.org/doc/stable/reference/generated/numpy.clip.html) `sqr_dists` such that any value that falls below zero gets set to zero and all other values will be left alone: + +```python +# "Clipping" all negative entries so that they are set to 0 +>>> np.sqrt(np.clip(sqr_dists, a_min=0, a_max=None)) +array([[0., 0.], + [0., 0.]]) +``` + + + +#### The Final Answer, At Last! + +In total, we have successfully used vectorization to compute all the pairs of distances, while only requiring an array of shape-$(M, N)$ to do so! This is the memory-efficient, vectorized form – the stuff that dreams are made of. +Let's write the function that performs this computation in full. + +```python +def pairwise_dists(x, y): + """ Computing pairwise distances using memory-efficient + vectorization. + + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) + + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" + sqr_dists = -2 * np.matmul(x, y.T) + sqr_dists += np.sum(x**2, axis=1)[:, np.newaxis] + sqr_dists += np.sum(y**2, axis=1) + return np.sqrt(np.clip(sqr_dists, a_min=0, a_max=None)) +``` + +```python +# produces a shape-(5, 6) result +>>> pairwise_dists(x, y) +array([[ 3.678 , 8.4524, 10.3057, 7.3711, 6.2152, 5.5548], + [10.1457, 5.8793, 2.9274, 4.1114, 3.9098, 5.2259], + [ 7.3219, 0.8439, 6.8734, 4.5687, 7.3283, 4.8216], + [10.339 , 7.032 , 7.4745, 7.0633, 3.5999, 4.0107], + [ 8.2878, 3.5468, 6.336 , 4.9014, 4.1858, 2.0257]]) +```
@@ -676,7 +766,7 @@ Use the function [numpy.allclose](https://numpy.org/doc/stable/reference/generat ## Reading Comprehension Solutions - + **Broadcast Compatibility: Solution** 1\. Incompatible @@ -688,7 +778,6 @@ Use the function [numpy.allclose](https://numpy.org/doc/stable/reference/generat 4\. `9 x 2 x 5` 5\. Incompatible - **Basic Broadcasting: Solution** diff --git a/Python/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.md b/Python/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.md index 84669d4d..2ef6f05d 100644 --- a/Python/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.md +++ b/Python/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module3_IntroducingNumpy/IntroducingTheNDarray.md b/Python/Module3_IntroducingNumpy/IntroducingTheNDarray.md index 17a3d192..b91339cb 100644 --- a/Python/Module3_IntroducingNumpy/IntroducingTheNDarray.md +++ b/Python/Module3_IntroducingNumpy/IntroducingTheNDarray.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module3_IntroducingNumpy/Problems/ComputeAccuracy.md b/Python/Module3_IntroducingNumpy/Problems/ComputeAccuracy.md index 17833303..451d91c4 100644 --- a/Python/Module3_IntroducingNumpy/Problems/ComputeAccuracy.md +++ b/Python/Module3_IntroducingNumpy/Problems/ComputeAccuracy.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module3_IntroducingNumpy/VectorizedOperations.md b/Python/Module3_IntroducingNumpy/VectorizedOperations.md index 8edd973e..f6edddb7 100644 --- a/Python/Module3_IntroducingNumpy/VectorizedOperations.md +++ b/Python/Module3_IntroducingNumpy/VectorizedOperations.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module4_OOP/Applications_of_OOP.md b/Python/Module4_OOP/Applications_of_OOP.md index fe93d859..00399112 100644 --- a/Python/Module4_OOP/Applications_of_OOP.md +++ b/Python/Module4_OOP/Applications_of_OOP.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -73,7 +73,7 @@ class ShoppingList: items = [items] # only mark items as purchased that are on our list to begin with self._purchased.update(set(items) & self._needed) - # remove all purchased items from out unpurchased set + # remove all purchased items from our unpurchased set self._needed.difference_update(self._purchased) def list_purchased_items(self): diff --git a/Python/Module4_OOP/Brief_Review.md b/Python/Module4_OOP/Brief_Review.md index 29d35c97..96fd1a64 100644 --- a/Python/Module4_OOP/Brief_Review.md +++ b/Python/Module4_OOP/Brief_Review.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module4_OOP/ClassDefinition.md b/Python/Module4_OOP/ClassDefinition.md index 6419727b..ffcd8683 100644 --- a/Python/Module4_OOP/ClassDefinition.md +++ b/Python/Module4_OOP/ClassDefinition.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module4_OOP/ClassInstances.md b/Python/Module4_OOP/ClassInstances.md index 7d5cc65c..30da5961 100644 --- a/Python/Module4_OOP/ClassInstances.md +++ b/Python/Module4_OOP/ClassInstances.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module4_OOP/Inheritance.md b/Python/Module4_OOP/Inheritance.md index 95114973..1e47a4e1 100644 --- a/Python/Module4_OOP/Inheritance.md +++ b/Python/Module4_OOP/Inheritance.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module4_OOP/Introduction_to_OOP.md b/Python/Module4_OOP/Introduction_to_OOP.md index e061c9c9..25c0ebe9 100644 --- a/Python/Module4_OOP/Introduction_to_OOP.md +++ b/Python/Module4_OOP/Introduction_to_OOP.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module4_OOP/Methods.md b/Python/Module4_OOP/Methods.md index 6bf8e4fc..7bb440e8 100644 --- a/Python/Module4_OOP/Methods.md +++ b/Python/Module4_OOP/Methods.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module4_OOP/ObjectOrientedProgramming.md b/Python/Module4_OOP/ObjectOrientedProgramming.md index 8c5802a6..f4de8d27 100644 --- a/Python/Module4_OOP/ObjectOrientedProgramming.md +++ b/Python/Module4_OOP/ObjectOrientedProgramming.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module4_OOP/Special_Methods.md b/Python/Module4_OOP/Special_Methods.md index 45a91811..a9477dcf 100644 --- a/Python/Module4_OOP/Special_Methods.md +++ b/Python/Module4_OOP/Special_Methods.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module5_OddsAndEnds/Modules_and_Packages.md b/Python/Module5_OddsAndEnds/Modules_and_Packages.md index 3324669e..30b52e27 100644 --- a/Python/Module5_OddsAndEnds/Modules_and_Packages.md +++ b/Python/Module5_OddsAndEnds/Modules_and_Packages.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python diff --git a/Python/Module5_OddsAndEnds/WorkingWithFiles.md b/Python/Module5_OddsAndEnds/WorkingWithFiles.md index d68d8f27..f33c737e 100644 --- a/Python/Module5_OddsAndEnds/WorkingWithFiles.md +++ b/Python/Module5_OddsAndEnds/WorkingWithFiles.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python @@ -254,7 +254,7 @@ with open("a_poem.txt", mode="r") as my_open_file: There are many cases in which we may want to construct a list of files to iterate over. For example, if we have several data files, it would be useful to create a file list which we can iterate through and process in sequence. One way to do this would be to manually construct such a list of files: -``` python +```python my_files = ['data/file1.txt', 'data/file2.txt', 'data/file3.txt', 'data/file4.txt'] ``` diff --git a/Python/Module5_OddsAndEnds/Writing_Good_Code.md b/Python/Module5_OddsAndEnds/Writing_Good_Code.md index 1fb91532..3cebc424 100644 --- a/Python/Module5_OddsAndEnds/Writing_Good_Code.md +++ b/Python/Module5_OddsAndEnds/Writing_Good_Code.md @@ -5,14 +5,13 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.9.1 kernelspec: display_name: Python 3 language: python name: python3 --- - .. meta:: :description: Topic: Writing good code, Difficulty: Easy, Category: Section @@ -440,7 +439,36 @@ This saves us the trouble of having to run our code, hit an error, read through It does not take long to experience the benefits of type-hinting through your IDE. This both accelerates your coding by informing you of the object types that you are working with on the fly, and helps to expose oversights in your code as soon as they are made. -Finally, it is also worthwhile to highlight two projects, [mypy](http://mypy-lang.org/) and [pyright](https://github.com/microsoft/pyright), which are used to perform static type-checking on your code based on your type-hints. That is, mypy and pyright will both automatically traverse your code and find potential bugs by identifying type conflicts in your code (e.g. trying to capitalize an integer) by checking their annotated and inferred types. These tools are especially useful for large-scale code bases. Companies like Dropbox and Microsoft make keen use of static type-checking to identify inconsistencies in their code without having to hit runtime errors. Keep mypy, pyright, and other type-checking utilities in mind as you mature as a Python developer and find yourself working on projects of growing complexity. If you are using [VSCode as your IDE](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html), you can install the [pyright vscode extension](https://marketplace.visualstudio.com/items?itemName=ms-pyright.pyright) to leverage type checking within your IDE. +Finally, it is also worthwhile to highlight two projects, [mypy](http://mypy-lang.org/) and [pyright](https://github.com/microsoft/pyright), which are used to perform static type-checking on your code based on your type-hints. +That is, mypy and pyright will both automatically traverse your code and find potential bugs by identifying type conflicts in your code (e.g. trying to capitalize an integer) by checking their annotated and inferred types. +These tools are especially useful for large-scale code bases. Companies like Dropbox and Microsoft make keen use of static type-checking to identify inconsistencies in their code without having to hit runtime errors. Keep mypy, pyright, and other type-checking utilities in mind as you mature as a Python developer and find yourself working on projects of growing complexity. +If you are using [VSCode as your IDE](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html), you can install the [PyLance VSCode extension](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) to leverage pyright's type checking within your IDE. + + + +
+ +**Reading Comprehension: Type-Assisted Code Completion** + +The `jedi` package, which is installed by default alongside Jupyter and IPython, enables type-informed code completion. +This means that we can benefit from type-hints even when we are working in a Jupyter notebook! + +In a Jupyter notebook, write the following type-annotated signature for a function: `def f(x: str):`. +Now in the body of the function (i.e. on the next line, and indented inwards), try typing `x.` and then hit ``. + +```python + +def f(x: str): + x.#hit here + +``` + +You should see a list of methods appear for `x`. +What are the first three methods that appear? +Do these make sense based on the annotation associated with `x`? +Now change the annotation for `x` to be `list` and trigger the auto-completion in the editor again; do you see an updated list of methods? + +
@@ -959,8 +987,17 @@ Take some time to review the NumPy and Google docstring specifications, pick one ## Reading Comprehension Solutions + +**Type-Assisted Code Completion: Solution** + +The tab-completion reveals methods like "capitalize", "casefold", and "center" – all of which are string methods. +These are made available despite the fact that `x` did not yet refer to a specific string. +Instead, the type-hint was able to tell the editor that `x` _will_ refer to a string, and this was enough to inform these type completions. + +Revising the type-annotation for `x` to be `list` affects the auto-completion options accordingly: the editor will now suggest list methods like "append", "clear", and "copy". + -**Type Hinting: Solutions** +**Type Hinting: Solution** The following is a well-annotated version of `get_first_and_last`: diff --git a/Python/changes.rst b/Python/changes.rst index 24dd88f0..a5bf2207 100644 --- a/Python/changes.rst +++ b/Python/changes.rst @@ -3,8 +3,69 @@ Changelog ========= This is a record of all past PLYMI releases and what went into them, -in reverse chronological order. All previous releases should still be available -on pip. +in reverse chronological order. + +---------- +2021-02-28 +---------- + +Fixes a syntax error (missing colons) in a code snippet in `a subsection about conditional expressions `_. + + +---------- +2021-01-31 +---------- + +Upgrades the tools used to build PLYMI: + +- sphinx 3.4.3 +- nbsphinx 0.8.1 +- jupytext 1.9.1 +- sphinx-rtd-theme 0.5.1 + +Adds a reading comprehension problem in `the section on type-hinting `_ +to show that ``jedi`` provides annotation-informed autocompletion abilities in notebooks. + + +---------- +2021-01-30 +---------- + +Updated the discussion of `computing pairwise differences `_ +to account for potential floating-point edge cases that can produce "NaNs" as a result. + +There is currently an incompatibility between ``jedi 0.18.0`` and IPython, which breaks autocompletion. See `here `_ for more details. +Added temporary callout boxes to the `informal introduction to Python `_ and to +the `introduction to Jupyter notebooks `_, which instruct readers to remedy this by downgrading jedi. + +Fixed a missing plot in the `introduction to Jupyter `_ section. + +Reformatted the `section on IDEs `_ and added a description of PyLance. + +Add link to `PLYMI's discussion board `_. + +---------- +2021-01-24 +---------- + +Added a brief `discussion of Python versions `_. Thanks `@samaocarpenter `_! + +Fixed typos `#160 `_ `#158 `_ +`#155 `_ + + +---------- +2020-06-17 +---------- + +Various typo fixes. Thanks to Darshan and David! + + +---------- +2020-05-10 +---------- + +Various typo fixes. Thanks to Patrick O'Shea and David Mascharka! ---------- diff --git a/Python/conf.py b/Python/conf.py index 34bd820e..8cdd5180 100644 --- a/Python/conf.py +++ b/Python/conf.py @@ -59,7 +59,7 @@ # General information about the project. project = "Python Like You Mean It" -copyright = "2019, Ryan Soklaski" +copyright = "2021, Ryan Soklaski" author = "Ryan Soklaski" html_title = "Python Like You Mean It" diff --git a/Python/index.rst b/Python/index.rst index 1cb6cfab..d2e400d2 100644 --- a/Python/index.rst +++ b/Python/index.rst @@ -1,3 +1,7 @@ +.. meta:: + :description: Topic: Top page of Python Like You Mean It, Difficulty: Easy, Category: Introduction + :keywords: PLYMI, Python Like You Mean It, tutorial, python for machine learning, python for deep learning, python for data science, numpy, python from scratch, basic python tutorial, teaching python + ======================= Python Like You Mean It ======================= @@ -12,7 +16,8 @@ What this is ------------ Python Like You Mean It (PLYMI) is a free resource for learning the basics of Python & NumPy, and moreover, becoming a competent Python user. The features of the Python language that are emphasized here were chosen to help those who are particularly interested in STEM applications (data analysis, machine learning, numerical work, etc.). -I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.8, as of writing this). +I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.9, as of writing this). +This material has proven to be fruitful for high school and college teachers alike to teach Python as part of their STEM curriculum. What this isn't @@ -32,10 +37,18 @@ Python shouldn't be *too* easy Python is a relatively easy language to pick up, and it doesn't require much rigor to make code work. Unfortunately, this means that there are many Python users out there who know enough to just get by, but lack a sound understanding of the language. You don't want to get caught in the "know enough Python to be dangerous" zone; therein lies complacency, stagnation, and the genesis of a lot of bad code. You've got to Python like you mean it! +Join Our Discussion Board +------------------------- +`Join the PLYMI community `_ to ask questions, recommend new content, or to just say hello! + +(A note to `BWSI students `_: please stick to your class' piazza board for posting questions) + + PLYMI is on GitHub ------------------ If you have questions about the reading, think that you have spotted some mistakes, or would like to contribute to PLYMI, please visit `our GitHub page `_. You will need to create a GitHub account in order to post an issue; this process is free and easy. We would love for you to join us to discuss the website! + Contributors ------------ The following people made significant contributions to PLYMI, adding problems with worked solutions and valuable feedback on the text: @@ -44,13 +57,13 @@ The following people made significant contributions to PLYMI, adding problems wi - AJ Federici (GitHub:`@Federici `_) - Annabelle Lew (GitHub:`@AnnabelleLew `_) - Petar Griggs (GitHub:`@petarmhg `_) -- Sam Carpenter (GitHub:`@HardBoiled800 `_) +- Sam Carpenter (GitHub:`@samaocarpenter `_) - Patrick O'Shea (GitHub:`@ArtichokeSap `_) About Me -------- -I started learning to use Python in graduate school for my physics research, and I was *so* bad at using it. Fortunately, one of my labmates was more experienced and had the good sense to tell me that my code and work flow was terrible. He pointed me to tooling, style guides, and documentation pages so that I could improve (I'd like to think that this resource would have been a huge help to me back then). I've been coding in Python for at least six years now, and I've taken to following the language, along with its new features and changes, quite closely. Currently I do machine learning research, and have served as a core developer for a machine learning library. I also love to teach, so this has been a fun project for me to take on! +I started learning to use Python in graduate school for my physics research, and I was *so* bad at using it. Fortunately, one of my labmates was more experienced and had the good sense to tell me that my code and work flow was terrible. He pointed me to tooling, style guides, and documentation pages so that I could improve (I'd like to think that this resource would have been a huge help to me back then). I've been coding in Python for at least eight years now, and I've taken to following the language, along with its new features and changes, quite closely. Currently I do machine learning research, and have served as a core developer for a machine learning library. I also love to teach, so this has been a fun project for me to take on! .. toctree:: diff --git a/Python/intro.rst b/Python/intro.rst index 97d3801e..1d822383 100644 --- a/Python/intro.rst +++ b/Python/intro.rst @@ -1,3 +1,7 @@ +.. meta:: + :description: Topic: Top page of Python Like You Mean It, Difficulty: Easy, Category: Introduction + :keywords: PLYMI, Python Like You Mean It, tutorial, python for machine learning, python for deep learning, python for data science, numpy, python from scratch, basic python tutorial, teaching python + ======================= Python Like You Mean It ======================= @@ -12,7 +16,8 @@ What this is ------------ Python Like You Mean It (PLYMI) is a free resource for learning the basics of Python & NumPy, and moreover, becoming a competent Python user. The features of the Python language that are emphasized here were chosen to help those who are particularly interested in STEM applications (data analysis, machine learning, numerical work, etc.). -I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.8, as of writing this). +I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.9, as of writing this). +This material has proven to be fruitful for high school and college teachers alike to teach Python as part of their STEM curriculum. What this isn't @@ -31,6 +36,12 @@ Python shouldn't be *too* easy ------------------------------ Python is a relatively easy language to pick up, and it doesn't require much rigor to make code work. Unfortunately, this means that there are many Python users out there who know enough to just get by, but lack a sound understanding of the language. You don't want to get caught in the "know enough Python to be dangerous" zone; therein lies complacency, stagnation, and the genesis of a lot of bad code. You've got to Python like you mean it! +Join Our Discussion Board +------------------------- +`Join the PLYMI community `_ to ask questions, recommend new content, or to just say hello! + +(A note to `BWSI students `_: please stick to your class' piazza board for posting questions) + PLYMI is on GitHub ------------------ @@ -44,10 +55,10 @@ The following people made significant contributions to PLYMI, adding problems wi - AJ Federici (GitHub:`@Federici `_) - Annabelle Lew (GitHub:`@AnnabelleLew `_) - Petar Griggs (GitHub:`@petarmhg `_) -- Sam Carpenter (GitHub:`@HardBoiled800 `_) +- Sam Carpenter (GitHub:`@samaocarpenter `_) - Patrick O'Shea (GitHub:`@ArtichokeSap `_) About Me -------- -I started learning to use Python in graduate school for my physics research, and I was *so* bad at using it. Fortunately, one of my labmates was more experienced and had the good sense to tell me that my code and work flow was terrible. He pointed me to tooling, style guides, and documentation pages so that I could improve (I'd like to think that this resource would have been a huge help to me back then). I've been coding in Python for at least six years now, and I've taken to following the language, along with its new features and changes, quite closely. Currently I do machine learning research, and have served as a core developer for a machine learning library. I also love to teach, so this has been a fun project for me to take on! +I started learning to use Python in graduate school for my physics research, and I was *so* bad at using it. Fortunately, one of my labmates was more experienced and had the good sense to tell me that my code and work flow was terrible. He pointed me to tooling, style guides, and documentation pages so that I could improve (I'd like to think that this resource would have been a huge help to me back then). I've been coding in Python for at least eight years now, and I've taken to following the language, along with its new features and changes, quite closely. Currently I do machine learning research, and have served as a core developer for a machine learning library. I also love to teach, so this has been a fun project for me to take on! diff --git a/Python/module_4.rst b/Python/module_4.rst index 021a2c97..0251813f 100644 --- a/Python/module_4.rst +++ b/Python/module_4.rst @@ -2,7 +2,7 @@ Module 4: Object Oriented Programming ===================================== In this module, we will come to see that Python is an object-oriented language. That is, the language is all about defining different types of objects that encapsulate data, and that possess functions that permit users to access and manipulate this data. Our tour through `the essentials of Python `_ and `the essentials of NumPy `_ brought us into contact with various types of objects, such as the :code:`int`, :code:`str`, :code:`list`, :code:`tuple`, :code:`dict`, and the :code:`numpy.ndarray`, to name a few. We have seen that these different types of objects have starkly different functionality from one another. We will study the syntax and constructs for creating and interacting with objects in Python. Ultimately, will find our skill sets as Python-users much fuller and more sophisticated having understood object-oriented programming in Python. -We being this module by establishing some key terminology for discussing object-oriented programming, drawing attention to the important fact that the terms 'class' and 'type' mean the same thing in modern Python. Next, we study the syntax for defining a class, and take time to distinguish between the resulting class object and the subsequent class instances that can then be created. Having defined our first custom class of object, we then study the syntax for defining class-methods, which permits us add customized functionality to our class. Further, we will introduce ourselves to Python's reserved special methods, which empower us to fully interface our class with the Python's protocols for behaving like a sequence, an iterable, a function, etc. We conclude this module with a brief discussion of the concept of inheritance, which is a mechanism by which a new class can inherit attributes from an existing class. +We begin this module by establishing some key terminology for discussing object-oriented programming, drawing attention to the important fact that the terms 'class' and 'type' mean the same thing in modern Python. Next, we study the syntax for defining a class, and take time to distinguish between the resulting class object and the subsequent class instances that can then be created. Having defined our first custom class of object, we then study the syntax for defining class-methods, which permits us to add customized functionality to our class. Further, we will introduce ourselves to Python's reserved special methods, which empower us to fully interface our class with Python's protocols for behaving like a sequence, an iterable, a function, etc. We conclude this module with a brief discussion of the concept of inheritance, which is a mechanism by which a new class can inherit attributes from an existing class. .. toctree:: :maxdepth: 2 diff --git a/README.md b/README.md index d1929075..bd686732 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Contributions to this project are very welcome! I will be sure to credit any/al - create lengthier standalone problems to serve as holistic examples of how to apply the concepts presented in the reading - recommend new sections to be added to PLYMI -You can either open an issue to provide feedback or point out errors, or you can create a [pull request](https://help.github.com/articles/creating-a-pull-request/)) if you want to submit new/modified materials. The other maintainers of PLYMI and I are happy to help you refine your issues and PRs, so please do not be discouraged if you are new to Git/GitHub. +You can either open an issue to provide feedback or point out errors, or you can create a [pull request](https://help.github.com/articles/creating-a-pull-request/) if you want to submit new/modified materials. The other maintainers of PLYMI and I are happy to help you refine your issues and PRs, so please do not be discouraged if you are new to Git/GitHub. I have posted a number of "To-Do" tasks in this project's [issues](https://github.com/rsokl/Learning_Python/issues) page, and I will be adding to these as this project progresses. Included are requests for proofreading and exercises. Please post within an issue if you are working on a to-do item, so multiple people don't end up working on the same task. General feedback on content is also hugely valuable, so feel free to open a new issue to provide your feedback on any of the material. @@ -22,28 +22,45 @@ I have posted a number of "To-Do" tasks in this project's [issues](https://githu ### Making a Pull Request If you want to submit a change to some of the content (e.g. correcting typos), do the following: -1. Clone this repository +1. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) this repository 2. Create a new branch, appropriately named for whatever task you are performing: `git checkout -b your_branch_name` 3. In your new branch, make the relevant changes and commit them. -4. Push your branch: `git push origin your_branch_name` (you should have permission to do this, if you are added as a "contributor" to this project) -5. Create a [Pull Request](https://help.github.com/articles/creating-a-pull-request/) from your branch into the master branch. +4. Push your branch to your fork: `git push origin your_branch_name` +5. Create a [Pull Request](https://help.github.com/articles/creating-a-pull-request/) from your fork branch into the master branch of this repo. # Building the Site **Important Note: it is strongly preferred that pull requests *do not* contain changes to the HTML of this site. Rather, it is better if PRs simply contain changes to text files (.rst or .md). A site administrator (@rsokl, @davidmascharka) will be responsible for publishing the actual site-HTML**. Thus the following instructions are useful for you to view your changes as they will appear in the site, but you likely need not go through the process of committing the changes to the HTML. -First, clone this repository. +## Creating a Conda Environment From Scratch -You will need to have [anaconda installed](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html) on your computer. Then create a new conda environment using the yaml file, `plymi.yml`, that is located at the top-level of this repository. To create the `plymi` conda environment, run: +First, create a miniconda environment. We'll call it `plymi` and will use Python 3.8 ```shell -conda env create -f plymi.yml +conda create -n plymi python=3.8 ``` -Once this environment is created activate it. You may need to manually install a couple of dependencies (check if these are installed in your environment first): +It is important that we activate the environment before proceeding ```shell -pip install sphinx-rtd-theme==0.4.3 -pip install jupytext==1.4.2 +conda activate plymi +``` + +Next, we will install ipython, Jupyter, numpy, and matplotlib + +```shell +conda install ipython jupyter notebook numpy matplotlib +``` + +Next, we'll use the `conda-forge` package channel to install some critical packages for building the HTML + +```shell +conda install -c conda-forge sphinx==3.4.3 nbsphinx==0.8.1 pandoc==2.1.3 jupytext=1.9.1 nbformat=5.0.8 +``` + +Finally, we will use PyPi to install jupytext and our website's stylistic theme + +```shell +pip install sphinx-rtd-theme==0.5.1 ``` and install the `plymi` code base from this repo. Clone the present repository and run: diff --git a/docs/.buildinfo b/docs/.buildinfo index 0880201e..b06273db 100644 --- a/docs/.buildinfo +++ b/docs/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 3c60093d6906b2b9dda08d0aee018696 +config: 30bed98bcfc3f0fafb4c6590d4dc316d tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/.doctrees/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.doctree b/docs/.doctrees/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.doctree index 365d9ae9..0092ec01 100644 Binary files a/docs/.doctrees/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.doctree and b/docs/.doctrees/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.doctree differ diff --git a/docs/.doctrees/Module1_GettingStartedWithPython/GettingStartedWithPython.doctree b/docs/.doctrees/Module1_GettingStartedWithPython/GettingStartedWithPython.doctree index c82b311e..73057077 100644 Binary files a/docs/.doctrees/Module1_GettingStartedWithPython/GettingStartedWithPython.doctree and b/docs/.doctrees/Module1_GettingStartedWithPython/GettingStartedWithPython.doctree differ diff --git a/docs/.doctrees/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.doctree b/docs/.doctrees/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.doctree index b911e312..09024a3d 100644 Binary files a/docs/.doctrees/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.doctree and b/docs/.doctrees/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.doctree differ diff --git a/docs/.doctrees/Module1_GettingStartedWithPython/Informal_Intro_Python.doctree b/docs/.doctrees/Module1_GettingStartedWithPython/Informal_Intro_Python.doctree index 23a58d14..d87de8e7 100644 Binary files a/docs/.doctrees/Module1_GettingStartedWithPython/Informal_Intro_Python.doctree and b/docs/.doctrees/Module1_GettingStartedWithPython/Informal_Intro_Python.doctree differ diff --git a/docs/.doctrees/Module1_GettingStartedWithPython/Installing_Python.doctree b/docs/.doctrees/Module1_GettingStartedWithPython/Installing_Python.doctree index a998a2c4..b26c1b84 100644 Binary files a/docs/.doctrees/Module1_GettingStartedWithPython/Installing_Python.doctree and b/docs/.doctrees/Module1_GettingStartedWithPython/Installing_Python.doctree differ diff --git a/docs/.doctrees/Module1_GettingStartedWithPython/Jupyter_Notebooks.doctree b/docs/.doctrees/Module1_GettingStartedWithPython/Jupyter_Notebooks.doctree index b8a47c50..fb5dfdca 100644 Binary files a/docs/.doctrees/Module1_GettingStartedWithPython/Jupyter_Notebooks.doctree and b/docs/.doctrees/Module1_GettingStartedWithPython/Jupyter_Notebooks.doctree differ diff --git a/docs/.doctrees/Module1_GettingStartedWithPython/Numerical_Work_In_Python.doctree b/docs/.doctrees/Module1_GettingStartedWithPython/Numerical_Work_In_Python.doctree index 68f2c2e1..1b6ac9cc 100644 Binary files a/docs/.doctrees/Module1_GettingStartedWithPython/Numerical_Work_In_Python.doctree and b/docs/.doctrees/Module1_GettingStartedWithPython/Numerical_Work_In_Python.doctree differ diff --git a/docs/.doctrees/Module1_GettingStartedWithPython/SiteFormatting.doctree b/docs/.doctrees/Module1_GettingStartedWithPython/SiteFormatting.doctree index 1037cccc..6f62688e 100644 Binary files a/docs/.doctrees/Module1_GettingStartedWithPython/SiteFormatting.doctree and b/docs/.doctrees/Module1_GettingStartedWithPython/SiteFormatting.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Basic_Objects.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Basic_Objects.doctree index 7edb7b43..833a6255 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Basic_Objects.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Basic_Objects.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/ConditionalStatements.doctree b/docs/.doctrees/Module2_EssentialsOfPython/ConditionalStatements.doctree index 8a3c2741..ef2c9ab2 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/ConditionalStatements.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/ConditionalStatements.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/DataStructures.doctree b/docs/.doctrees/Module2_EssentialsOfPython/DataStructures.doctree index 9bea0227..5d7adfbf 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/DataStructures.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/DataStructures.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.doctree b/docs/.doctrees/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.doctree index 2be4ab39..9473ad6c 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.doctree b/docs/.doctrees/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.doctree index adc0707c..0823b9c0 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/ForLoops.doctree b/docs/.doctrees/Module2_EssentialsOfPython/ForLoops.doctree index 860b0cb5..525142bb 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/ForLoops.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/ForLoops.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Functions.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Functions.doctree index b713975e..572241d6 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Functions.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Functions.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Generators_and_Comprehensions.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Generators_and_Comprehensions.doctree index 58277511..59240de8 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Generators_and_Comprehensions.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Generators_and_Comprehensions.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Introduction.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Introduction.doctree index 69df3fb0..12d41701 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Introduction.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Introduction.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Iterables.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Iterables.doctree index 2058ca29..2c877ad8 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Iterables.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Iterables.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Itertools.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Itertools.doctree index bc540053..e2c626c4 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Itertools.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Itertools.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Problems/DifferenceFanout.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Problems/DifferenceFanout.doctree index cd7d5d8c..f4530a2d 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Problems/DifferenceFanout.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Problems/DifferenceFanout.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Problems/EncodeAsString.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Problems/EncodeAsString.doctree index 1374766e..fd845627 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Problems/EncodeAsString.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Problems/EncodeAsString.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Problems/MarginPercentage.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Problems/MarginPercentage.doctree index 94cb1c51..666595a1 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Problems/MarginPercentage.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Problems/MarginPercentage.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Problems/MergeMaxDicts.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Problems/MergeMaxDicts.doctree index 7c6f79c3..9c84a3c4 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Problems/MergeMaxDicts.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Problems/MergeMaxDicts.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Problems/Palindrome.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Problems/Palindrome.doctree index 7d76a177..18da2d78 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Problems/Palindrome.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Problems/Palindrome.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Scope.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Scope.doctree index e25e81bd..3c0b0099 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Scope.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Scope.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/SequenceTypes.doctree b/docs/.doctrees/Module2_EssentialsOfPython/SequenceTypes.doctree index b9921a42..8d06d614 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/SequenceTypes.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/SequenceTypes.doctree differ diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Variables_and_Assignment.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Variables_and_Assignment.doctree index 4db32cfb..bb0d5c63 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Variables_and_Assignment.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Variables_and_Assignment.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.doctree b/docs/.doctrees/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.doctree index 2ee5cb48..05a816a2 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/AdvancedIndexing.doctree b/docs/.doctrees/Module3_IntroducingNumpy/AdvancedIndexing.doctree index 35101f6a..98fe7034 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/AdvancedIndexing.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/AdvancedIndexing.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/ArrayTraversal.doctree b/docs/.doctrees/Module3_IntroducingNumpy/ArrayTraversal.doctree index 6291cee7..9aae60e8 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/ArrayTraversal.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/ArrayTraversal.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/BasicArrayAttributes.doctree b/docs/.doctrees/Module3_IntroducingNumpy/BasicArrayAttributes.doctree index ecf9e11c..adcf5d80 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/BasicArrayAttributes.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/BasicArrayAttributes.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/BasicIndexing.doctree b/docs/.doctrees/Module3_IntroducingNumpy/BasicIndexing.doctree index 6aa4dc35..0f07b929 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/BasicIndexing.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/BasicIndexing.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree b/docs/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree index 8a3e7da0..6cc38def 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.doctree b/docs/.doctrees/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.doctree index 4940286f..e3db9949 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/IntroducingTheNDarray.doctree b/docs/.doctrees/Module3_IntroducingNumpy/IntroducingTheNDarray.doctree index 2dc495e8..b7152d0f 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/IntroducingTheNDarray.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/IntroducingTheNDarray.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/Problems/Approximating_pi.doctree b/docs/.doctrees/Module3_IntroducingNumpy/Problems/Approximating_pi.doctree index 8efa2eee..d8e9be76 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/Problems/Approximating_pi.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/Problems/Approximating_pi.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/Problems/ComputeAccuracy.doctree b/docs/.doctrees/Module3_IntroducingNumpy/Problems/ComputeAccuracy.doctree index 82e149f7..06c5fbd5 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/Problems/ComputeAccuracy.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/Problems/ComputeAccuracy.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/VectorizedOperations.doctree b/docs/.doctrees/Module3_IntroducingNumpy/VectorizedOperations.doctree index 00026af3..cd7271d1 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/VectorizedOperations.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/VectorizedOperations.doctree differ diff --git a/docs/.doctrees/Module4_OOP/Applications_of_OOP.doctree b/docs/.doctrees/Module4_OOP/Applications_of_OOP.doctree index 19f12944..6f69ce32 100644 Binary files a/docs/.doctrees/Module4_OOP/Applications_of_OOP.doctree and b/docs/.doctrees/Module4_OOP/Applications_of_OOP.doctree differ diff --git a/docs/.doctrees/Module4_OOP/Brief_Review.doctree b/docs/.doctrees/Module4_OOP/Brief_Review.doctree index 08262e8a..87e23c37 100644 Binary files a/docs/.doctrees/Module4_OOP/Brief_Review.doctree and b/docs/.doctrees/Module4_OOP/Brief_Review.doctree differ diff --git a/docs/.doctrees/Module4_OOP/ClassDefinition.doctree b/docs/.doctrees/Module4_OOP/ClassDefinition.doctree index 090427e2..0849bc32 100644 Binary files a/docs/.doctrees/Module4_OOP/ClassDefinition.doctree and b/docs/.doctrees/Module4_OOP/ClassDefinition.doctree differ diff --git a/docs/.doctrees/Module4_OOP/ClassInstances.doctree b/docs/.doctrees/Module4_OOP/ClassInstances.doctree index 595a5ca8..83073dcf 100644 Binary files a/docs/.doctrees/Module4_OOP/ClassInstances.doctree and b/docs/.doctrees/Module4_OOP/ClassInstances.doctree differ diff --git a/docs/.doctrees/Module4_OOP/Inheritance.doctree b/docs/.doctrees/Module4_OOP/Inheritance.doctree index 50fd06fc..53ea9fcc 100644 Binary files a/docs/.doctrees/Module4_OOP/Inheritance.doctree and b/docs/.doctrees/Module4_OOP/Inheritance.doctree differ diff --git a/docs/.doctrees/Module4_OOP/Introduction_to_OOP.doctree b/docs/.doctrees/Module4_OOP/Introduction_to_OOP.doctree index 5321fdfb..0738ad92 100644 Binary files a/docs/.doctrees/Module4_OOP/Introduction_to_OOP.doctree and b/docs/.doctrees/Module4_OOP/Introduction_to_OOP.doctree differ diff --git a/docs/.doctrees/Module4_OOP/Methods.doctree b/docs/.doctrees/Module4_OOP/Methods.doctree index 1cbd4813..65453dd2 100644 Binary files a/docs/.doctrees/Module4_OOP/Methods.doctree and b/docs/.doctrees/Module4_OOP/Methods.doctree differ diff --git a/docs/.doctrees/Module4_OOP/ObjectOrientedProgramming.doctree b/docs/.doctrees/Module4_OOP/ObjectOrientedProgramming.doctree index 7ae811f0..fb185b7c 100644 Binary files a/docs/.doctrees/Module4_OOP/ObjectOrientedProgramming.doctree and b/docs/.doctrees/Module4_OOP/ObjectOrientedProgramming.doctree differ diff --git a/docs/.doctrees/Module4_OOP/Special_Methods.doctree b/docs/.doctrees/Module4_OOP/Special_Methods.doctree index 3ab66e61..7a41bae4 100644 Binary files a/docs/.doctrees/Module4_OOP/Special_Methods.doctree and b/docs/.doctrees/Module4_OOP/Special_Methods.doctree differ diff --git a/docs/.doctrees/Module5_OddsAndEnds/Matplotlib.doctree b/docs/.doctrees/Module5_OddsAndEnds/Matplotlib.doctree index 24fcab94..77695bb0 100644 Binary files a/docs/.doctrees/Module5_OddsAndEnds/Matplotlib.doctree and b/docs/.doctrees/Module5_OddsAndEnds/Matplotlib.doctree differ diff --git a/docs/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree b/docs/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree index 4a12c810..b453a668 100644 Binary files a/docs/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree and b/docs/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree differ diff --git a/docs/.doctrees/Module5_OddsAndEnds/WorkingWithFiles.doctree b/docs/.doctrees/Module5_OddsAndEnds/WorkingWithFiles.doctree index f8c2ce31..d6405019 100644 Binary files a/docs/.doctrees/Module5_OddsAndEnds/WorkingWithFiles.doctree and b/docs/.doctrees/Module5_OddsAndEnds/WorkingWithFiles.doctree differ diff --git a/docs/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree b/docs/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree index c7fcb150..8497f6f3 100644 Binary files a/docs/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree and b/docs/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree differ diff --git a/docs/.doctrees/changes.doctree b/docs/.doctrees/changes.doctree index 78d5aacb..702d571d 100644 Binary files a/docs/.doctrees/changes.doctree and b/docs/.doctrees/changes.doctree differ diff --git a/docs/.doctrees/environment.pickle b/docs/.doctrees/environment.pickle index 94b0175c..e126a41d 100644 Binary files a/docs/.doctrees/environment.pickle and b/docs/.doctrees/environment.pickle differ diff --git a/docs/.doctrees/index.doctree b/docs/.doctrees/index.doctree index c11a9160..4d10dcdf 100644 Binary files a/docs/.doctrees/index.doctree and b/docs/.doctrees/index.doctree differ diff --git a/docs/.doctrees/intro.doctree b/docs/.doctrees/intro.doctree index 127981dc..e1e547f2 100644 Binary files a/docs/.doctrees/intro.doctree and b/docs/.doctrees/intro.doctree differ diff --git a/docs/.doctrees/module_1.doctree b/docs/.doctrees/module_1.doctree index 16d6b400..55827411 100644 Binary files a/docs/.doctrees/module_1.doctree and b/docs/.doctrees/module_1.doctree differ diff --git a/docs/.doctrees/module_2.doctree b/docs/.doctrees/module_2.doctree index 6acc8ff7..d15933d6 100644 Binary files a/docs/.doctrees/module_2.doctree and b/docs/.doctrees/module_2.doctree differ diff --git a/docs/.doctrees/module_2_problems.doctree b/docs/.doctrees/module_2_problems.doctree index 8749f86b..5772075c 100644 Binary files a/docs/.doctrees/module_2_problems.doctree and b/docs/.doctrees/module_2_problems.doctree differ diff --git a/docs/.doctrees/module_3.doctree b/docs/.doctrees/module_3.doctree index e275be70..5b547a17 100644 Binary files a/docs/.doctrees/module_3.doctree and b/docs/.doctrees/module_3.doctree differ diff --git a/docs/.doctrees/module_3_problems.doctree b/docs/.doctrees/module_3_problems.doctree index 93eaf4e2..56216a93 100644 Binary files a/docs/.doctrees/module_3_problems.doctree and b/docs/.doctrees/module_3_problems.doctree differ diff --git a/docs/.doctrees/module_4.doctree b/docs/.doctrees/module_4.doctree index 0ce16562..caffdb54 100644 Binary files a/docs/.doctrees/module_4.doctree and b/docs/.doctrees/module_4.doctree differ diff --git a/docs/.doctrees/module_5.doctree b/docs/.doctrees/module_5.doctree index 93a451d1..9bcebc6c 100644 Binary files a/docs/.doctrees/module_5.doctree and b/docs/.doctrees/module_5.doctree differ diff --git a/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/GettingStartedWithPython.ipynb b/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/GettingStartedWithPython.ipynb index fc0f34e8..60a8cebb 100644 --- a/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/GettingStartedWithPython.ipynb +++ b/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/GettingStartedWithPython.ipynb @@ -8,7 +8,7 @@ "source": [ ".. meta::\n", " :description: Topic: Basic description of the Python programming language, Difficulty: Easy, Category: Background\n", - " :keywords: python, install, basics, scripts, interpreter, foundations" + " :keywords: python, install, basics, scripts, interpreter, foundations, versions" ] }, { @@ -153,6 +153,64 @@ "We will be relying heavily on Python and a library for doing optimized numerical computations, called NumPy, throughout this course." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Understanding Different Versions of Python\n", + "\n", + "New versions of Python come out periodically, bringing new features and fixes. \n", + "You can keep track of what's new in Python by [bookmarking and checking this page every few months](https://docs.python.org/3/whatsnew/index.html).\n", + "As we take on coding projects in Python, whether it be for work, school, or a personal hobby, it is important that we remain aware of\n", + "the ways in which the language is changing, and that we take care to write code that will remain functional in the future.\n", + "\n", + "All Python version numbers use the `A.B.C` format, in accordance with [semantic versioning](https://semver.org/). \n", + "The three numbers denote major releases, minor releases, and patches.\n", + "For example, as of writing this, the current release of Python is version `3.9.1`.\n", + "\n", + "The first number denotes major releases to the language. \n", + "When a major release comes out, it means that older code will not necessarily work with the new release, and vice versa. \n", + "For example, the following code worked in Python 2 but no longer works because the `xrange` function was removed from the language\n", + "upon the release of Python 3.\n", + "\n", + "```python\n", + "# `xrange` was a frequently-used function in Python 2, but\n", + "# was removed from the language in Python 3 in favor of `range`. \n", + "# Thus the following code does not work in any version of Python 3.\n", + "count = 0\n", + "for i in xrange(10):\n", + " count = count + 1\n", + "```\n", + "\n", + "The most current major release is Python 3; Python 2 is no longer supported by any bug or security fixes and should not be used.\n", + "All releases in the near future will be improvements to Python 3, and thus they will come in the form of minor releases and patches.\n", + "\n", + "The second number denotes a minor release. \n", + "A minor release will be compatible with code from the preceding release, but it might add new features to the language that are not backwards-compatible.\n", + "For example, Python 3.6 introduced [formatted string literals](https://docs.python.org/3/whatsnew/3.6.html#pep-498-formatted-string-literals), which are \n", + "commonly referred to as \"f-strings\".\n", + "Thus as of Python 3.6 you could write code like\n", + "\n", + "```python\n", + "# Python 3.6 introduced the \"f-string\" feature, which is not\n", + "# backwards compatible with Python 3.5\n", + ">>> f\"one plus two is {1 + 2}\"\n", + "'one plus two is 3'\n", + "```\n", + "\n", + "but this code would not run in Python 3.5.X.\n", + "\n", + "The third and final number denotes a patch, which generally means bug fixes and performance improvements. \n", + "All code within the same minor release will run on all other patches within that minor release\n", + "For example, all Python 3.7.8 code is compatible with a Python 3.7.1 interpreter, and vice versa. \n", + "Patches are released fairly often, and their changes only occur 'under the hood'.\n", + "[Here is a list of changes](https://docs.python.org/3/whatsnew/changelog.html#python-3-9-1-final) were introduced by the patch level increment from Python 3.9.0 to Python 3.9.1;\n", + "few of these would affect our day-to-day experience with using Python (which isn't to say that they aren't important!).\n", + "\n", + "In simpler terms, major releases are neither backward nor forward compatible.\n", + "Minor releases are forward compatible but not necessarily fully backward compatible, and patches are both forward and backward compatible.\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -175,7 +233,7 @@ "extension": ".md", "format_name": "markdown", "format_version": "1.2", - "jupytext_version": "1.3.0rc1" + "jupytext_version": "1.9.1" } }, "kernelspec": { diff --git a/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.ipynb b/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.ipynb index 4ad5c023..4d3fd6b4 100644 --- a/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.ipynb +++ b/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.ipynb @@ -40,39 +40,49 @@ "\n", "An IDE also often provides debugging tools so that you can test your code; it will also typically interface with version-control software, like Git, so that you can keep track of versions of your code as you modify it. We will not discuss these useful, but more advanced features here.\n", "\n", - "### Recommended IDEs\n", + "## Recommended IDEs\n", "There are many excellent IDEs that can be configured to work well with Python. Two IDEs that we endorse are:\n", " \n", - "[PyCharm](https://www.jetbrains.com/pycharm/download): A powerful IDE dedicated to Python.\n", + "### PyCharm\n", + "\n", + "[PyCharm](https://www.jetbrains.com/pycharm/download) is a powerful and highly-polished IDE dedicated to developing Python code.\n", "\n", "**Pros**\n", "\n", - "- works well out-of-the-box\n", - "- long-supported by professionals and thus is very reliable\n", - "- highly configurable\n", - "- fully-featured, with an excellent debugger, context-dependent \"intellisense\", type-inference, and more\n", - "- the free \"community version\" is extremely robust and feature-rich. \n", + "- Works well out-of-the-box.\n", + "- Long-supported by professionals and thus is very reliable.\n", + "- Highly configurable.\n", + "- Fully-featured, with an excellent debugger, context-dependent \"intellisense\", type-inference, and more.\n", + "- The free \"community version\" is extremely robust and feature-rich.\n", + "- Generally provides an extremely high-quality and responsive experience for doing Python development.\n", "\n", "**Cons**\n", "\n", - " - can be resource-heavy, especially for a laptop\n", - " - may be overwhelming to new users (but has good documentation and tutorials)\n", - " - Jupyter notebook support requires the premium version of PyCharm, making it inaccessible to newcomers\n", + " - Can be resource-heavy, especially for a laptop.\n", + " - May be overwhelming to new users (but has good documentation and tutorials).\n", + " - Jupyter notebook support requires the premium version of PyCharm, making it inaccessible to newcomers.\n", " \n", - "[Visual Studio Code](https://code.visualstudio.com/) with the [Python extension](https://code.visualstudio.com/docs/languages/python): A lightweight, highly customizable IDE.\n", + "### Visual Studio Code\n", + "\n", + "[Visual Studio Code](https://code.visualstudio.com/) (with the [Python extension](https://code.visualstudio.com/docs/languages/python)) is a lightweight, highly customizable IDE that works with many different languages.\n", + "\n", + "Note: if you decide to use VSCode to do Python development, it is highly recommended that you install Microsoft's [PyLance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance)\n", + "extension.\n", + "This adds many useful features to the IDE that will make writing Python code a more delightful experience. \n", "\n", "**Pros**\n", "\n", - "- lightweight and elegant\n", - "- completely free\n", - "- works with many different languages, so you only need to familiarize yourself with one IDE if you are a polyglot programmer\n", - "- a huge number of extensions can be downloaded to add functionality to the editor; these are created by a large community of open-source developers.\n", - "- [has native support for Jupyter notebooks](https://code.visualstudio.com/docs/python/jupyter-support), meaning that you get VSCode's intellisense, debugger, and ability to inspect variables, all in a notebook.\n", + "- Lightweight and elegant.\n", + "- Completely free.\n", + "- Works with many different languages, so you only need to familiarize yourself with one IDE if you are a polyglot programmer.\n", + "- Offers a huge number of extensions that can be downloaded to add functionality to the editor; these are created by a large community of open-source developers.\n", + "- [Has native support for Jupyter notebooks](https://code.visualstudio.com/docs/python/jupyter-support), meaning that you get VSCode's intellisense, debugger, and ability to inspect variables, all in a notebook.\n", + "- Provides incredibly robust [remote coding](https://code.visualstudio.com/docs/remote/remote-overview) and [collaborative coding](https://visualstudio.microsoft.com/services/live-share/) capabilities.\n", "\n", "**Cons**\n", "\n", - "- configuring VSCode for python development can have a moderate learning curve for newcomers\n", - "- many features, like context-aware intellisense and type-inference, are simply more polished and powerful in PyCharm" + "- Configuring VSCode for Python development can have a moderate learning curve for newcomers.\n", + "- Some features, like context-aware intellisense and type-inference, are simply more polished and powerful in PyCharm." ] }, { @@ -94,7 +104,7 @@ "extension": ".md", "format_name": "markdown", "format_version": "1.2", - "jupytext_version": "1.3.0rc1" + "jupytext_version": "1.9.1" } }, "kernelspec": { diff --git a/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Informal_Intro_Python.ipynb b/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Informal_Intro_Python.ipynb index 0c7f332e..b514c4ed 100644 --- a/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Informal_Intro_Python.ipynb +++ b/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Informal_Intro_Python.ipynb @@ -16,6 +16,39 @@ "metadata": {}, "source": [ "# An Informal Introduction to Python\n", + "\n", + "
\n", + "\n", + "**Before You Start This Section**: \n", + "\n", + "In the following section we will be using IPython or a Jupyter notebook to run our code.\n", + "Presently, there is an incompatibility with these programs and a Python package called `jedi`, which typically is responsible for performing auto-completions in our code (when prompted by hitting ``, which we will be doing below).\n", + "It is really useful!\n", + "\n", + "First, let's check to see if we have an incompatible version of `jedi` installed.\n", + "In your terminal (before starting a Python/IPython/Jupyter session), run\n", + " \n", + "```\n", + "conda list\n", + "```\n", + "\n", + "And look for the line that starts with `jedi`\n", + " \n", + "```\n", + "jedi 0.18.0\n", + "```\n", + "\n", + "If you see that you have version `0.18.0` installed (as above), then you will want to downgrade it.\n", + "In the same terminal, run the following command\n", + "\n", + "```\n", + "conda install jedi=0.17.2\n", + "```\n", + "You should be all set once you have followed the prompts and the installation has completed!\n", + " \n", + "Note that you will need to repeat this process if you [create a new conda environment](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html#A-Brief-Introduction-to-Conda-Environments) with IPython/Jupter installed in it.\n", + "
\n", + "\n", "Now that you have the Anaconda distribution of Python installed on your machine, let's write some simple Python code! We are going to forego writing a full Python script for now, and instead make use of a convenient tool for doing quick code scratchwork. The IPython console was installed as a part of Anaconda; it will allow us to build incrementally off of snippets of code, instead of having to execute an entire script all at once. \n", "\n", "Let's open an IPython console. Open your terminal if you are a Mac/Linux user, or start `cmd.exe` if you are a Windows user. Now type `ipython` into the console and hit ``. You should see the following display on your screen:\n", @@ -33,7 +66,14 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.361255Z", + "iopub.status.busy": "2021-01-31T21:47:25.361255Z", + "iopub.status.idle": "2021-01-31T21:47:25.378259Z", + "shell.execute_reply": "2021-01-31T21:47:25.378259Z" + } + }, "outputs": [ { "data": { @@ -60,7 +100,14 @@ { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.382261Z", + "iopub.status.busy": "2021-01-31T21:47:25.381257Z", + "iopub.status.idle": "2021-01-31T21:47:25.394256Z", + "shell.execute_reply": "2021-01-31T21:47:25.395259Z" + } + }, "outputs": [], "source": [ "x = 10" @@ -76,7 +123,14 @@ { "cell_type": "code", "execution_count": 3, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.399257Z", + "iopub.status.busy": "2021-01-31T21:47:25.398260Z", + "iopub.status.idle": "2021-01-31T21:47:25.409258Z", + "shell.execute_reply": "2021-01-31T21:47:25.410259Z" + } + }, "outputs": [ { "data": { @@ -84,7 +138,7 @@ "10" ] }, - "execution_count": 3, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -103,7 +157,14 @@ { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.414258Z", + "iopub.status.busy": "2021-01-31T21:47:25.413258Z", + "iopub.status.idle": "2021-01-31T21:47:25.425259Z", + "shell.execute_reply": "2021-01-31T21:47:25.425259Z" + } + }, "outputs": [ { "data": { @@ -111,7 +172,7 @@ "123" ] }, - "execution_count": 4, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -130,7 +191,14 @@ { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.428260Z", + "iopub.status.busy": "2021-01-31T21:47:25.428260Z", + "iopub.status.idle": "2021-01-31T21:47:25.440256Z", + "shell.execute_reply": "2021-01-31T21:47:25.440256Z" + } + }, "outputs": [], "source": [ "import math" @@ -162,7 +230,14 @@ { "cell_type": "code", "execution_count": 6, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.444260Z", + "iopub.status.busy": "2021-01-31T21:47:25.444260Z", + "iopub.status.idle": "2021-01-31T21:47:25.455258Z", + "shell.execute_reply": "2021-01-31T21:47:25.455258Z" + } + }, "outputs": [ { "data": { @@ -170,7 +245,7 @@ "10.0" ] }, - "execution_count": 6, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -191,7 +266,14 @@ { "cell_type": "code", "execution_count": 7, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.459259Z", + "iopub.status.busy": "2021-01-31T21:47:25.458259Z", + "iopub.status.idle": "2021-01-31T21:47:25.472259Z", + "shell.execute_reply": "2021-01-31T21:47:25.471259Z" + } + }, "outputs": [], "source": [ "from math import factorial" @@ -207,7 +289,14 @@ { "cell_type": "code", "execution_count": 8, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.475260Z", + "iopub.status.busy": "2021-01-31T21:47:25.475260Z", + "iopub.status.idle": "2021-01-31T21:47:25.487257Z", + "shell.execute_reply": "2021-01-31T21:47:25.488257Z" + } + }, "outputs": [ { "data": { @@ -215,7 +304,7 @@ "120" ] }, - "execution_count": 8, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -237,7 +326,14 @@ { "cell_type": "code", "execution_count": 9, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.492257Z", + "iopub.status.busy": "2021-01-31T21:47:25.491256Z", + "iopub.status.idle": "2021-01-31T21:47:25.503256Z", + "shell.execute_reply": "2021-01-31T21:47:25.503256Z" + } + }, "outputs": [ { "data": { @@ -245,7 +341,7 @@ "'the cat in the hat'" ] }, - "execution_count": 9, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -264,7 +360,14 @@ { "cell_type": "code", "execution_count": 10, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.506259Z", + "iopub.status.busy": "2021-01-31T21:47:25.506259Z", + "iopub.status.idle": "2021-01-31T21:47:25.519257Z", + "shell.execute_reply": "2021-01-31T21:47:25.519257Z" + } + }, "outputs": [ { "data": { @@ -272,7 +375,7 @@ "'the dog in the sash'" ] }, - "execution_count": 10, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -291,7 +394,14 @@ { "cell_type": "code", "execution_count": 11, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.522258Z", + "iopub.status.busy": "2021-01-31T21:47:25.522258Z", + "iopub.status.idle": "2021-01-31T21:47:25.536257Z", + "shell.execute_reply": "2021-01-31T21:47:25.535257Z" + } + }, "outputs": [ { "data": { @@ -299,7 +409,7 @@ "'He picked up the phone, \"Hello? What do you want?\" Bob was a rather impolite dude.'" ] }, - "execution_count": 11, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -320,7 +430,14 @@ { "cell_type": "code", "execution_count": 12, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.539258Z", + "iopub.status.busy": "2021-01-31T21:47:25.539258Z", + "iopub.status.idle": "2021-01-31T21:47:25.551257Z", + "shell.execute_reply": "2021-01-31T21:47:25.551257Z" + } + }, "outputs": [ { "name": "stdout", @@ -346,7 +463,14 @@ { "cell_type": "code", "execution_count": 13, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.554257Z", + "iopub.status.busy": "2021-01-31T21:47:25.554257Z", + "iopub.status.idle": "2021-01-31T21:47:25.565256Z", + "shell.execute_reply": "2021-01-31T21:47:25.566258Z" + } + }, "outputs": [], "source": [ "sentence = \"Who would have thought that we were robots all along?\"" @@ -362,7 +486,14 @@ { "cell_type": "code", "execution_count": 14, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.569257Z", + "iopub.status.busy": "2021-01-31T21:47:25.569257Z", + "iopub.status.idle": "2021-01-31T21:47:25.582259Z", + "shell.execute_reply": "2021-01-31T21:47:25.582259Z" + } + }, "outputs": [ { "data": { @@ -370,7 +501,7 @@ "53" ] }, - "execution_count": 14, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -389,7 +520,14 @@ { "cell_type": "code", "execution_count": 15, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.585257Z", + "iopub.status.busy": "2021-01-31T21:47:25.585257Z", + "iopub.status.idle": "2021-01-31T21:47:25.597257Z", + "shell.execute_reply": "2021-01-31T21:47:25.597257Z" + } + }, "outputs": [ { "data": { @@ -397,7 +535,7 @@ "'Who '" ] }, - "execution_count": 15, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -409,7 +547,14 @@ { "cell_type": "code", "execution_count": 16, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.600256Z", + "iopub.status.busy": "2021-01-31T21:47:25.600256Z", + "iopub.status.idle": "2021-01-31T21:47:25.613258Z", + "shell.execute_reply": "2021-01-31T21:47:25.613258Z" + } + }, "outputs": [ { "data": { @@ -417,7 +562,7 @@ "'along?'" ] }, - "execution_count": 16, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -429,7 +574,14 @@ { "cell_type": "code", "execution_count": 17, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.617260Z", + "iopub.status.busy": "2021-01-31T21:47:25.617260Z", + "iopub.status.idle": "2021-01-31T21:47:25.629260Z", + "shell.execute_reply": "2021-01-31T21:47:25.630259Z" + } + }, "outputs": [ { "data": { @@ -437,7 +589,7 @@ "'ould have thought'" ] }, - "execution_count": 17, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -456,7 +608,14 @@ { "cell_type": "code", "execution_count": 18, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.635262Z", + "iopub.status.busy": "2021-01-31T21:47:25.634258Z", + "iopub.status.idle": "2021-01-31T21:47:25.645257Z", + "shell.execute_reply": "2021-01-31T21:47:25.646262Z" + } + }, "outputs": [ { "data": { @@ -464,7 +623,7 @@ "True" ] }, - "execution_count": 18, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -497,7 +656,14 @@ { "cell_type": "code", "execution_count": 19, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.652260Z", + "iopub.status.busy": "2021-01-31T21:47:25.651257Z", + "iopub.status.idle": "2021-01-31T21:47:25.661259Z", + "shell.execute_reply": "2021-01-31T21:47:25.662258Z" + } + }, "outputs": [ { "data": { @@ -505,7 +671,7 @@ "3" ] }, - "execution_count": 19, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -528,7 +694,14 @@ { "cell_type": "code", "execution_count": 20, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.667257Z", + "iopub.status.busy": "2021-01-31T21:47:25.666257Z", + "iopub.status.idle": "2021-01-31T21:47:25.677257Z", + "shell.execute_reply": "2021-01-31T21:47:25.676259Z" + } + }, "outputs": [ { "data": { @@ -536,7 +709,7 @@ "'Who would have thought that we were computers all along?'" ] }, - "execution_count": 20, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -556,7 +729,14 @@ { "cell_type": "code", "execution_count": 21, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.683257Z", + "iopub.status.busy": "2021-01-31T21:47:25.683257Z", + "iopub.status.idle": "2021-01-31T21:47:25.692258Z", + "shell.execute_reply": "2021-01-31T21:47:25.693257Z" + } + }, "outputs": [ { "data": { @@ -564,7 +744,7 @@ "[-1, 0.3333333333333333, 20, 6]" ] }, - "execution_count": 21, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -583,7 +763,14 @@ { "cell_type": "code", "execution_count": 22, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.697256Z", + "iopub.status.busy": "2021-01-31T21:47:25.697256Z", + "iopub.status.idle": "2021-01-31T21:47:25.708258Z", + "shell.execute_reply": "2021-01-31T21:47:25.707256Z" + } + }, "outputs": [ { "data": { @@ -591,7 +778,7 @@ "[1, 2, 'a', 0.5, 'apple and orange']" ] }, - "execution_count": 22, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -610,7 +797,14 @@ { "cell_type": "code", "execution_count": 23, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.712258Z", + "iopub.status.busy": "2021-01-31T21:47:25.711257Z", + "iopub.status.idle": "2021-01-31T21:47:25.723257Z", + "shell.execute_reply": "2021-01-31T21:47:25.723257Z" + } + }, "outputs": [ { "data": { @@ -618,7 +812,7 @@ "[1, 2, 3, 'a', 'b', 'c']" ] }, - "execution_count": 23, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -637,7 +831,14 @@ { "cell_type": "code", "execution_count": 24, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.727258Z", + "iopub.status.busy": "2021-01-31T21:47:25.726259Z", + "iopub.status.idle": "2021-01-31T21:47:25.739257Z", + "shell.execute_reply": "2021-01-31T21:47:25.740256Z" + } + }, "outputs": [], "source": [ "my_list = [10, 20, 30, 40, 50, 60]" @@ -646,7 +847,14 @@ { "cell_type": "code", "execution_count": 25, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.745258Z", + "iopub.status.busy": "2021-01-31T21:47:25.744257Z", + "iopub.status.idle": "2021-01-31T21:47:25.757260Z", + "shell.execute_reply": "2021-01-31T21:47:25.756259Z" + } + }, "outputs": [ { "data": { @@ -654,7 +862,7 @@ "10" ] }, - "execution_count": 25, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -666,7 +874,14 @@ { "cell_type": "code", "execution_count": 26, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.765259Z", + "iopub.status.busy": "2021-01-31T21:47:25.764257Z", + "iopub.status.idle": "2021-01-31T21:47:25.770258Z", + "shell.execute_reply": "2021-01-31T21:47:25.771258Z" + } + }, "outputs": [ { "data": { @@ -674,7 +889,7 @@ "20" ] }, - "execution_count": 26, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -693,7 +908,14 @@ { "cell_type": "code", "execution_count": 27, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.777259Z", + "iopub.status.busy": "2021-01-31T21:47:25.776259Z", + "iopub.status.idle": "2021-01-31T21:47:25.785256Z", + "shell.execute_reply": "2021-01-31T21:47:25.785256Z" + } + }, "outputs": [ { "data": { @@ -701,7 +923,7 @@ "60" ] }, - "execution_count": 27, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -720,7 +942,14 @@ { "cell_type": "code", "execution_count": 28, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.790257Z", + "iopub.status.busy": "2021-01-31T21:47:25.789257Z", + "iopub.status.idle": "2021-01-31T21:47:25.801257Z", + "shell.execute_reply": "2021-01-31T21:47:25.802256Z" + } + }, "outputs": [ { "data": { @@ -728,7 +957,7 @@ "False" ] }, - "execution_count": 28, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -740,7 +969,14 @@ { "cell_type": "code", "execution_count": 29, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.806257Z", + "iopub.status.busy": "2021-01-31T21:47:25.805257Z", + "iopub.status.idle": "2021-01-31T21:47:25.817257Z", + "shell.execute_reply": "2021-01-31T21:47:25.816256Z" + } + }, "outputs": [], "source": [ "my_list[1] = -5" @@ -749,7 +985,14 @@ { "cell_type": "code", "execution_count": 30, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.821257Z", + "iopub.status.busy": "2021-01-31T21:47:25.820256Z", + "iopub.status.idle": "2021-01-31T21:47:25.831257Z", + "shell.execute_reply": "2021-01-31T21:47:25.831257Z" + } + }, "outputs": [ { "data": { @@ -757,7 +1000,7 @@ "[10, -5, 30, 40, 50, 60]" ] }, - "execution_count": 30, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -769,7 +1012,14 @@ { "cell_type": "code", "execution_count": 31, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.835259Z", + "iopub.status.busy": "2021-01-31T21:47:25.834256Z", + "iopub.status.idle": "2021-01-31T21:47:25.848257Z", + "shell.execute_reply": "2021-01-31T21:47:25.847256Z" + } + }, "outputs": [ { "data": { @@ -777,7 +1027,7 @@ "True" ] }, - "execution_count": 31, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -796,7 +1046,14 @@ { "cell_type": "code", "execution_count": 32, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.852256Z", + "iopub.status.busy": "2021-01-31T21:47:25.851257Z", + "iopub.status.idle": "2021-01-31T21:47:25.862256Z", + "shell.execute_reply": "2021-01-31T21:47:25.862256Z" + } + }, "outputs": [ { "data": { @@ -804,7 +1061,7 @@ "[10, -5, 30]" ] }, - "execution_count": 32, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -823,7 +1080,14 @@ { "cell_type": "code", "execution_count": 33, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.866257Z", + "iopub.status.busy": "2021-01-31T21:47:25.865256Z", + "iopub.status.idle": "2021-01-31T21:47:25.876256Z", + "shell.execute_reply": "2021-01-31T21:47:25.877258Z" + } + }, "outputs": [], "source": [ "my_list[:3] = \"abc\"" @@ -832,7 +1096,14 @@ { "cell_type": "code", "execution_count": 34, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.880257Z", + "iopub.status.busy": "2021-01-31T21:47:25.879256Z", + "iopub.status.idle": "2021-01-31T21:47:25.893255Z", + "shell.execute_reply": "2021-01-31T21:47:25.893255Z" + } + }, "outputs": [ { "data": { @@ -840,7 +1111,7 @@ "['a', 'b', 'c', 40, 50, 60]" ] }, - "execution_count": 34, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -859,7 +1130,14 @@ { "cell_type": "code", "execution_count": 35, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.896257Z", + "iopub.status.busy": "2021-01-31T21:47:25.895256Z", + "iopub.status.idle": "2021-01-31T21:47:25.909260Z", + "shell.execute_reply": "2021-01-31T21:47:25.909260Z" + } + }, "outputs": [], "source": [ "my_list.append(\"moo\")" @@ -868,7 +1146,14 @@ { "cell_type": "code", "execution_count": 36, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.913256Z", + "iopub.status.busy": "2021-01-31T21:47:25.913256Z", + "iopub.status.idle": "2021-01-31T21:47:25.925256Z", + "shell.execute_reply": "2021-01-31T21:47:25.925256Z" + } + }, "outputs": [ { "data": { @@ -876,7 +1161,7 @@ "['a', 'b', 'c', 40, 50, 60, 'moo']" ] }, - "execution_count": 36, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -892,7 +1177,7 @@ "extension": ".md", "format_name": "markdown", "format_version": "1.2", - "jupytext_version": "1.3.0rc1" + "jupytext_version": "1.9.1" } }, "kernelspec": { @@ -910,7 +1195,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.8.5" } }, "nbformat": 4, diff --git a/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Installing_Python.ipynb b/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Installing_Python.ipynb index bb9d6277..e0e897a3 100644 --- a/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Installing_Python.ipynb +++ b/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Installing_Python.ipynb @@ -111,7 +111,7 @@ "extension": ".md", "format_name": "markdown", "format_version": "1.2", - "jupytext_version": "1.3.0rc1" + "jupytext_version": "1.9.1" } }, "kernelspec": { diff --git a/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Jupyter_Notebooks.ipynb b/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Jupyter_Notebooks.ipynb index 2071cfa6..c1984b1c 100644 --- a/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Jupyter_Notebooks.ipynb +++ b/docs/.doctrees/nbsphinx/Module1_GettingStartedWithPython/Jupyter_Notebooks.ipynb @@ -16,14 +16,51 @@ "metadata": {}, "source": [ "# Jupyter Notebooks\n", - "In recent years, the Jupyter Notebook has become a massively popular tool for doing research-oriented work in Python and other languages alike. Its emergence marked a paradigm shift in the way data science is conducted. \n", "\n", - "A Jupyter notebook is similar to the IPython console, but, instead of only being able to work with a single line of code at a time, you can easily edit and re-execute *any* code that had been written in a notebook. Furthermore, you can save a notebook, and thus return to it later. Additionally, a notebook provides many terrific features. For instance, you can embed visualizations of data within a notebook, and write blocks of nicely-formatted text (using the [Markdown syntax](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)), for presenting and explaining the contents of the notebook. \n", + "
\n", + "\n", + "**Before You Start This Section**: \n", + "\n", + "In the following section we will be using IPython or a Jupyter notebook to run our code.\n", + "Presently, there is an incompatibility with these programs and a Python package called `jedi`, which typically is responsible for performing auto-completions in our code (when prompted by hitting ``, which we will be doing below).\n", + "It is really useful!\n", + "\n", + "First, let's check to see if we have an incompatible version of `jedi` installed.\n", + "In your terminal (before starting a Python/IPython/Jupyter session), run\n", + " \n", + "```\n", + "conda list\n", + "```\n", + "\n", + "And look for the line that starts with `jedi`\n", + " \n", + "```\n", + "jedi 0.18.0\n", + "```\n", + "\n", + "If you see that you have version `0.18.0` installed (as above), then you will want to downgrade it.\n", + "In the same terminal, run the following command\n", + "\n", + "```\n", + "conda install jedi=0.17.2\n", + "```\n", + "You should be all set once you have followed the prompts and the installation has completed!\n", + " \n", + "Note that you will need to repeat this process if you [create a new conda environment](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html#A-Brief-Introduction-to-Conda-Environments) with IPython/Jupter installed in it.\n", + "
\n", + "\n", + "In recent years, the Jupyter Notebook has become a massively popular tool for doing research-oriented work in Python and other languages alike.\n", + "Its emergence marked a paradigm shift in the way data science is conducted. \n", + "\n", + "A Jupyter notebook is similar to the IPython console, but, instead of only being able to work with a single line of code at a time, you can easily edit and re-execute *any* code that had been written in a notebook. Furthermore, you can save a notebook, and thus return to it later.\n", + "Additionally, a notebook provides many terrific features. For instance, you can embed visualizations of data within a notebook, and write blocks of nicely-formatted text (using the [Markdown syntax](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)), for presenting and explaining the contents of the notebook. \n", "\n", "In this way, the Jupyter Notebook stands out as an excellent tool for many practical applications. You could work on a notebook while you are working through sections of this website, for instance, testing out snippets of code, and answering reading-comprehension questions as you proceed through the text, and using markdown-headers to visually separate different portions of the notebook. When I do research, I am always creating Jupyter notebooks in which I write code that analyzes data, I plot various results, presented in different ways, and I write detailed markdown-text blocks to document my work. The end result is something that I can share with my labmates, and easily revisit months later without having to struggle to recall what I had done.\n", "\n", "## Jupyter Lab\n", - "[Jupyter lab](https://jupyterlab.readthedocs.io/) is a new web interface from Project Jupyter that provides a rich web-based interface for managing and running Jupyter notebooks, console terminals, and text editors, all within your browser. Among its useful features and polished user interface - compared to that a Jupyter notebook server - Jupyter lab provides moveable panes for viewing data, images, and code output apart from the rest of the notebook. This is facilitates effective data science work flows.\n", + "[Jupyter lab](https://jupyterlab.readthedocs.io/) is a new web interface from Project Jupyter that provides a rich web-based interface for managing and running Jupyter notebooks, console terminals, and text editors, all within your browser.\n", + "Among its useful features and polished user interface, Jupyter lab provides moveable panes for viewing data, images, and code output apart from the rest of the notebook.\n", + "This is facilitates effective data science work flows.\n", "\n", "It is recommended that you peruse the [Jupyter lab documentation](https://jupyterlab.readthedocs.io/en/stable/getting_started/overview.html) to get a feel for all of its added capabilities." ] @@ -32,7 +69,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The following instructions are laid out for running a Jupyter notebook server. That being said, the process for running a Jupyter lab server and working with notebooks therein is nearly identical. Both Jupyter notebook and Jupyter lab should already be [installed via Anaconda](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html)." + "The following instructions are laid out for running a Jupyter notebook server. That being said, the process for running a Jupyter lab server and working with notebooks therein is nearly identical.\n", + "Both Jupyter notebook and Jupyter lab should already be [installed via Anaconda](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html)." ] }, { @@ -115,20 +153,34 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:30.495595Z", + "iopub.status.busy": "2021-01-31T21:47:30.494594Z", + "iopub.status.idle": "2021-01-31T21:47:31.168637Z", + "shell.execute_reply": "2021-01-31T21:47:31.167635Z" + } + }, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "# this tells Jupyter to embed matplotlib plots in the notebook\n", - "%matplotlib notebook " + "%matplotlib inline " ] }, { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:31.173637Z", + "iopub.status.busy": "2021-01-31T21:47:31.172634Z", + "iopub.status.idle": "2021-01-31T21:47:31.183635Z", + "shell.execute_reply": "2021-01-31T21:47:31.183635Z" + } + }, "outputs": [], "source": [ "def sinc(x):\n", @@ -142,7 +194,14 @@ { "cell_type": "code", "execution_count": 3, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:31.187635Z", + "iopub.status.busy": "2021-01-31T21:47:31.186634Z", + "iopub.status.idle": "2021-01-31T21:47:31.198636Z", + "shell.execute_reply": "2021-01-31T21:47:31.198636Z" + } + }, "outputs": [], "source": [ "# evaluate functions at 1000 points evenly spaced in [-15, 15]\n", @@ -154,798 +213,35 @@ { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:31.233635Z", + "iopub.status.busy": "2021-01-31T21:47:31.232637Z", + "iopub.status.idle": "2021-01-31T21:47:31.719634Z", + "shell.execute_reply": "2021-01-31T21:47:31.720634Z" + } + }, "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "window.mpl = {};\n", - "\n", - "\n", - "mpl.get_websocket_type = function() {\n", - " if (typeof(WebSocket) !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof(MozWebSocket) !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert('Your browser does not have WebSocket support.' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.');\n", - " };\n", - "}\n", - "\n", - "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = (this.ws.binaryType != undefined);\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById(\"mpl-warnings\");\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent = (\n", - " \"This browser does not support binary websocket messages. \" +\n", - " \"Performance may be slow.\");\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = $('
');\n", - " this._root_extra_style(this.root)\n", - " this.root.attr('style', 'display: inline-block');\n", - "\n", - " $(parent_element).append(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", - " fig.send_message(\"send_image_mode\", {});\n", - " if (mpl.ratio != 1) {\n", - " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", - " }\n", - " fig.send_message(\"refresh\", {});\n", - " }\n", - "\n", - " this.imageObj.onload = function() {\n", - " if (fig.image_mode == 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function() {\n", - " fig.ws.close();\n", - " }\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "}\n", - "\n", - "mpl.figure.prototype._init_header = function() {\n", - " var titlebar = $(\n", - " '
');\n", - " var titletext = $(\n", - " '
');\n", - " titlebar.append(titletext)\n", - " this.root.append(titlebar);\n", - " this.header = titletext[0];\n", - "}\n", - "\n", - "\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "\n", - "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "mpl.figure.prototype._init_canvas = function() {\n", - " var fig = this;\n", - "\n", - " var canvas_div = $('
');\n", - "\n", - " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", - "\n", - " function canvas_keyboard_event(event) {\n", - " return fig.key_event(event, event['data']);\n", - " }\n", - "\n", - " canvas_div.keydown('key_press', canvas_keyboard_event);\n", - " canvas_div.keyup('key_release', canvas_keyboard_event);\n", - " this.canvas_div = canvas_div\n", - " this._canvas_extra_style(canvas_div)\n", - " this.root.append(canvas_div);\n", - "\n", - " var canvas = $('');\n", - " canvas.addClass('mpl-canvas');\n", - " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", - "\n", - " this.canvas = canvas[0];\n", - " this.context = canvas[0].getContext(\"2d\");\n", - "\n", - " var backingStore = this.context.backingStorePixelRatio ||\n", - "\tthis.context.webkitBackingStorePixelRatio ||\n", - "\tthis.context.mozBackingStorePixelRatio ||\n", - "\tthis.context.msBackingStorePixelRatio ||\n", - "\tthis.context.oBackingStorePixelRatio ||\n", - "\tthis.context.backingStorePixelRatio || 1;\n", - "\n", - " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband = $('');\n", - " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", - "\n", - " var pass_mouse_events = true;\n", - "\n", - " canvas_div.resizable({\n", - " start: function(event, ui) {\n", - " pass_mouse_events = false;\n", - " },\n", - " resize: function(event, ui) {\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " stop: function(event, ui) {\n", - " pass_mouse_events = true;\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " });\n", - "\n", - " function mouse_event_fn(event) {\n", - " if (pass_mouse_events)\n", - " return fig.mouse_event(event, event['data']);\n", - " }\n", - "\n", - " rubberband.mousedown('button_press', mouse_event_fn);\n", - " rubberband.mouseup('button_release', mouse_event_fn);\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband.mousemove('motion_notify', mouse_event_fn);\n", - "\n", - " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", - " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", - "\n", - " canvas_div.on(\"wheel\", function (event) {\n", - " event = event.originalEvent;\n", - " event['data'] = 'scroll'\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " mouse_event_fn(event);\n", - " });\n", - "\n", - " canvas_div.append(canvas);\n", - " canvas_div.append(rubberband);\n", - "\n", - " this.rubberband = rubberband;\n", - " this.rubberband_canvas = rubberband[0];\n", - " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", - " this.rubberband_context.strokeStyle = \"#000000\";\n", - "\n", - " this._resize_canvas = function(width, height) {\n", - " // Keep the size of the canvas, canvas container, and rubber band\n", - " // canvas in synch.\n", - " canvas_div.css('width', width)\n", - " canvas_div.css('height', height)\n", - "\n", - " canvas.attr('width', width * mpl.ratio);\n", - " canvas.attr('height', height * mpl.ratio);\n", - " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", - "\n", - " rubberband.attr('width', width);\n", - " rubberband.attr('height', height);\n", - " }\n", - "\n", - " // Set the figure to an initial 600x600px, this will subsequently be updated\n", - " // upon first draw.\n", - " this._resize_canvas(600, 600);\n", - "\n", - " // Disable right mouse context menu.\n", - " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", - " return false;\n", - " });\n", - "\n", - " function set_focus () {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "}\n", - "\n", - "mpl.figure.prototype._init_toolbar = function() {\n", - " var fig = this;\n", - "\n", - " var nav_element = $('
')\n", - " nav_element.attr('style', 'width: 100%');\n", - " this.root.append(nav_element);\n", - "\n", - " // Define a callback function for later on.\n", - " function toolbar_event(event) {\n", - " return fig.toolbar_button_onclick(event['data']);\n", - " }\n", - " function toolbar_mouse_event(event) {\n", - " return fig.toolbar_button_onmouseover(event['data']);\n", - " }\n", - "\n", - " for(var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " // put a spacer in here.\n", - " continue;\n", - " }\n", - " var button = $('');\n", - " button.click(method_name, toolbar_event);\n", - " button.mouseover(tooltip, toolbar_mouse_event);\n", - " nav_element.append(button);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = $('');\n", - " nav_element.append(status_bar);\n", - " this.message = status_bar[0];\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = $('
');\n", - " var button = $('');\n", - " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", - " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", - " buttongrp.append(button);\n", - " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", - " titlebar.prepend(buttongrp);\n", - "}\n", - "\n", - "mpl.figure.prototype._root_extra_style = function(el){\n", - " var fig = this\n", - " el.on(\"remove\", function(){\n", - "\tfig.close_ws(fig, {});\n", - " });\n", - "}\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function(el){\n", - " // this is important to make the div 'focusable\n", - " el.attr('tabindex', 0)\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " }\n", - " else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "\n", - "}\n", - "\n", - "mpl.figure.prototype._key_event_extra = function(event, name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager)\n", - " manager = IPython.keyboard_manager;\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which == 13) {\n", - " this.canvas_div.blur();\n", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], "text/plain": [ - "" + "" ] }, + "execution_count": 1, "metadata": {}, - "output_type": "display_data" + "output_type": "execute_result" }, { "data": { - "text/html": [ - "
" - ], + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -1038,7 +334,7 @@ "extension": ".md", "format_name": "markdown", "format_version": "1.2", - "jupytext_version": "1.3.0rc1" + "jupytext_version": "1.9.1" } }, "kernelspec": { @@ -1056,7 +352,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.8.5" } }, "nbformat": 4, diff --git a/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html b/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html index 2c40252e..901877b7 100644 --- a/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html +++ b/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html @@ -1,44 +1,47 @@ - - + - + - + Doing Numerical Work in Python — Python Like You Mean It + + + + + + + + - + - - + - - - - - @@ -81,6 +84,7 @@
+ +
@@ -138,18 +143,20 @@ + +
- Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. -
@@ -264,7 +276,6 @@

Summary jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.ipynb b/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.ipynb index 043e09e5..36fd6d83 100644 --- a/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.ipynb +++ b/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.ipynb @@ -65,7 +65,7 @@ "extension": ".md", "format_name": "markdown", "format_version": "1.2", - "jupytext_version": "1.3.0rc1" + "jupytext_version": "1.9.1" } }, "kernelspec": { diff --git a/docs/Module1_GettingStartedWithPython/SiteFormatting.html b/docs/Module1_GettingStartedWithPython/SiteFormatting.html index 6ab5e0cc..9c01a669 100644 --- a/docs/Module1_GettingStartedWithPython/SiteFormatting.html +++ b/docs/Module1_GettingStartedWithPython/SiteFormatting.html @@ -1,46 +1,49 @@ - - + - + - + A Quick Guide to Formatting — Python Like You Mean It + + + + + + - + + + - - + - - - - - @@ -85,6 +88,7 @@

+ +
@@ -150,11 +158,13 @@ + +
    -
  • Docs »
  • +
  • »
  • Module 1: Getting Started with Python »
  • @@ -163,7 +173,7 @@
  • - + View page source @@ -179,224 +189,6 @@ ",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/docs/_static/js/html5shiv.min.js b/docs/_static/js/html5shiv.min.js new file mode 100644 index 00000000..cd1c674f --- /dev/null +++ b/docs/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/docs/_static/js/modernizr.min.js b/docs/_static/js/modernizr.min.js deleted file mode 100644 index f65d4797..00000000 --- a/docs/_static/js/modernizr.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/* Modernizr 2.6.2 (Custom Build) | MIT & BSD - * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load - */ -;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d',a,""].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f
"),i("table.docutils.footnote").wrap("
"),i("table.docutils.citation").wrap("
"),i(".wy-menu-vertical ul").not(".simple").siblings("a").each(function(){var e=i(this);expand=i(''),expand.on("click",function(n){return t.toggleCurrent(e),n.stopPropagation(),!1}),e.prepend(expand)})},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),i=e.find('[href="'+n+'"]');if(0===i.length){var t=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(i=e.find('[href="#'+t.attr("id")+'"]')).length&&(i=e.find('[href="#"]'))}0this.docHeight||(this.navBar.scrollTop(i),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",function(){this.linkScroll=!1})},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:e.exports.ThemeNav,StickyNav:e.exports.ThemeNav}),function(){for(var r=0,n=["ms","moz","webkit","o"],e=0;e
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}t.length>0&&($(".wy-menu-vertical .current").removeClass("current"),t.addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l1").parent().addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l2").addClass("current"),t.closest("li.toctree-l3").addClass("current"),t.closest("li.toctree-l4").addClass("current"),t.closest("li.toctree-l5").addClass("current"),t[0].scrollIntoView())}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t - - + - + - + Changelog — Python Like You Mean It + + + + + + + + - + - - + - - - - - @@ -82,6 +85,7 @@
+ +
@@ -148,18 +159,20 @@ + +
@@ -196,7 +207,6 @@

Index

- + + + - - + - - - - - @@ -82,6 +87,7 @@
+ + @@ -139,18 +146,20 @@ + +

What this isn’t

@@ -213,6 +223,11 @@

What about Python textbooks?

Python is a relatively easy language to pick up, and it doesn’t require much rigor to make code work. Unfortunately, this means that there are many Python users out there who know enough to just get by, but lack a sound understanding of the language. You don’t want to get caught in the “know enough Python to be dangerous” zone; therein lies complacency, stagnation, and the genesis of a lot of bad code. You’ve got to Python like you mean it!

+
+

Join Our Discussion Board

+

Join the PLYMI community to ask questions, recommend new content, or to just say hello!

+

(A note to BWSI students: please stick to your class’ piazza board for posting questions)

+

PLYMI is on GitHub

If you have questions about the reading, think that you have spotted some mistakes, or would like to contribute to PLYMI, please visit our GitHub page. You will need to create a GitHub account in order to post an issue; this process is free and easy. We would love for you to join us to discuss the website!

@@ -225,12 +240,13 @@

Contributors@Federici)

  • Annabelle Lew (GitHub:@AnnabelleLew)

  • Petar Griggs (GitHub:@petarmhg)

  • -
  • Sam Carpenter (GitHub:@HardBoiled800)

  • +
  • Sam Carpenter (GitHub:@samaocarpenter)

  • +
  • Patrick O’Shea (GitHub:@ArtichokeSap)

  • About Me

    -

    I started learning to use Python in graduate school for my physics research, and I was so bad at using it. Fortunately, one of my labmates was more experienced and had the good sense to tell me that my code and work flow was terrible. He pointed me to tooling, style guides, and documentation pages so that I could improve (I’d like to think that this resource would have been a huge help to me back then). I’ve been coding in Python for at least six years now, and I’ve taken to following the language, along with its new features and changes, quite closely. Currently I do machine learning research, and have served as a core developer for a machine learning library. I also love to teach, so this has been a fun project for me to take on!

    +

    I started learning to use Python in graduate school for my physics research, and I was so bad at using it. Fortunately, one of my labmates was more experienced and had the good sense to tell me that my code and work flow was terrible. He pointed me to tooling, style guides, and documentation pages so that I could improve (I’d like to think that this resource would have been a huge help to me back then). I’ve been coding in Python for at least eight years now, and I’ve taken to following the language, along with its new features and changes, quite closely. Currently I do machine learning research, and have served as a core developer for a machine learning library. I also love to teach, so this has been a fun project for me to take on!

    Table of Contents:

    @@ -338,27 +361,28 @@

    Indices and tables - - - - +

    -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. -
    @@ -367,7 +391,6 @@

    Indices and tables jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs/intro.html b/docs/intro.html index 1a845175..de64ef09 100644 --- a/docs/intro.html +++ b/docs/intro.html @@ -1,44 +1,49 @@ - - + - - - + + + + + Python Like You Mean It — Python Like You Mean It + + + + + + + + - + - - + - - - - - @@ -83,6 +88,7 @@ + + @@ -149,18 +157,20 @@ + +

    What this isn’t

    @@ -223,6 +234,11 @@

    What about Python textbooks?

    Python is a relatively easy language to pick up, and it doesn’t require much rigor to make code work. Unfortunately, this means that there are many Python users out there who know enough to just get by, but lack a sound understanding of the language. You don’t want to get caught in the “know enough Python to be dangerous” zone; therein lies complacency, stagnation, and the genesis of a lot of bad code. You’ve got to Python like you mean it!

    +
    +

    Join Our Discussion Board

    +

    Join the PLYMI community to ask questions, recommend new content, or to just say hello!

    +

    (A note to BWSI students: please stick to your class’ piazza board for posting questions)

    +

    PLYMI is on GitHub

    If you have questions about the reading, think that you have spotted some mistakes, or would like to contribute to PLYMI, please visit our GitHub page. You will need to create a GitHub account in order to post an issue; this process is free and easy. We would love for you to join us to discuss the website!

    @@ -235,12 +251,13 @@

    Contributors@Federici)

  • Annabelle Lew (GitHub:@AnnabelleLew)

  • Petar Griggs (GitHub:@petarmhg)

  • -
  • Sam Carpenter (GitHub:@HardBoiled800)

  • +
  • Sam Carpenter (GitHub:@samaocarpenter)

  • +
  • Patrick O’Shea (GitHub:@ArtichokeSap)

  • About Me

    -

    I started learning to use Python in graduate school for my physics research, and I was so bad at using it. Fortunately, one of my labmates was more experienced and had the good sense to tell me that my code and work flow was terrible. He pointed me to tooling, style guides, and documentation pages so that I could improve (I’d like to think that this resource would have been a huge help to me back then). I’ve been coding in Python for at least six years now, and I’ve taken to following the language, along with its new features and changes, quite closely. Currently I do machine learning research, and have served as a core developer for a machine learning library. I also love to teach, so this has been a fun project for me to take on!

    +

    I started learning to use Python in graduate school for my physics research, and I was so bad at using it. Fortunately, one of my labmates was more experienced and had the good sense to tell me that my code and work flow was terrible. He pointed me to tooling, style guides, and documentation pages so that I could improve (I’d like to think that this resource would have been a huge help to me back then). I’ve been coding in Python for at least eight years now, and I’ve taken to following the language, along with its new features and changes, quite closely. Currently I do machine learning research, and have served as a core developer for a machine learning library. I also love to teach, so this has been a fun project for me to take on!

    @@ -249,29 +266,29 @@

    About Me - - - - - - + + -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -280,7 +297,6 @@

    About Me jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs/module_1.html b/docs/module_1.html index e39a3659..f5f6513a 100644 --- a/docs/module_1.html +++ b/docs/module_1.html @@ -1,44 +1,47 @@ - - + - + - + Module 1: Getting Started with Python — Python Like You Mean It + + + + + + + + - + - - + - - - - - @@ -83,6 +86,7 @@ + + @@ -148,18 +153,20 @@ + +
    -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -280,7 +292,6 @@

    Module 1: Getting Started with Python jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs/module_2.html b/docs/module_2.html index 80212a7e..a4cb3b8c 100644 --- a/docs/module_2.html +++ b/docs/module_2.html @@ -1,44 +1,47 @@ - - + - + - + Module 2: The Essentials of Python — Python Like You Mean It + + + + + + + + - + - - + - - - - - @@ -83,6 +86,7 @@ + + @@ -156,18 +161,20 @@ + +
    -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -358,7 +365,6 @@

    Module 2: The Essentials of Python jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs/module_2_problems.html b/docs/module_2_problems.html index 7ef497c0..8c9bb505 100644 --- a/docs/module_2_problems.html +++ b/docs/module_2_problems.html @@ -1,44 +1,47 @@ - - + - + - + Module 2: Problems — Python Like You Mean It + + + + + + + + - + - - + - - - - - @@ -83,6 +86,7 @@ + + @@ -147,18 +152,20 @@ + +
    -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -271,7 +278,6 @@

    Module 2: Problems jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs/module_3.html b/docs/module_3.html index 1d46e7a4..2767b3a1 100644 --- a/docs/module_3.html +++ b/docs/module_3.html @@ -1,44 +1,47 @@ - - + - + - + Module 3: The Essentials of NumPy — Python Like You Mean It + + + + + + + + - + - - + - - - - - @@ -83,6 +86,7 @@ + + @@ -151,18 +156,20 @@ + +
    -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -318,7 +325,6 @@

    Module 3: The Essentials of NumPy jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs/module_3_problems.html b/docs/module_3_problems.html index b7e1be69..6d8c8399 100644 --- a/docs/module_3_problems.html +++ b/docs/module_3_problems.html @@ -1,44 +1,47 @@ - - + - + - + Module 3: Problems — Python Like You Mean It + + + + + + + + - + - - + - - - - - @@ -83,6 +86,7 @@ + + @@ -144,18 +149,20 @@ + +
    -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -255,7 +262,6 @@

    Module 3: Problems jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs/module_4.html b/docs/module_4.html index 51241e9d..1e0599fa 100644 --- a/docs/module_4.html +++ b/docs/module_4.html @@ -1,44 +1,47 @@ - - + - + - + Module 4: Object Oriented Programming — Python Like You Mean It + + + + + + + + - + - - + - - - - - @@ -83,6 +86,7 @@ + + @@ -150,18 +155,20 @@ + +
    @@ -288,7 +295,6 @@

    Module 4: Object Oriented Programming jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs/module_5.html b/docs/module_5.html index 7aacdc34..36593ab0 100644 --- a/docs/module_5.html +++ b/docs/module_5.html @@ -1,44 +1,47 @@ - - + - + - + Module 5: Odds and Ends — Python Like You Mean It + + + + + + + + - + - - + - - - - - @@ -83,6 +86,7 @@ + + @@ -146,18 +151,20 @@ + +
    @@ -285,7 +292,6 @@

    Module 5: Odds and Ends - + + - - + - - - - - - + + @@ -82,6 +87,7 @@ + + @@ -139,19 +146,19 @@ + +
    @@ -165,8 +172,7 @@ @@ -180,20 +186,25 @@
    - @@ -202,7 +213,6 @@ - + - - - - - - - + + + + + + + - - - - - @@ -80,6 +84,7 @@ + + @@ -137,18 +143,20 @@ + +
    @@ -239,20 +250,25 @@

    Doing Simple Arithmetic (not graded)

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with
    Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -261,7 +277,6 @@

    Doing Simple Arithmetic (not graded) jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.ipynb b/docs_backup/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.ipynb new file mode 100644 index 00000000..fddde186 --- /dev/null +++ b/docs_backup/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Checking Python Version (not graded)\n", + "Run \n", + "```python\n", + "import sys\n", + "``` \n", + "and then \n", + "```python\n", + "print(sys.version)\n", + "```\n", + "to confirm you have Python 3.5 (or greater)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Slicing Strings (not graded)\n", + "Create a variable, `x`, with the string value `\"I'm a string, hear me roar!\"` assigned to it. Now print out the last 13 characters contained in `x` via slicing." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Constructing a List (not graded)\n", + "Create an empty list, `x = []`. Using \n", + " - a `while` loop \n", + " - the list-method `append`\n", + " - the built-in function `len`\n", + "append numbers to `x` until it contains 0-9: `[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]`.\n", + "\n", + "> WARNING: if you give the while-loop a condition that never evaluates to False then your code will run forever. If this happens, at the top of your Jupyter notebook go to Kernel and then click Interrupt. If you are in the IPython shell, hit CTRL-C or close the terminal.\n", + "\n", + "**Bonus**: accomplish this without using any variables, other than `x`.\n", + "\n", + ">Note that there are much simpler ways to construct a list of numbers than by appending to one in a while loop. For instance, one can use list comprehensions. We will learn about these later." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Slicing a List (not graded)\n", + "Given `x = [1, 2, 3, 4, 5]`, predict the output following sliced lists. Try rewriting any negative indices using the appropriate positive indices.\n", + "\n", + "- `x[-3:]`\n", + "- `x[-3:2]`\n", + "- `x[-6:4]`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Operating on Various Data Types (not graded)\n", + "Why can Python calculate `1 + 1` and `'1' + '1'` but not `'1' + 1`?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Doing Simple Arithmetic (not graded)\n", + "Given a, b, and c calculate and print the two solutions to the quadratic equation using the quadratic formula.\n", + "\n", + ">(Use `x**.5` to take the square root of an expression)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.html b/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.html index d6e0e87c..59ba49ab 100644 --- a/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.html +++ b/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.html @@ -1,45 +1,49 @@ - - + - + - + - + Introducing the Python Programming Language — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ + + @@ -156,11 +163,13 @@ + +

    Python Scripts

    You can save the the valid code from the preceding section in a text file using a simple text editor, and voilà you have written a Python script: a text file containing Python code. It is standard to save this text file using the suffix .py (e.g. my_code.py), rather than the familiar .txt (e.g. my_text.txt). There is nothing special about the .py suffix; it simply helps differentiate files that contain Python code from run-of-the-mill text files, which contain plain English.

    -

    Although you can use simple text editors to write Python scripts (e.g. notepad (Win), TextEdit (Mac), nano (Linux)), there are much more sophisticated editors that provide an “integrated development environment” (IDE) for writing code. An IDE, configured to support Python, will warn you if you have written code that violates Python’s grammar rules, similar to the way word processing software warns you if you have made a spelling mistake. More on IDEs in a later section.

    +

    Although you can use simple text editors to write Python scripts (e.g. notepad (Win), TextEdit (Mac), nano (Linux)), there are much more sophisticated editors that provide an “integrated development environment” (IDE) for writing code. An IDE, configured to support Python, will warn you if you have written code that violates Python’s grammar rules, similar to the way word processing software warns you if you have made a spelling mistake. More on IDEs in a later section.

    WARNING:

    Do not use word processing programs, like Microsoft Word, to write code. They will “silently” change the characters written in your file, such as the type of quotation marks being used. This will cause errors in your code.

    @@ -256,11 +265,11 @@

    Python Scripts

    A Python interpreter is any computer program that is capable of doing the following:

      -
    • Read in a text file (e.g. my_code.py).
    • -
    • Parse the text and determine if it obeys the rules of the Python language (the interpreter will raise an error if the rules are not obeyed).
    • -
    • Translate the parsed text into instructions, according to the Python language’s specifications.
    • -
    • Instruct the computer to carry out the tasks.
    • -
    • As a whole, a Python script is executed from top-to-bottom by the interpreter.
    • +
    • Read in a text file (e.g. my_code.py).

    • +
    • Parse the text and determine if it obeys the rules of the Python language (the interpreter will raise an error if the rules are not obeyed).

    • +
    • Translate the parsed text into instructions, according to the Python language’s specifications.

    • +
    • Instruct the computer to carry out the tasks.

    • +
    • As a whole, a Python script is executed from top-to-bottom by the interpreter.

    The first Python interpeter was written in the programming language C, and is known as CPython. Accordingly, the CPython interpreter is the official interpreter of the Python language. Any new rules/features that are introduced to the Python language are guaranteed be implemented in the CPython code base.

    @@ -285,7 +294,7 @@

    What is a Python Interpreter and What Does it Mean to “Install Python”?<

    Why Python?

    Python has become a hugely popular programming language. In fact, it is likely the most popular introductory language at universities. First and foremost, its syntax is designed to be intuitive and readable. For example, the following Python code sums the numbers 0-9, and prints the result:

    a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    -print(sum(a))
    +print(sum(a))
     

    This can be reproduced by the following C++ code, which is arguably less-intuitive:

    @@ -302,16 +311,42 @@

    Why Python? +

    Understanding Different Versions of Python

    +

    New versions of Python come out periodically, bringing new features and fixes. You can keep track of what’s new in Python by bookmarking and checking this page every few months. As we take on coding projects in Python, whether it be for work, school, or a personal hobby, it is important that we remain aware of the ways in which the language is changing, and that we take care to write code that will remain functional in the future.

    +

    All Python version numbers use the A.B.C format, in accordance with semantic versioning. The three numbers denote major releases, minor releases, and patches. For example, as of writing this, the current release of Python is version 3.9.1.

    +

    The first number denotes major releases to the language. When a major release comes out, it means that older code will not necessarily work with the new release, and vice versa. For example, the following code worked in Python 2 but no longer works because the xrange function was removed from the language upon the release of Python 3.

    +
    # `xrange` was a frequently-used function in Python 2, but
    +# was removed from the language in Python 3 in favor of `range`.
    +# Thus the following code does not work in any version of Python 3.
    +count = 0
    +for i in xrange(10):
    +    count = count + 1
    +
    +
    +

    The most current major release is Python 3; Python 2 is no longer supported by any bug or security fixes and should not be used. All releases in the near future will be improvements to Python 3, and thus they will come in the form of minor releases and patches.

    +

    The second number denotes a minor release. A minor release will be compatible with code from the preceding release, but it might add new features to the language that are not backwards-compatible. For example, Python 3.6 introduced formatted string literals, which are commonly referred to as “f-strings”. Thus as of Python 3.6 you could write code like

    +
    # Python 3.6 introduced the "f-string" feature, which is not
    +# backwards compatible with Python 3.5
    +>>> f"one plus two is {1 + 2}"
    +'one plus two is 3'
    +
    +
    +

    but this code would not run in Python 3.5.X.

    +

    The third and final number denotes a patch, which generally means bug fixes and performance improvements. All code within the same minor release will run on all other patches within that minor release For example, all Python 3.7.8 code is compatible with a Python 3.7.1 interpreter, and vice versa. Patches are released fairly often, and their changes only occur ‘under the hood’. Here is a list of changes were introduced by +the patch level increment from Python 3.9.0 to Python 3.9.1; few of these would affect our day-to-day experience with using Python (which isn’t to say that they aren’t important!).

    +

    In simpler terms, major releases are neither backward nor forward compatible. Minor releases are forward compatible but not necessarily fully backward compatible, and patches are both forward and backward compatible.

    +

    Summary

      -
    • Python is a programming language - it provides us with a simple set of grammatical rules that allow us to write human-readable text, which can be translated unambiguously to instruct a computer to perform tasks.
    • -
    • Python code is text that conforms to the Python language.
    • -
    • A Python script is a text file containing Python code. Traditionally such a file will be saved using the suffix .py.
    • -
    • A Python interpreter is a program that is capable of reading and parsing a text file, and translating the code into machine instructions, as specified by the Python language.
    • -
    • To “install Python” onto you machine boils down to saving a functioning Python interpreter onto your machine.
    • -
    • The official Python interpreter is a program written in the language C, and is known as the CPython interpreter.
    • -
    • The “standard library” is a large collection of tools and functions that comes packaged with the CPython interpreter.
    • +
    • Python is a programming language - it provides us with a simple set of grammatical rules that allow us to write human-readable text, which can be translated unambiguously to instruct a computer to perform tasks.

    • +
    • Python code is text that conforms to the Python language.

    • +
    • A Python script is a text file containing Python code. Traditionally such a file will be saved using the suffix .py.

    • +
    • A Python interpreter is a program that is capable of reading and parsing a text file, and translating the code into machine instructions, as specified by the Python language.

    • +
    • To “install Python” onto you machine boils down to saving a functioning Python interpreter onto your machine.

    • +
    • The official Python interpreter is a program written in the language C, and is known as the CPython interpreter.

    • +
    • The “standard library” is a large collection of tools and functions that comes packaged with the CPython interpreter.

    @@ -321,29 +356,29 @@

    Summary - - - - - - + +

    -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -352,7 +387,6 @@

    Summary jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.ipynb b/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.ipynb new file mode 100644 index 00000000..60a8cebb --- /dev/null +++ b/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.ipynb @@ -0,0 +1,247 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Basic description of the Python programming language, Difficulty: Easy, Category: Background\n", + " :keywords: python, install, basics, scripts, interpreter, foundations, versions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introducing the Python Programming Language\n", + "\n", + "In this section we will learn\n", + "\n", + " - What Python is.\n", + " - What it means to \"install Python\" on your computer.\n", + " - How one writes and executes Python code.\n", + "\n", + "## What is Python?\n", + "**Python is a programming language**. That is, it provides us with a strict set of grammatical rules that correspond to well-defined instructions that a computer will obey. The tremendous value of this is that we can write text documents that are relatively simple and intuitive for humans to read, and yet can inform the computer to perform precise operations. Python **code** is simply text that conforms to the Python language.\n", + "\n", + "For example, the following text obeys the rules of the Python language:\n", + "\n", + "```python\n", + "x = 2 + 3\n", + "print('2 + 3 = {}'.format(x))\n", + "```\n", + "\n", + "According to the Python language, it will instruct the computer to:\n", + "\n", + " - compute 2 + 3\n", + " - assign the resulting value (5) to a variable `x`, in memory\n", + " - access the value of `x`, and print to the computer's screen: '2 + 3 = 5'\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An example of code that **does not** obey Python's rules is:\n", + "\n", + "```python\n", + "x = 2 ~ 3\n", + "```\n", + "because character `~` has no meaning in the Python language when it is placed between two integers.\n", + "\n", + "To \"learn Python\" thus entails learning the grammatical rules specified by the Python language, and the computer instuctions that they map to. Additionally, you will want to familiarize yourself with many of the convenient tools that are \"pre-written\" and come with the Python language; they are part of the so-called standard library.\n", + "\n", + "Given this basic understanding of what the Python programming language is, we now want to know how to use our Python code to send instructions to the computer. The most basic way of doing this is to:\n", + "\n", + " - Write a Python \"script\": a text file containing Python code.\n", + " - Pass this text file to a **Python interpreter**, which will instruct the computer to carry out the operations described by the code.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Scripts\n", + "You can save the the valid code from the preceding section in a text file using a simple text editor, and *voilà* you have written a **Python script**: a text file containing Python code. It is standard to save this text file using the suffix `.py` (e.g. `my_code.py`), rather than the familiar `.txt` (e.g. `my_text.txt`). There is nothing special about the `.py` suffix; it simply helps differentiate files that contain Python code from run-of-the-mill text files, which contain plain English.\n", + "\n", + "Although you can use simple text editors to write Python scripts (e.g. notepad (Win), TextEdit (Mac), nano (Linux)), there are much more sophisticated editors that provide an \"integrated development environment\" (IDE) for writing code. An IDE, configured to support Python, will warn you if you have written code that violates Python's grammar rules, similar to the way word processing software warns you if you have made a spelling mistake. More on IDEs in a later section. \n", + "\n", + "
    \n", + "\n", + "**WARNING**: \n", + "\n", + "Do not use word processing programs, like Microsoft Word, to write code. They will \"silently\" change the characters written in your file, such as the type of quotation marks being used. This will cause errors in your code. \n", + "
    \n", + "\n", + "Now that you have a Python script, how do you get the computer to read it and follow its instructions? You will need to install a **Python interpreter** on your computer to accomplish this. This is what people mean, whether they know it or not, when they tell you to \"install Python\" on your computer." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What is a Python Interpreter and What Does it Mean to \"Install Python\"?\n", + "\n", + "A Python interpreter is any computer program that is capable of doing the following:\n", + "\n", + " - Read in a text file (e.g. `my_code.py`).\n", + " - Parse the text and determine if it obeys the rules of the Python language (the interpreter will raise an error if the rules are not obeyed).\n", + " - Translate the parsed text into instructions, according to the Python language's specifications.\n", + " - Instruct the computer to carry out the tasks.\n", + " - As a whole, a Python script is executed from top-to-bottom by the interpreter.\n", + "\n", + "The first Python interpeter was written in the programming language C, and is known as CPython. Accordingly, **the CPython interpreter is the official interpreter of the Python language**. Any new rules/features that are introduced to the Python language are guaranteed be implemented in the [CPython code base](https://github.com/python/cpython).\n", + "\n", + "
    \n", + "\n", + "**Note**: \n", + "\n", + "Python interpreters have been in written in programming languages other than C, like in Java (Jython) and Go (Grumpy). These are not guaranteed to be up-to-date with the latest specifications of the Python language, and are rarely used in comparison to the CPython interpreter.\n", + "
    \n", + "\n", + "
    \n", + "\n", + "**About Installing Python**: \n", + "\n", + "Do not download and install Python from python.org. There isn't anything wrong with this, but a later section will provide you with explicit instructions for installing Python on your machine. \n", + "\n", + "
    \n", + "\n", + "If you \"install Python on your computer\" from [python.org](https://www.python.org/downloads/release/python-363/), you are essentially downloading an executable program onto your machine that operates as a Python interpreter. On Windows, for instance, this program is called `python.exe`. This program is the result of the aforementioned CPython code, and it is capable of performing the all of the tasks of a Python interpreter. Additionally, you are downloading a large suite of useful tools and functions that you can utilize in your code. This is known as the Python standard library; take a moment to look over its contents [here](https://docs.python.org/3/library/index.html#the-python-standard-library). \n", + "\n", + "Once you have a Python interpreter installed on your machine, using it to execute a Python script is quite simple. Assume for the sake of simplicity that the `python` interpreter program and `my_script.py` are in the same directory (a.k.a 'folder') in your computer. Then, in a terminal (`cmd.exe` for Windows) you can execute the following command:\n", + "\n", + "```shell\n", + "python my_script.py\n", + "```\n", + "\n", + "this will instruct the Python interpreter program `python` to read your text file `my_script.py`, ensure that your code obeys all of the grammatical rules specified by the Python language, and then send instructions to your computer in accordance with the code that it reads. If your script simply contains the code `print(\"hello world\")`, then the text `hello world` will appear in your terminal window, as expected.\n", + "\n", + "In practice, you will be able to simply execute `python my_script.py` in any directory, and your computer will know where to look to find the `python` program. This will be set up during the installation process.\n", + "\n", + "It may be confusing to think that the Python language is interpreted by using a program written in another language. How, then, is that language interpreted? The answer, in the case of CPython, is that C code need not be interpreted; programs exist for Windows, Mac, and Linux that can translate C code directly into machine instructions. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Why Python?\n", + "\n", + "Python has become a hugely popular programming language. In fact, it is likely the [most popular introductory language at universities](https://cacm.acm.org/blogs/blog-cacm/176450-python-is-now-the-most-popular-introductory-teaching-language-at-top-u-s-universities/fulltext). First and foremost, its syntax is designed to be intuitive and readable. For example, the following Python code sums the numbers 0-9, and prints the result:\n", + "```python\n", + "a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", + "print(sum(a))\n", + "```\n", + "\n", + "This can be reproduced by the following C++ code, which is arguably less-intuitive:\n", + "```cpp\n", + "#include \n", + "#include \n", + "#include \n", + "\n", + "int main() {\n", + " std::vector a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n", + " std::cout << std::accumulate(a.begin(), a.end(), 0) << std::endl;\n", + "}\n", + "```\n", + "\n", + "As such, Python is a language that is conducive to rapidly prototyping and testing code. Additionally, it is open-sourced: it is free to use, anyone can participate in improving/maintaining the language, and many people create new libraries that add tremendous functionality to the language. Thus, Python has become exceptionally popular especially among scientists, engineers, and other researchers.\n", + "\n", + "We will be relying heavily on Python and a library for doing optimized numerical computations, called NumPy, throughout this course." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Understanding Different Versions of Python\n", + "\n", + "New versions of Python come out periodically, bringing new features and fixes. \n", + "You can keep track of what's new in Python by [bookmarking and checking this page every few months](https://docs.python.org/3/whatsnew/index.html).\n", + "As we take on coding projects in Python, whether it be for work, school, or a personal hobby, it is important that we remain aware of\n", + "the ways in which the language is changing, and that we take care to write code that will remain functional in the future.\n", + "\n", + "All Python version numbers use the `A.B.C` format, in accordance with [semantic versioning](https://semver.org/). \n", + "The three numbers denote major releases, minor releases, and patches.\n", + "For example, as of writing this, the current release of Python is version `3.9.1`.\n", + "\n", + "The first number denotes major releases to the language. \n", + "When a major release comes out, it means that older code will not necessarily work with the new release, and vice versa. \n", + "For example, the following code worked in Python 2 but no longer works because the `xrange` function was removed from the language\n", + "upon the release of Python 3.\n", + "\n", + "```python\n", + "# `xrange` was a frequently-used function in Python 2, but\n", + "# was removed from the language in Python 3 in favor of `range`. \n", + "# Thus the following code does not work in any version of Python 3.\n", + "count = 0\n", + "for i in xrange(10):\n", + " count = count + 1\n", + "```\n", + "\n", + "The most current major release is Python 3; Python 2 is no longer supported by any bug or security fixes and should not be used.\n", + "All releases in the near future will be improvements to Python 3, and thus they will come in the form of minor releases and patches.\n", + "\n", + "The second number denotes a minor release. \n", + "A minor release will be compatible with code from the preceding release, but it might add new features to the language that are not backwards-compatible.\n", + "For example, Python 3.6 introduced [formatted string literals](https://docs.python.org/3/whatsnew/3.6.html#pep-498-formatted-string-literals), which are \n", + "commonly referred to as \"f-strings\".\n", + "Thus as of Python 3.6 you could write code like\n", + "\n", + "```python\n", + "# Python 3.6 introduced the \"f-string\" feature, which is not\n", + "# backwards compatible with Python 3.5\n", + ">>> f\"one plus two is {1 + 2}\"\n", + "'one plus two is 3'\n", + "```\n", + "\n", + "but this code would not run in Python 3.5.X.\n", + "\n", + "The third and final number denotes a patch, which generally means bug fixes and performance improvements. \n", + "All code within the same minor release will run on all other patches within that minor release\n", + "For example, all Python 3.7.8 code is compatible with a Python 3.7.1 interpreter, and vice versa. \n", + "Patches are released fairly often, and their changes only occur 'under the hood'.\n", + "[Here is a list of changes](https://docs.python.org/3/whatsnew/changelog.html#python-3-9-1-final) were introduced by the patch level increment from Python 3.9.0 to Python 3.9.1;\n", + "few of these would affect our day-to-day experience with using Python (which isn't to say that they aren't important!).\n", + "\n", + "In simpler terms, major releases are neither backward nor forward compatible.\n", + "Minor releases are forward compatible but not necessarily fully backward compatible, and patches are both forward and backward compatible.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "- Python is a programming language - it provides us with a simple set of grammatical rules that allow us to write human-readable text, which can be translated unambiguously to instruct a computer to perform tasks.\n", + "- Python code is text that conforms to the Python language.\n", + "- A Python script is a text file containing Python code. Traditionally such a file will be saved using the suffix `.py`.\n", + "- A Python interpreter is a program that is capable of reading and parsing a text file, and translating the code into machine instructions, as specified by the Python language.\n", + "- To \"install Python\" onto you machine boils down to saving a functioning Python interpreter onto your machine.\n", + "- The official Python interpreter is a program written in the language C, and is known as the CPython interpreter.\n", + "- The \"standard library\" is a large collection of tools and functions that comes packaged with the CPython interpreter." + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html b/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html index 462d4d3a..818aefda 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html +++ b/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html @@ -1,45 +1,49 @@ - - + - + - + Setting Up a Development Environment — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ +
    + @@ -156,11 +164,13 @@ + +
    @@ -224,43 +234,52 @@

    Integrated Development Environments -
  • check your code for syntax errors (a misspelled function name, a reference to an undefined variable, etc)
  • -
  • colorize your code so that it is easy to distinguish, for instance, numbers from character strings.
  • -
  • enable you to easily look up documentation and definitions for functions that you are using.
  • -
  • autocomplete the names of variables and functions as you are typing them.
  • +
  • check your code for syntax errors (a misspelled function name, a reference to an undefined variable, etc)

  • +
  • colorize your code so that it is easy to distinguish, for instance, numbers from character strings.

  • +
  • enable you to easily look up documentation and definitions for functions that you are using.

  • +
  • autocomplete the names of variables and functions as you are typing them.

  • An IDE also often provides debugging tools so that you can test your code; it will also typically interface with version-control software, like Git, so that you can keep track of versions of your code as you modify it. We will not discuss these useful, but more advanced features here.

    +

    @@ -306,7 +325,6 @@

    Recommended IDEs jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.ipynb b/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.ipynb new file mode 100644 index 00000000..4d3fd6b4 --- /dev/null +++ b/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.ipynb @@ -0,0 +1,118 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Integrated Development Environments, Difficulty: Easy, Category: Tools\n", + " :keywords: python, introduction, IDE, PyCharm, VSCode, Jupyter, recommendation, tools" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Setting Up a Development Environment\n", + "## What You Will Learn\n", + "\n", + "- An IDE is a sophisticated text editor that allows you edit, run, and debug code. \n", + "- The Python shell is an interface for typing Python code and executing it directly in your computer's terminal.\n", + "- The IPython shell is a much nicer version of the Python shell - it provides syntax highlighting, autocompletion, and other features.\n", + "- The Jupyter Notebook is a powerful tool for prototyping and experimenting with code, as well as visualizing data and writing nicely-formatted text. We will be using this throughout the course." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Integrated Development Environments\n", + "In Section 1 of this module, we learned that a Python script is simply a text file that contains Python code. Aside from using a `.py` suffix for the filename, there is nothing that differentiates this sort of file from any other text file. That being said, it is not a good idea to use a simple text editor to write Python code (and it is a big mistake use word-processing software, like Microsoft Word, to do so). Instead we want an \"integrated development environment\" (IDE) that will facilitate our code-writing. \n", + "\n", + "First and foremost, a good IDE will provide a text editor that will:\n", + "\n", + "- check your code for syntax errors (a misspelled function name, a reference to an undefined variable, etc)\n", + "- colorize your code so that it is easy to distinguish, for instance, numbers from character strings.\n", + "- enable you to easily look up documentation and definitions for functions that you are using.\n", + "- autocomplete the names of variables and functions as you are typing them.\n", + "\n", + "An IDE also often provides debugging tools so that you can test your code; it will also typically interface with version-control software, like Git, so that you can keep track of versions of your code as you modify it. We will not discuss these useful, but more advanced features here.\n", + "\n", + "## Recommended IDEs\n", + "There are many excellent IDEs that can be configured to work well with Python. Two IDEs that we endorse are:\n", + " \n", + "### PyCharm\n", + "\n", + "[PyCharm](https://www.jetbrains.com/pycharm/download) is a powerful and highly-polished IDE dedicated to developing Python code.\n", + "\n", + "**Pros**\n", + "\n", + "- Works well out-of-the-box.\n", + "- Long-supported by professionals and thus is very reliable.\n", + "- Highly configurable.\n", + "- Fully-featured, with an excellent debugger, context-dependent \"intellisense\", type-inference, and more.\n", + "- The free \"community version\" is extremely robust and feature-rich.\n", + "- Generally provides an extremely high-quality and responsive experience for doing Python development.\n", + "\n", + "**Cons**\n", + "\n", + " - Can be resource-heavy, especially for a laptop.\n", + " - May be overwhelming to new users (but has good documentation and tutorials).\n", + " - Jupyter notebook support requires the premium version of PyCharm, making it inaccessible to newcomers.\n", + " \n", + "### Visual Studio Code\n", + "\n", + "[Visual Studio Code](https://code.visualstudio.com/) (with the [Python extension](https://code.visualstudio.com/docs/languages/python)) is a lightweight, highly customizable IDE that works with many different languages.\n", + "\n", + "Note: if you decide to use VSCode to do Python development, it is highly recommended that you install Microsoft's [PyLance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance)\n", + "extension.\n", + "This adds many useful features to the IDE that will make writing Python code a more delightful experience. \n", + "\n", + "**Pros**\n", + "\n", + "- Lightweight and elegant.\n", + "- Completely free.\n", + "- Works with many different languages, so you only need to familiarize yourself with one IDE if you are a polyglot programmer.\n", + "- Offers a huge number of extensions that can be downloaded to add functionality to the editor; these are created by a large community of open-source developers.\n", + "- [Has native support for Jupyter notebooks](https://code.visualstudio.com/docs/python/jupyter-support), meaning that you get VSCode's intellisense, debugger, and ability to inspect variables, all in a notebook.\n", + "- Provides incredibly robust [remote coding](https://code.visualstudio.com/docs/remote/remote-overview) and [collaborative coding](https://visualstudio.microsoft.com/services/live-share/) capabilities.\n", + "\n", + "**Cons**\n", + "\n", + "- Configuring VSCode for Python development can have a moderate learning curve for newcomers.\n", + "- Some features, like context-aware intellisense and type-inference, are simply more polished and powerful in PyCharm." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Takeaway**:\n", + "\n", + "Integrated Development Environments (IDEs) provide powerful tools for helping you write well-formatted and typo-free code. We recommend using PyCharm Community Edition or Visual Studio Code (with the Python extension installed) for your Python IDE. \n", + "
    " + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.html b/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.html index 124649a1..6e5edc3c 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.html +++ b/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.html @@ -1,45 +1,49 @@ - - + - + - + An Informal Introduction to Python — Python Like You Mean It + + + + + + - + + + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ + + @@ -154,11 +160,13 @@ + +

    This console session is persistent, meaning that we can define a variable and then reference it in our code later on within this console session. Let’s define the variable x and assign it to the integer 10 (please follow along in the IPython console)

    [2]:
     
    -
    - -
    -10
    -
    -
    +
    +
    +10
    +

    Now, let’s use x in a quadratic equation \(x^{2} + 2x + 3\), and compute this total.

    [4]:
     
    -
    -
    -123
    -
    -
    +
    +
    +123
    +

    Python’s “standard library”, the various tools and functions that come packaged as part of the core language, includes plenty of familiar mathematical functions. As a matter of organization, Python stores these mathematical functions away in a module named “math”. To make use of this math module, we must import it into our code.

    [5]:
     
    -
    - -
    -10.0
    -
    -
    +
    +
    +10.0
    +

    You might wonder why the result displayed as 10.0 and not simply as 10; in Module 2 we will see that these are two different types of numbers in the Python language. The former is called a floating-point number, indicating the presence of its decimal point, whereas the latter is an integer. The math.sqrt function is defined such that it always returns its results as floating-point numbers.

    In the case that we want to make frequent use of a certain function from the math module, it’d be nice to avoid having to type out the math module prefix, math., repeatedly. We can accomplish this by importing an individual function from the math module. Let’s import the factorial function from the math module.

    @@ -518,8 +592,8 @@

    Dabbling with Numbers
    [7]:
     
    -
    - -
    -120
    -
    -
    +
    +
    +120
    +
    - -
    -'the cat in the hat'
    -
    -
    +
    +
    +'the cat in the hat'
    +

    Single quotes also work:

    If you use single quotes to form a string, then that string is able to contain the double-quote as a character (and vice versa):

    There are designated special characters that allow us to affect the way a string is formatted when it is printed to the string. For example, if \n ever occurs in a string, it is treated as a single character that indicates a line-break. This will only manifest if such a string is fed to the built-in print function, which informs the computer to print text to a user’s screen.

    Let’s create a string that will display as three separate lines, when printed to the screen.

    @@ -609,8 +683,8 @@

    Messing with Strings
    [12]:
     
    -
    - - -
    -53
    -
    -
    +
    +
    +53
    +

    We can access the first 4 characters in the string, the last 6 characters, or a few characters in the middle by “slicing” the string:

    We can also check to see if some other string is contained within our string. Is the string "robot" contained within sentence?

    As a quick way to check out the built-in functions that strings have available to them, we can make use of IPython’s autocompletion feature once again. Type sentence. (including the trailing period) and then hit <TAB>. A menu of functions should appear as so:

    Built-in functions for a string

    @@ -734,8 +808,8 @@

    Messing with Strings
    [19]:
     
    -
    -
    -3
    -
    -
    +
    +
    +3
    +

    Let’s see what the replace function does. IPython provides a great utility for looking up the documentation for a function by simply putting two question marks after the function name. For example:

    Looking up documentation for a function

    @@ -755,8 +829,8 @@

    Messing with Strings
    [20]:
     
    -
    -
    -'Who would have thought that we were computers all along?'
    -
    -
    +
    +
    +'Who would have thought that we were computers all along?'
    +
    - -
    -[-1, 0.3333333333333333, 20, 6]
    -
    -
    +
    +
    +[-1, 0.3333333333333333, 20, 6]
    +

    A list can contain any type of Python object; it can store a mix of numbers, strings, other lists, and much more!

    You can join lists together, which is known as concatenation.

    Like a string, a list is sequential in nature and we can access the items in a list by specifying its position in the sequence. This is known as “indexing” the list; the index of the first item in a sequence is always 0.

    Negative integers can be used to index relative to the end (right-side) of the list.

    You can change an entry in a list by assigning it to a new value.

    We can also access multiple items in a list at once by slicing the list, like we did with the string.

    This slice can be used to update the first three entries of the list

    To wrap up this quick demo, let’s append an new entry to the end of this list.

    @@ -1041,29 +1115,29 @@

    Playing with Lists - - - - - - + + -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -1072,7 +1146,6 @@

    Playing with Lists jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.ipynb b/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.ipynb new file mode 100644 index 00000000..b514c4ed --- /dev/null +++ b/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.ipynb @@ -0,0 +1,1203 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Informal Introduction to Python, Difficulty: Easy, Category: Tutorial\n", + " :keywords: python, installation, script, introduction, ipython, console, quick introduction" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# An Informal Introduction to Python\n", + "\n", + "
    \n", + "\n", + "**Before You Start This Section**: \n", + "\n", + "In the following section we will be using IPython or a Jupyter notebook to run our code.\n", + "Presently, there is an incompatibility with these programs and a Python package called `jedi`, which typically is responsible for performing auto-completions in our code (when prompted by hitting ``, which we will be doing below).\n", + "It is really useful!\n", + "\n", + "First, let's check to see if we have an incompatible version of `jedi` installed.\n", + "In your terminal (before starting a Python/IPython/Jupyter session), run\n", + " \n", + "```\n", + "conda list\n", + "```\n", + "\n", + "And look for the line that starts with `jedi`\n", + " \n", + "```\n", + "jedi 0.18.0\n", + "```\n", + "\n", + "If you see that you have version `0.18.0` installed (as above), then you will want to downgrade it.\n", + "In the same terminal, run the following command\n", + "\n", + "```\n", + "conda install jedi=0.17.2\n", + "```\n", + "You should be all set once you have followed the prompts and the installation has completed!\n", + " \n", + "Note that you will need to repeat this process if you [create a new conda environment](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html#A-Brief-Introduction-to-Conda-Environments) with IPython/Jupter installed in it.\n", + "
    \n", + "\n", + "Now that you have the Anaconda distribution of Python installed on your machine, let's write some simple Python code! We are going to forego writing a full Python script for now, and instead make use of a convenient tool for doing quick code scratchwork. The IPython console was installed as a part of Anaconda; it will allow us to build incrementally off of snippets of code, instead of having to execute an entire script all at once. \n", + "\n", + "Let's open an IPython console. Open your terminal if you are a Mac/Linux user, or start `cmd.exe` if you are a Windows user. Now type `ipython` into the console and hit ``. You should see the following display on your screen:\n", + "\n", + "![IPython console example](attachments/ipython_0.PNG)\n", + "\n", + "We can type small pieces of Python code into this console, and then simply hit `` to have the CPython interpreter execute our code immediately within the IPython console!\n", + "\n", + "Let's acquaint ourselves with Python's numbers, strings, and lists. In doing so, we will learn about the Python standard library, and how to make use of its modules, like the math module. IPython's autocompletion and documentation-display utilities will provide a nice means for exploring the library and the functionality built into the different types of Python objects. A quick glimpse at Python's strings and lists will hint at the common interface Python provides for working with sequences of objects, while highlighting some of the nice features of these all-important data types. \n", + "\n", + "## Dabbling with Numbers \n", + "Time to execute some Python code that performs simple arithmetic. Typing `2 + 3` into the IPython console and hitting the `` key, you should see the following input and output in the console:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.361255Z", + "iopub.status.busy": "2021-01-31T21:47:25.361255Z", + "iopub.status.idle": "2021-01-31T21:47:25.378259Z", + "shell.execute_reply": "2021-01-31T21:47:25.378259Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "2 + 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This console session is persistent, meaning that we can define a variable and then reference it in our code later on within this console session. Let's define the variable `x` and assign it to the integer `10` (please follow along in the IPython console)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.382261Z", + "iopub.status.busy": "2021-01-31T21:47:25.381257Z", + "iopub.status.idle": "2021-01-31T21:47:25.394256Z", + "shell.execute_reply": "2021-01-31T21:47:25.395259Z" + } + }, + "outputs": [], + "source": [ + "x = 10" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can check the contents of `x` in this console by simply entering `x` in the next line and hitting ``:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.399257Z", + "iopub.status.busy": "2021-01-31T21:47:25.398260Z", + "iopub.status.idle": "2021-01-31T21:47:25.409258Z", + "shell.execute_reply": "2021-01-31T21:47:25.410259Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's use `x` in a quadratic equation $x^{2} + 2x + 3$, and compute this total." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.414258Z", + "iopub.status.busy": "2021-01-31T21:47:25.413258Z", + "iopub.status.idle": "2021-01-31T21:47:25.425259Z", + "shell.execute_reply": "2021-01-31T21:47:25.425259Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "123" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x**2 + 2*x + 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Python's \"standard library\", the various tools and functions that come packaged as part of the core language, includes plenty of familiar mathematical functions. As a matter of organization, Python stores these mathematical functions away in a module named \"math\". To make use of this math module, we must import it into our code. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.428260Z", + "iopub.status.busy": "2021-01-31T21:47:25.428260Z", + "iopub.status.idle": "2021-01-31T21:47:25.440256Z", + "shell.execute_reply": "2021-01-31T21:47:25.440256Z" + } + }, + "outputs": [], + "source": [ + "import math" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Having imported it, the term `math` now refers to the math module in our code. IPython provides a nice way for us to see a list of all the functions that are provided by the math module. To utilize this, type into the console `math.` (note the trailing period) and then hit ``. You should see this list appear:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Displaying the contents of the math module](attachments/ipython_math.PNG)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In general, hitting `` will cue IPython to try to autocomplete code for you. This menu displays all the valid things that you could type after `math.`. Looking at the functions starting with \"s\", we see `sqrt()`. This is the square root function. To see autocompletion in action, type `math.sq` and then hit ``. You should see the code autocomplete to `math.sqrt`.\n", + "\n", + "Let's use this function to compute $\\sqrt{100}$:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.444260Z", + "iopub.status.busy": "2021-01-31T21:47:25.444260Z", + "iopub.status.idle": "2021-01-31T21:47:25.455258Z", + "shell.execute_reply": "2021-01-31T21:47:25.455258Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10.0" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "math.sqrt(100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You might wonder why the result displayed as `10.0` and not simply as `10`; in Module 2 we will see that these are two different *types* of numbers in the Python language. The former is called a floating-point number, indicating the presence of its decimal point, whereas the latter is an integer. The `math.sqrt` function is defined such that it always returns its results as floating-point numbers.\n", + "\n", + "In the case that we want to make frequent use of a certain function from the math module, it'd be nice to avoid having to type out the math module prefix, `math.`, repeatedly. We can accomplish this by importing an individual function from the math module. Let's import the factorial function from the math module." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.459259Z", + "iopub.status.busy": "2021-01-31T21:47:25.458259Z", + "iopub.status.idle": "2021-01-31T21:47:25.472259Z", + "shell.execute_reply": "2021-01-31T21:47:25.471259Z" + } + }, + "outputs": [], + "source": [ + "from math import factorial" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now make use of the `factorial` function in our code. Recall that 5-factorial is $5! = 5\\times 4\\times 3\\times 2\\times 1 = 120$ " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.475260Z", + "iopub.status.busy": "2021-01-31T21:47:25.475260Z", + "iopub.status.idle": "2021-01-31T21:47:25.487257Z", + "shell.execute_reply": "2021-01-31T21:47:25.488257Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "120" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Messing with Strings\n", + "In the context of code, written text is referred to as a string of characters, or string for short. Python is an excellent language for doing text-processing work as it provides many convenient, efficient functions for working with strings. \n", + "\n", + "To begin, we simply form a string by typing characters between quotation marks:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.492257Z", + "iopub.status.busy": "2021-01-31T21:47:25.491256Z", + "iopub.status.idle": "2021-01-31T21:47:25.503256Z", + "shell.execute_reply": "2021-01-31T21:47:25.503256Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'the cat in the hat'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"the cat in the hat\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Single quotes also work:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.506259Z", + "iopub.status.busy": "2021-01-31T21:47:25.506259Z", + "iopub.status.idle": "2021-01-31T21:47:25.519257Z", + "shell.execute_reply": "2021-01-31T21:47:25.519257Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'the dog in the sash'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "'the dog in the sash'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you use single quotes to form a string, then that string is able to contain the double-quote as a character (and vice versa):" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.522258Z", + "iopub.status.busy": "2021-01-31T21:47:25.522258Z", + "iopub.status.idle": "2021-01-31T21:47:25.536257Z", + "shell.execute_reply": "2021-01-31T21:47:25.535257Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'He picked up the phone, \"Hello? What do you want?\" Bob was a rather impolite dude.'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "'He picked up the phone, \"Hello? What do you want?\" Bob was a rather impolite dude.'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are designated special characters that allow us to affect the way a string is formatted when it is printed to the string. For example, if `\\n` ever occurs in a string, it is treated as a single character that indicates a line-break. This will only manifest if such a string is fed to the built-in `print` function, which informs the computer to print text to a user's screen.\n", + "\n", + "Let's create a string that will display as three separate lines, when printed to the screen." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.539258Z", + "iopub.status.busy": "2021-01-31T21:47:25.539258Z", + "iopub.status.idle": "2021-01-31T21:47:25.551257Z", + "shell.execute_reply": "2021-01-31T21:47:25.551257Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I like to talk to dogs.\n", + "I like to talk to cats.\n", + "What's my deal?\n" + ] + } + ], + "source": [ + "print(\"I like to talk to dogs.\\nI like to talk to cats.\\nWhat's my deal?\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Of course, strings are useful beyond merely containing text! Let's explore some ways to manipulate strings. First, we'll write a string and assign it to a variable named `sentence`:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.554257Z", + "iopub.status.busy": "2021-01-31T21:47:25.554257Z", + "iopub.status.idle": "2021-01-31T21:47:25.565256Z", + "shell.execute_reply": "2021-01-31T21:47:25.566258Z" + } + }, + "outputs": [], + "source": [ + "sentence = \"Who would have thought that we were robots all along?\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see how many characters are in this string by checking the \"length\" of this sequence of characters:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.569257Z", + "iopub.status.busy": "2021-01-31T21:47:25.569257Z", + "iopub.status.idle": "2021-01-31T21:47:25.582259Z", + "shell.execute_reply": "2021-01-31T21:47:25.582259Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "53" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(sentence)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can access the first 4 characters in the string, the last 6 characters, or a few characters in the middle by \"slicing\" the string:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.585257Z", + "iopub.status.busy": "2021-01-31T21:47:25.585257Z", + "iopub.status.idle": "2021-01-31T21:47:25.597257Z", + "shell.execute_reply": "2021-01-31T21:47:25.597257Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Who '" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sentence[:4]" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.600256Z", + "iopub.status.busy": "2021-01-31T21:47:25.600256Z", + "iopub.status.idle": "2021-01-31T21:47:25.613258Z", + "shell.execute_reply": "2021-01-31T21:47:25.613258Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'along?'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sentence[-6:]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.617260Z", + "iopub.status.busy": "2021-01-31T21:47:25.617260Z", + "iopub.status.idle": "2021-01-31T21:47:25.629260Z", + "shell.execute_reply": "2021-01-31T21:47:25.630259Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'ould have thought'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sentence[5:22]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also check to see if some other string is contained within our string. Is the string `\"robot\"` contained within `sentence`?" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.635262Z", + "iopub.status.busy": "2021-01-31T21:47:25.634258Z", + "iopub.status.idle": "2021-01-31T21:47:25.645257Z", + "shell.execute_reply": "2021-01-31T21:47:25.646262Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"robot\" in sentence" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As a quick way to check out the built-in functions that strings have available to them, we can make use of IPython's autocompletion feature once again. Type `sentence.` (including the trailing period) and then hit ``. A menu of functions should appear as so:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Built-in functions for a string](attachments/ipython_string.PNG)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's use the count function to tally the number of lowercase w's in `sentence`" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.652260Z", + "iopub.status.busy": "2021-01-31T21:47:25.651257Z", + "iopub.status.idle": "2021-01-31T21:47:25.661259Z", + "shell.execute_reply": "2021-01-31T21:47:25.662258Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sentence.count('w')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see what the replace function does. IPython provides a great utility for looking up the documentation for a function by simply putting two question marks after the function name. For example:\n", + "\n", + "![Looking up documentation for a function](attachments/ipython_doc1.PNG)\n", + "\n", + "Putting our newfound understanding of the string's replace function, let's replace \"robot\" with \"computer\":" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.667257Z", + "iopub.status.busy": "2021-01-31T21:47:25.666257Z", + "iopub.status.idle": "2021-01-31T21:47:25.677257Z", + "shell.execute_reply": "2021-01-31T21:47:25.676259Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Who would have thought that we were computers all along?'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sentence.replace(\"robot\", \"computer\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Playing with Lists\n", + "A list is one of several types of containers that are built into Python's standard library. It can hold a sequence of Python objects. We can create a list of numbers: " + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.683257Z", + "iopub.status.busy": "2021-01-31T21:47:25.683257Z", + "iopub.status.idle": "2021-01-31T21:47:25.692258Z", + "shell.execute_reply": "2021-01-31T21:47:25.693257Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[-1, 0.3333333333333333, 20, 6]" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[-1, 1/3, 10*2, 7-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A list can contain any type of Python object; it can store a mix of numbers, strings, other lists, and much more!" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.697256Z", + "iopub.status.busy": "2021-01-31T21:47:25.697256Z", + "iopub.status.idle": "2021-01-31T21:47:25.708258Z", + "shell.execute_reply": "2021-01-31T21:47:25.707256Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 'a', 0.5, 'apple and orange']" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[1, 2, \"a\", 0.5, \"apple and orange\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can join lists together, which is known as concatenation." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.712258Z", + "iopub.status.busy": "2021-01-31T21:47:25.711257Z", + "iopub.status.idle": "2021-01-31T21:47:25.723257Z", + "shell.execute_reply": "2021-01-31T21:47:25.723257Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 'a', 'b', 'c']" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[1, 2, 3] + [\"a\", \"b\", \"c\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Like a string, a list is sequential in nature and we can access the items in a list by specifying its position in the sequence. This is known as \"indexing\" the list; the index of the first item in a sequence is always 0." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.727258Z", + "iopub.status.busy": "2021-01-31T21:47:25.726259Z", + "iopub.status.idle": "2021-01-31T21:47:25.739257Z", + "shell.execute_reply": "2021-01-31T21:47:25.740256Z" + } + }, + "outputs": [], + "source": [ + "my_list = [10, 20, 30, 40, 50, 60]" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.745258Z", + "iopub.status.busy": "2021-01-31T21:47:25.744257Z", + "iopub.status.idle": "2021-01-31T21:47:25.757260Z", + "shell.execute_reply": "2021-01-31T21:47:25.756259Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_list[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.765259Z", + "iopub.status.busy": "2021-01-31T21:47:25.764257Z", + "iopub.status.idle": "2021-01-31T21:47:25.770258Z", + "shell.execute_reply": "2021-01-31T21:47:25.771258Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "20" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_list[1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Negative integers can be used to index relative to the end (right-side) of the list." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.777259Z", + "iopub.status.busy": "2021-01-31T21:47:25.776259Z", + "iopub.status.idle": "2021-01-31T21:47:25.785256Z", + "shell.execute_reply": "2021-01-31T21:47:25.785256Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "60" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_list[-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can change an entry in a list by assigning it to a new value." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.790257Z", + "iopub.status.busy": "2021-01-31T21:47:25.789257Z", + "iopub.status.idle": "2021-01-31T21:47:25.801257Z", + "shell.execute_reply": "2021-01-31T21:47:25.802256Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "-5 in my_list" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.806257Z", + "iopub.status.busy": "2021-01-31T21:47:25.805257Z", + "iopub.status.idle": "2021-01-31T21:47:25.817257Z", + "shell.execute_reply": "2021-01-31T21:47:25.816256Z" + } + }, + "outputs": [], + "source": [ + "my_list[1] = -5" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.821257Z", + "iopub.status.busy": "2021-01-31T21:47:25.820256Z", + "iopub.status.idle": "2021-01-31T21:47:25.831257Z", + "shell.execute_reply": "2021-01-31T21:47:25.831257Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[10, -5, 30, 40, 50, 60]" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_list" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.835259Z", + "iopub.status.busy": "2021-01-31T21:47:25.834256Z", + "iopub.status.idle": "2021-01-31T21:47:25.848257Z", + "shell.execute_reply": "2021-01-31T21:47:25.847256Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "-5 in my_list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also access multiple items in a list at once by slicing the list, like we did with the string." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.852256Z", + "iopub.status.busy": "2021-01-31T21:47:25.851257Z", + "iopub.status.idle": "2021-01-31T21:47:25.862256Z", + "shell.execute_reply": "2021-01-31T21:47:25.862256Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[10, -5, 30]" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_list[:3]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This slice can be used to update the first three entries of the list" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.866257Z", + "iopub.status.busy": "2021-01-31T21:47:25.865256Z", + "iopub.status.idle": "2021-01-31T21:47:25.876256Z", + "shell.execute_reply": "2021-01-31T21:47:25.877258Z" + } + }, + "outputs": [], + "source": [ + "my_list[:3] = \"abc\"" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.880257Z", + "iopub.status.busy": "2021-01-31T21:47:25.879256Z", + "iopub.status.idle": "2021-01-31T21:47:25.893255Z", + "shell.execute_reply": "2021-01-31T21:47:25.893255Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['a', 'b', 'c', 40, 50, 60]" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To wrap up this quick demo, let's append an new entry to the end of this list." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.896257Z", + "iopub.status.busy": "2021-01-31T21:47:25.895256Z", + "iopub.status.idle": "2021-01-31T21:47:25.909260Z", + "shell.execute_reply": "2021-01-31T21:47:25.909260Z" + } + }, + "outputs": [], + "source": [ + "my_list.append(\"moo\")" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:25.913256Z", + "iopub.status.busy": "2021-01-31T21:47:25.913256Z", + "iopub.status.idle": "2021-01-31T21:47:25.925256Z", + "shell.execute_reply": "2021-01-31T21:47:25.925256Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['a', 'b', 'c', 40, 50, 60, 'moo']" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_list" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module1_GettingStartedWithPython/Installing_Python.html b/docs_backup/Module1_GettingStartedWithPython/Installing_Python.html index 75e705e7..b1293470 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Installing_Python.html +++ b/docs_backup/Module1_GettingStartedWithPython/Installing_Python.html @@ -1,45 +1,49 @@ - - + - + - + Installing Python — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ + + @@ -154,11 +160,13 @@ + +
      -
    • Docs »
    • +
    • »
    • Module 1: Getting Started with Python »
    • @@ -167,7 +175,7 @@
    • - + View page source @@ -186,13 +194,13 @@ /* CSS overrides for sphinx_rtd_theme */ /* 24px margin */ -.nbinput.nblast, -.nboutput.nblast { +.nbinput.nblast.container, +.nboutput.nblast.container { margin-bottom: 19px; /* padding has already 5px */ } /* ... except between code cells! */ -.nblast + .nbinput { +.nblast.container + .nbinput.container { margin-top: -19px; } @@ -209,10 +217,10 @@

      Installing Python

      Without further ado, we now provide instructions for installing Python and other useful Python libraries on your machine via the Anaconda platform. Installing the Anaconda platform will install the following:

        -
      • Python; specifically the CPython interpreter that we discussed in the previous section.
      • -
      • A number of useful Python packages, like matplotlib, NumPy, and SciPy.
      • -
      • Jupyter, which provides an interactive “notebook” environment for prototyping code.
      • -
      • conda: a package manager that will allow you to install and update Python and additional Python packages, while handling all compatibility issues for you.
      • +
      • Python; specifically the CPython interpreter that we discussed in the previous section.

      • +
      • A number of useful Python packages, like matplotlib, NumPy, and SciPy.

      • +
      • Jupyter, which provides an interactive “notebook” environment for prototyping code.

      • +
      • conda: a package manager that will allow you to install and update Python and additional Python packages, while handling all compatibility issues for you.

      Note that installing Python via Anaconda will not break any other installations of Python that already exist on your computer. See What did this just do to my computer? for more details.

      Some of the packages provided by Anaconda, like NumPy, have been optimized and will run significantly faster than if you installed them manually.

      @@ -223,19 +231,19 @@

      Installing Python

      Installing Anaconda

        -
      1. Navigate to this page, and click the “Download” button for Python 3.
      2. -
      3. After the download is complete, begin the installation process. There will be an installation option: Add Anaconda to the system PATH environment variable; we advise you to enable this installation option (advanced users: see below for caveats).
      4. -
      5. Complete the 30 minute “Getting Started” tutorial to familiarize yourself with conda. This is very important!
      6. +
      7. Navigate to this page, and click the “Download” button for Python 3.

      8. +
      9. After the download is complete, begin the installation process. There will be an installation option: Add Anaconda to the system PATH environment variable; we advise you to enable this installation option (advanced users: see below for caveats).

      10. +
      11. Complete the 30 minute “Getting Started” tutorial to familiarize yourself with conda. This is very important!

      You will need to know how to open a terminal (cmd.exe for Windows users) on your computer, and how to navigate between directories in the terminal. If you do not know how to do this, read a ‘how-to’ for whatever operating system you are using.

    What did this just do to my computer?

    -

    This created a directory called Anaconda3 (or some variant of this) on your computer, which contains all of the files associated with the CPython interpreter, all of the modules in Python’s standard library, the aforementioned 3rd party packages that come as part of the Anaconda distribution (e.g. NumPy, SciPy, Jupyter, iPython), and the conda package manager. It also contains the executable files for all of these applications. The default install location for Anaconda is:

    +

    This created a directory called Anaconda3 (or some variant of this) on your computer, which contains all of the files associated with the CPython interpreter, all of the modules in Python’s standard library, the aforementioned 3rd party packages that come as part of the Anaconda distribution (e.g. NumPy, SciPy, Jupyter, iPython), and the conda package manager. It also contains the executable files for all of these applications. The default install location for Anaconda is:

      -
    • (Linux): /home/<your_username>/Anaconda3
    • -
    • (Windows): C:\Users\<your_username>\Anaconda3
    • -
    • (Mac): /Users/<your_username>/Anaconda3
    • +
    • (Linux): /home/<your_username>/Anaconda3

    • +
    • (Windows): C:\Users\<your_username>\Anaconda3

    • +
    • (Mac): /Users/<your_username>/Anaconda3

    If you followed the install instructions as specified above, then the Anaconda-installer also placed this directory in your system’s “path”. Let’s briefly discuss what this means. Your system’s path is simply a list of directories. Whenever you execute any command in your computer’s terminal, the computer will quickly search through the directories that are specified in the path for an executable with that name; it will execute the first such executable that it finds. Thus, by placing the Anaconda3 directory at the beginning of your path, the Anaconda-installer has ensured that your computer will prioritize Anaconda’s python executable over any other installations of Python on your computer, because it will find that executable first.

    @@ -253,8 +261,9 @@

    What did this just do to my computer?

    conda is not only a package manager, but also a powerful environment manager. Let’s take a moment to motivate a common use case for environment management before we dive into what it actually is:

    -
    It is expected and encouraged that you work through Python Like You Mean It using the latest version of Python (Python 3.X). That being said, it is not uncommon to encounter courses and projects that require you to use Python 2.7, which is a dead version of the language. Is there a simple and sane way to switch back and forth between working in Python 3 and Python 2.7 environments? Yes! Utilizing conda environments is a perfect way to solve this problem.
    -

    Assuming that your initial installation of Anaconda contained Python 3, then your root (i.e. default) conda environment is that Python 3 environment. You can now create a conda environment that instead includes Python 2.7 and all of the 3rd party packages that come with Anaconda. Execute the following command in your terminal:

    +

    It is expected and encouraged that you work through Python Like You Mean It using the latest version of Python (Python 3.X). That being said, it is not uncommon to encounter courses and projects that require you to use Python 2.7, which is a dead version of the language. Is there a simple and sane way to switch back and forth between working in Python 3 and Python 2.7 environments? Yes! Utilizing conda environments is a perfect way to solve this problem.

    +
    +

    Assuming that your initial installation of Anaconda contained Python 3, then your root (i.e. default) conda environment is that Python 3 environment. You can now create a conda environment that instead includes Python 2.7 and all of the 3rd party packages that come with Anaconda. Execute the following command in your terminal:

    conda create -n py27 python=2.7 anaconda
     
    @@ -279,29 +288,29 @@

    A Brief Introduction to Conda Environments - - - - - - + +

    -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -310,7 +319,6 @@

    A Brief Introduction to Conda Environments jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module1_GettingStartedWithPython/Installing_Python.ipynb b/docs_backup/Module1_GettingStartedWithPython/Installing_Python.ipynb new file mode 100644 index 00000000..e0e897a3 --- /dev/null +++ b/docs_backup/Module1_GettingStartedWithPython/Installing_Python.ipynb @@ -0,0 +1,125 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Installing Python with Anaconda, Difficulty: Easy, Category: Tutorial\n", + " :keywords: python, anaconda, instructions, environments, beginner, data science, introduction" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installing Python\n", + "\n", + "Without further ado, we now provide instructions for installing Python and other useful Python libraries on your machine via the Anaconda platform. Installing the Anaconda platform will install the following:\n", + "\n", + " - Python; specifically the CPython interpreter that we discussed in the previous section.\n", + " - A number of useful Python packages, like matplotlib, NumPy, and SciPy.\n", + " - Jupyter, which provides an interactive \"notebook\" environment for prototyping code.\n", + " - conda: a package manager that will allow you to install and update Python and additional Python packages, while handling all compatibility issues for you.\n", + " \n", + "Note that installing Python via Anaconda will **not** break any other installations of Python that already exist on your computer. See [What did this just do to my computer?](#What-did-this-just-do-to-my-computer?) for more details.\n", + "\n", + "Some of the packages provided by Anaconda, like NumPy, have been [optimized](https://docs.anaconda.com/mkl-optimizations/) and will run significantly faster than if you installed them manually.\n", + "\n", + "
    \n", + "\n", + "**Takeaway**: \n", + "\n", + "\"Anaconda\" is a collection of the CPython interpreter and a number of very popular Python libraries for doing data science-related work. It also provides a package manager for downloading/updating Python packages, and an environment manager for maintaining independent installations of Python side-by-side. \n", + "
    \n", + "\n", + "### Installing Anaconda\n", + "\n", + "1. Navigate to [this page](https://www.anaconda.com/download/), and click the \"Download\" button for **Python 3**.\n", + "2. After the download is complete, begin the installation process. There will be an installation option: `Add Anaconda to the system PATH environment variable`; we advise you to **enable** this installation option (advanced users: see below for caveats).\n", + "3. Complete the 30 minute [\"Getting Started\"](https://conda.io/projects/conda/en/latest/user-guide/getting-started.html) tutorial to familiarize yourself with `conda`. This is very important!\n", + "\n", + "You will need to know how to open a terminal (cmd.exe for Windows users) on your computer, and how to navigate between directories in the terminal. If you do not know how to do this, read a 'how-to' for whatever operating system you are using." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### What did this just do to my computer?\n", + "\n", + "This created a directory called `Anaconda3` (or some variant of this) on your computer, which contains all of the files associated with the CPython interpreter, all of the modules in Python's standard library, the aforementioned 3rd party packages that come as part of the Anaconda distribution (e.g. NumPy, SciPy, Jupyter, iPython), and the `conda` package manager. It also contains the executable files for all of these applications. The default install location for Anaconda is:\n", + "\n", + "- (Linux): `/home//Anaconda3`\n", + "- (Windows): `C:\\Users\\\\Anaconda3`\n", + "- (Mac): `/Users//Anaconda3`\n", + "\n", + "If you followed the install instructions as specified above, then the Anaconda-installer also *placed this directory in your system's \"path\"*. Let's briefly discuss what this means. Your system's path is simply a list of directories. Whenever you execute any command in your computer's terminal, the computer will quickly search through the directories that are specified in the path for an executable with that name; *it will execute the first such executable that it finds*. Thus, by placing the `Anaconda3` directory at the beginning of your path, the Anaconda-installer has ensured that your computer will prioritize Anaconda's python executable over any other installations of Python on your computer, because it will find that executable first. \n", + "\n", + "For Linux and Mac users, it is very likely that your system already has a version of Python installed. *It is critical that you do not attempt to uninstall, remove, or change this native version of Python*. Those operating systems use their native versions of Python to perform some of their services. Those services are written such that they will directly invoke the Python executable that came with the operating system - they will not accidentally run the version of Python that came with Anaconda. At the end of the day you can simply install Anaconda without worrying about any of these details. \n", + "\n", + "**An important note for people who code in languages other than Python:** Anaconda has its own `lib` and `bin` directories that it uses to store library files and binary files as needed. While this makes it very easy for users to install sophisticated Python packages that leverage C-libraries without having to manually build those libraries, it also means that your system will prioritize Anaconda's files before your system-level files. This can be a big problem if you work in languages other than Python.\n", + "\n", + "The simple solution to this is to *not* have the Anaconda-installer include Anaconda in your path. Instead, you can create an alias that will allow you manually prepend Anaconda to your path. E.g., in Linux you can add the following alias to your `~/.bashrc` file:\n", + "\n", + "```shell\n", + "alias anaconda=\"export PATH=/home//anaconda3/bin:$PATH\"\n", + "```\n", + "\n", + "With this alias in place, you can simply invoke the command `anaconda` in your terminal to place Anaconda at the beginning of your path for that terminal session. \n", + "\n", + "### A Brief Introduction to Conda Environments\n", + "\n", + "`conda` is not only a package manager, but also a powerful environment manager. Let's take a moment to motivate a common use case for environment management before we dive into what it actually is:\n", + "\n", + ">It is expected and encouraged that you work through Python Like You Mean It using the latest version of Python (Python 3.X). That being said, it is not uncommon to encounter courses and projects that require you to use Python 2.7, which is a dead version of the language. Is there a simple and sane way to switch back and forth between working in Python 3 and Python 2.7 environments? Yes! Utilizing conda environments is a perfect way to solve this problem.\n", + "\n", + "Assuming that your initial installation of Anaconda contained Python 3, then your *root* (i.e. default) conda environment is that Python 3 environment. You can now create a conda environment that instead includes Python 2.7 and all of the 3rd party packages that come with Anaconda. Execute the following command in your terminal:\n", + "\n", + "```shell\n", + "conda create -n py27 python=2.7 anaconda\n", + "```\n", + "\n", + "Once the installation process is complete, you will be able to activate this environment, which we have named `py27`, by executing the command: \n", + "```shell\n", + "conda activate py27\n", + "``` \n", + "\n", + "Activating an environment simply updates your system's path, swapping the directory `Anaconda3` with `Anaconda3/envs/py27` in this instance. Thus your system will now find the Python 2.7 executable and its associated libraries in its path. Note that this path change only occurs effect in *that particular terminal session*. Any other terminal session will default to the root conda environment. \n", + "\n", + "Having activated your `py27` environment, you can start a vanilla Python console, an iPython console, a Jupyter notebook, run a Python script, etc. These will now all use Python 2.7. You can also use `conda` (and `pip`) to install Python 2.7-compatible packages in this environment. As long as your path points to `Anaconda3/envs/py27` and not `Anaconda3`, it is as if this is the only version of Python that lives on your computer.\n", + "\n", + "Deactivating this environment will return you to the root Python 3 environment. That is, it will switch your path back to including `Anaconda3` instead of `Anaconda3/envs/py27`. Simply invoke the command:\n", + "\n", + "```shell\n", + "conda deactivate\n", + "```\n", + "\n", + "And like that, conda environments give you all of the powers of a necromancer, allowing you to nimbly cross back and forth between the land of the living (Python 3) and the dead (Python 2.7).\n", + "\n", + "Conda environments have more uses than simply switching back and forth between Python 3 and 2. Many people like to make a new conda environment for every major project that they work on, so that they can freely install any dependencies that are needed for that particular project, without worrying about conflicts with their other work. You should be keen on making regular use of conda environments.\n", + "\n", + "It is highly recommended that you take time to read through [this tutorial on managing conda environments](https://conda.io/docs/user-guide/tasks/manage-environments.html)." + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.html b/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.html index a19840ae..fe466831 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.html +++ b/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.html @@ -1,45 +1,49 @@ - - + - + - + Jupyter Notebooks — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ + + @@ -161,11 +167,13 @@ + +
      -
    • Docs »
    • +
    • »
    • Module 1: Getting Started with Python »
    • @@ -174,7 +182,7 @@
    • - + View page source @@ -193,31 +201,45 @@ /* CSS for nbsphinx extension */ /* remove conflicting styling from Sphinx themes */ -div.nbinput, -div.nbinput div.prompt, -div.nbinput div.input_area, -div.nbinput div[class*=highlight], -div.nbinput div[class*=highlight] pre, -div.nboutput, -div.nbinput div.prompt, -div.nbinput div.output_area, -div.nboutput div[class*=highlight], -div.nboutput div[class*=highlight] pre { - background: none; +div.nbinput.container div.prompt *, +div.nboutput.container div.prompt *, +div.nbinput.container div.input_area pre, +div.nboutput.container div.output_area pre, +div.nbinput.container div.input_area .highlight, +div.nboutput.container div.output_area .highlight { border: none; - padding: 0 0; + padding: 0; margin: 0; box-shadow: none; } +div.nbinput.container > div[class*=highlight], +div.nboutput.container > div[class*=highlight] { + margin: 0; +} + +div.nbinput.container div.prompt *, +div.nboutput.container div.prompt * { + background: none; +} + +div.nboutput.container div.output_area .highlight, +div.nboutput.container div.output_area pre { + background: unset; +} + +div.nboutput.container div.output_area div.highlight { + color: unset; /* override Pygments text color */ +} + /* avoid gaps between output lines */ -div.nboutput div[class*=highlight] pre { +div.nboutput.container div[class*=highlight] pre { line-height: normal; } /* input/output containers */ -div.nbinput, -div.nboutput { +div.nbinput.container, +div.nboutput.container { display: -webkit-flex; display: flex; align-items: flex-start; @@ -225,92 +247,104 @@ width: 100%; } @media (max-width: 540px) { - div.nbinput, - div.nboutput { + div.nbinput.container, + div.nboutput.container { flex-direction: column; } } /* input container */ -div.nbinput { +div.nbinput.container { padding-top: 5px; } /* last container */ -div.nblast { +div.nblast.container { padding-bottom: 5px; } /* input prompt */ -div.nbinput div.prompt pre { +div.nbinput.container div.prompt pre { color: #307FC1; } /* output prompt */ -div.nboutput div.prompt pre { +div.nboutput.container div.prompt pre { color: #BF5B3D; } /* all prompts */ -div.nbinput div.prompt, -div.nboutput div.prompt { - min-width: 5ex; - padding-top: 0.4em; - padding-right: 0.4em; - text-align: right; - flex: 0; +div.nbinput.container div.prompt, +div.nboutput.container div.prompt { + width: 4.5ex; + padding-top: 5px; + position: relative; + user-select: none; } + +div.nbinput.container div.prompt > div, +div.nboutput.container div.prompt > div { + position: absolute; + right: 0; + margin-right: 0.3ex; +} + @media (max-width: 540px) { - div.nbinput div.prompt, - div.nboutput div.prompt { + div.nbinput.container div.prompt, + div.nboutput.container div.prompt { + width: unset; text-align: left; padding: 0.4em; } - div.nboutput div.prompt.empty { + div.nboutput.container div.prompt.empty { padding: 0; } + + div.nbinput.container div.prompt > div, + div.nboutput.container div.prompt > div { + position: unset; + } } /* disable scrollbars on prompts */ -div.nbinput div.prompt pre, -div.nboutput div.prompt pre { +div.nbinput.container div.prompt pre, +div.nboutput.container div.prompt pre { overflow: hidden; } /* input/output area */ -div.nbinput div.input_area, -div.nboutput div.output_area { - padding: 0.4em; +div.nbinput.container div.input_area, +div.nboutput.container div.output_area { -webkit-flex: 1; flex: 1; overflow: auto; } @media (max-width: 540px) { - div.nbinput div.input_area, - div.nboutput div.output_area { + div.nbinput.container div.input_area, + div.nboutput.container div.output_area { width: 100%; } } /* input area */ -div.nbinput div.input_area { +div.nbinput.container div.input_area { border: 1px solid #e0e0e0; border-radius: 2px; - background: #f5f5f5; + /*background: #f5f5f5;*/ } /* override MathJax center alignment in output cells */ -div.nboutput div[class*=MathJax] { +div.nboutput.container div[class*=MathJax] { text-align: left !important; } /* override sphinx.ext.imgmath center alignment in output cells */ -div.nboutput div.math p { +div.nboutput.container div.math p { text-align: left; } /* standard error */ -div.nboutput div.output_area.stderr { +div.nboutput.container div.output_area.stderr { background: #fdd; } @@ -354,6 +388,28 @@ .ansi-bold { font-weight: bold; } .ansi-underline { text-decoration: underline; } + +div.nbinput.container div.input_area div[class*=highlight] > pre, +div.nboutput.container div.output_area div[class*=highlight] > pre, +div.nboutput.container div.output_area div[class*=highlight].math, +div.nboutput.container div.output_area.rendered_html, +div.nboutput.container div.output_area > div.output_javascript, +div.nboutput.container div.output_area:not(.rendered_html) > img{ + padding: 5px; + margin: 0; +} + +/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */ +div.nbinput.container div.input_area > div[class^='highlight'], +div.nboutput.container div.output_area > div[class^='highlight']{ + overflow-y: hidden; +} + +/* hide copybtn icon on prompts (needed for 'sphinx_copybutton') */ +.prompt a.copybtn { + display: none; +} + /* Some additional styling taken form the Jupyter notebook CSS */ div.rendered_html table { border: none; @@ -391,13 +447,13 @@ /* CSS overrides for sphinx_rtd_theme */ /* 24px margin */ -.nbinput.nblast, -.nboutput.nblast { +.nbinput.nblast.container, +.nboutput.nblast.container { margin-bottom: 19px; /* padding has already 5px */ } /* ... except between code cells! */ -.nblast + .nbinput { +.nblast.container + .nbinput.container { margin-top: -19px; } @@ -412,6 +468,24 @@

      Jupyter Notebooks

      +
      +

      Before You Start This Section:

      +

      In the following section we will be using IPython or a Jupyter notebook to run our code. Presently, there is an incompatibility with these programs and a Python package called jedi, which typically is responsible for performing auto-completions in our code (when prompted by hitting <TAB>, which we will be doing below). It is really useful!

      +

      First, let’s check to see if we have an incompatible version of jedi installed. In your terminal (before starting a Python/IPython/Jupyter session), run

      +
      conda list
      +
      +
      +

      And look for the line that starts with jedi

      +
      jedi                      0.18.0
      +
      +
      +

      If you see that you have version 0.18.0 installed (as above), then you will want to downgrade it. In the same terminal, run the following command

      +
      conda install jedi=0.17.2
      +
      +
      +

      You should be all set once you have followed the prompts and the installation has completed!

      +

      Note that you will need to repeat this process if you create a new conda environment with IPython/Jupter installed in it.

      +

      In recent years, the Jupyter Notebook has become a massively popular tool for doing research-oriented work in Python and other languages alike. Its emergence marked a paradigm shift in the way data science is conducted.

      A Jupyter notebook is similar to the IPython console, but, instead of only being able to work with a single line of code at a time, you can easily edit and re-execute any code that had been written in a notebook. Furthermore, you can save a notebook, and thus return to it later. Additionally, a notebook provides many terrific features. For instance, you can embed visualizations of data within a notebook, and write blocks of nicely-formatted text (using the Markdown syntax), for presenting and explaining the contents of the notebook.

      @@ -419,8 +493,7 @@

      Jupyter Notebooks

      Jupyter Lab

      -

      Jupyter lab is a new web interface from Project Jupyter that provides a rich web-based interface for managing and running Jupyter notebooks, console terminals, and text editors, all within your browser. Among its useful features and polished user interface - compared to that a Jupyter notebook server - Jupyter lab provides moveable panes for viewing data, images, and code output apart from the rest of the notebook. This is facilitates effective data -science work flows.

      +

      Jupyter lab is a new web interface from Project Jupyter that provides a rich web-based interface for managing and running Jupyter notebooks, console terminals, and text editors, all within your browser. Among its useful features and polished user interface, Jupyter lab provides moveable panes for viewing data, images, and code output apart from the rest of the notebook. This is facilitates effective data science work flows.

      It is recommended that you peruse the Jupyter lab documentation to get a feel for all of its added capabilities.

      The following instructions are laid out for running a Jupyter notebook server. That being said, the process for running a Jupyter lab server and working with notebooks therein is nearly identical. Both Jupyter notebook and Jupyter lab should already be installed via Anaconda.

      @@ -467,12 +540,12 @@

      An Example Notebook
      [1]:
       

    - - - -
    -# plot the sinc-function and its derivative
    -fig, ax = plt.subplots()
    -ax.plot(x, f, color="red", label=r"$sinc(x)$")
    -ax.plot(x, df, color="blue", ls="--", label=r"$\frac{d(sinc(x))}{dx}$")
    +
    +# plot the sinc-function and its derivative
    +fig, ax = plt.subplots()
    +ax.plot(x, f, color="red", label=r"$sinc(x)$")
    +ax.plot(x, df, color="blue", ls="--", label=r"$\frac{d(sinc(x))}{dx}$")
     
     
    -ax.set_title("Example Notebook Plot")
    -ax.set_xlabel(r"$x$ [radians]")
    +ax.set_title("Example Notebook Plot")
    +ax.set_xlabel(r"$x$ [radians]")
     
    -ax.grid(True)
    -ax.legend();
    +ax.grid(True)
    +ax.legend();
     
    +
    +
    [4]:
    +
    +
    +
    +
    +<matplotlib.legend.Legend at 0x2a496ed7f10>
    +
    +
    -../_images/Module1_GettingStartedWithPython_Jupyter_Notebooks_10_0.png +../_images/Module1_GettingStartedWithPython_Jupyter_Notebooks_10_1.png

    Notice that this notebook interface is great for making adjustments to this plot. You can easily change the color or line-style of the plot and redraw it without having to recompute the functions. You simply re-execute the cell containing the plot code. This is especially nice when the numerical computations required to generate the curves are costly.

    @@ -536,18 +618,18 @@

    Familiarizing Yourself with Jupyter Notebooks<ESC> to activate)

    When in command mode, you can use keyboard shortcuts to create/delete/cut/paste notebook cells, and to change a cell’s type between code and markdown modes. Your selected cell will be surrounded by a blue border when you are in command mode. For a complete listing of keyboard shortcuts, toward the top of the notebook click Help > Keyboard Shortcuts. The most critical shortcuts are:

      -
    • create a new cell above the current cell: a
    • -
    • create a new cell below the current cell: b
    • -
    • delete the current cell: dd
    • -
    • restart the notebook kernel (kill all executions and erase all defined variables): 00
    • -
    • change the current cell’s type to “Code”: y
    • -
    • change the current cell’s type to “Markdown”: m
    • +
    • create a new cell above the current cell: a

    • +
    • create a new cell below the current cell: b

    • +
    • delete the current cell: dd

    • +
    • restart the notebook kernel (kill all executions and erase all defined variables): 00

    • +
    • change the current cell’s type to “Code”: y

    • +
    • change the current cell’s type to “Markdown”: m

    Edit Mode (Press <Enter> to activate)

    Edit mode simply permits you to type text into the selected cell. When in edit mode, the current cell will be surrounded by a green border. There are two commands for executing a cell:

      -
    • execute current cell: <CTRL>+<ENTER>
    • -
    • execute current cell and then create a new cell below: <SHIFT>+<ENTER>
    • +
    • execute current cell: <CTRL>+<ENTER>

    • +
    • execute current cell and then create a new cell below: <SHIFT>+<ENTER>

    By default, a cell will be a code-type cell, meaning that its content will be formatted and executed as Python code. Just as you saw when using the IPython notebook, <TAB> can be used to perform autocomplete. Additionally, when your cursor is on the name of a Python function in your code, <SHIFT>+<TAB> will bring up a small window with the function’s documentations string. This is very useful.

    Looking up code documentation in a notebook

    @@ -564,12 +646,12 @@

    Markdown Cells

    The Jupyter Notebook does not work exclusively with Python. A “kernel” can be developed in order to provide support for a given programming language in Jupyter. Indeed, kernels for several prominent programming languages are being developed for use with Jupyter:

    The ever-growing list of available kernels for use with Jupyter can be found here. It should be noted that these efforts are not all equally mature. For instance, whereas the Python and Julia kernels are robust, the Haskell kernel cannot run natively on Windows machines, and the C++ kernel is still in early development, as of writing this.

    @@ -585,29 +667,29 @@

    Jupyter Notebook Support in Visual Studio Code - - - - - - + + -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -616,7 +698,6 @@

    Jupyter Notebook Support in Visual Studio Code jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.ipynb b/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.ipynb new file mode 100644 index 00000000..c1984b1c --- /dev/null +++ b/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.ipynb @@ -0,0 +1,360 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Jupyter notebooks, Difficulty: Easy, Category: Tutorial\n", + " :keywords: jupyter, jupyter lab, notebook, kernel, basics, server, console, plot, beginner, data science" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Jupyter Notebooks\n", + "\n", + "
    \n", + "\n", + "**Before You Start This Section**: \n", + "\n", + "In the following section we will be using IPython or a Jupyter notebook to run our code.\n", + "Presently, there is an incompatibility with these programs and a Python package called `jedi`, which typically is responsible for performing auto-completions in our code (when prompted by hitting ``, which we will be doing below).\n", + "It is really useful!\n", + "\n", + "First, let's check to see if we have an incompatible version of `jedi` installed.\n", + "In your terminal (before starting a Python/IPython/Jupyter session), run\n", + " \n", + "```\n", + "conda list\n", + "```\n", + "\n", + "And look for the line that starts with `jedi`\n", + " \n", + "```\n", + "jedi 0.18.0\n", + "```\n", + "\n", + "If you see that you have version `0.18.0` installed (as above), then you will want to downgrade it.\n", + "In the same terminal, run the following command\n", + "\n", + "```\n", + "conda install jedi=0.17.2\n", + "```\n", + "You should be all set once you have followed the prompts and the installation has completed!\n", + " \n", + "Note that you will need to repeat this process if you [create a new conda environment](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html#A-Brief-Introduction-to-Conda-Environments) with IPython/Jupter installed in it.\n", + "
    \n", + "\n", + "In recent years, the Jupyter Notebook has become a massively popular tool for doing research-oriented work in Python and other languages alike.\n", + "Its emergence marked a paradigm shift in the way data science is conducted. \n", + "\n", + "A Jupyter notebook is similar to the IPython console, but, instead of only being able to work with a single line of code at a time, you can easily edit and re-execute *any* code that had been written in a notebook. Furthermore, you can save a notebook, and thus return to it later.\n", + "Additionally, a notebook provides many terrific features. For instance, you can embed visualizations of data within a notebook, and write blocks of nicely-formatted text (using the [Markdown syntax](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)), for presenting and explaining the contents of the notebook. \n", + "\n", + "In this way, the Jupyter Notebook stands out as an excellent tool for many practical applications. You could work on a notebook while you are working through sections of this website, for instance, testing out snippets of code, and answering reading-comprehension questions as you proceed through the text, and using markdown-headers to visually separate different portions of the notebook. When I do research, I am always creating Jupyter notebooks in which I write code that analyzes data, I plot various results, presented in different ways, and I write detailed markdown-text blocks to document my work. The end result is something that I can share with my labmates, and easily revisit months later without having to struggle to recall what I had done.\n", + "\n", + "## Jupyter Lab\n", + "[Jupyter lab](https://jupyterlab.readthedocs.io/) is a new web interface from Project Jupyter that provides a rich web-based interface for managing and running Jupyter notebooks, console terminals, and text editors, all within your browser.\n", + "Among its useful features and polished user interface, Jupyter lab provides moveable panes for viewing data, images, and code output apart from the rest of the notebook.\n", + "This is facilitates effective data science work flows.\n", + "\n", + "It is recommended that you peruse the [Jupyter lab documentation](https://jupyterlab.readthedocs.io/en/stable/getting_started/overview.html) to get a feel for all of its added capabilities." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following instructions are laid out for running a Jupyter notebook server. That being said, the process for running a Jupyter lab server and working with notebooks therein is nearly identical.\n", + "Both Jupyter notebook and Jupyter lab should already be [installed via Anaconda](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running a Notebook Server & Creating a Notebook\n", + "Enough gushing about Jupyter notebooks. Let's start using them!\n", + "\n", + "In your terminal, navigate to a directory (a.k.a folder) that you are okay creating files in. If you don't know how to do this, Google it!\n", + "\n", + "Once you are in the desired directory, execute in your terminal (type the following, and then hit ``): `jupyter notebook`\n", + "\n", + "Alternatively, if you want to work in Jupyter lab, run: `jupyter lab`\n", + "\n", + "You should see some text appear in your terminal:\n", + "\n", + "![Starting a jupyter notebook server on your machine](attachments/jupyter_login.PNG)\n", + "\n", + "This is a \"notebook server\" that is running on your machine - it basically handles all of the communication between your browser and your machine. A new window or tab should open in your web browser, which looks like a file explorer. \n", + "\n", + "![File explorer that opens in your browser](attachments/jp_files.PNG)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can use this to enter subdirectories and to open up any Jupyter notebooks that you have saved. *You will need to use this file explorer any time that you want to open up a Jupyter notebook, old or new.* In the top-right corner of this window, click on the dropdown menu labeled \"New\", and select the option `Python 3`.\n", + "\n", + "![](attachments/jp_dropdown.PNG)\n", + "\n", + "A new tab will open in your browser, revealing a \"Jupyter notebook\" called `Untitled.ipynb` running a Python 3 kernel. Clicking `File > Rename` in the notebook will enable you to name your notebook. `.ipynb` is the file-type suffix used for Jupyter notebooks (`ipynb` stands for \"IPython-notebook\", which is what these notebooks were called prior to 2014). The commands that you run in this notebook are interpreted and executed by Python in the essentially same way that they would be in a IPython console. \n", + "\n", + "
    \n", + "\n", + "**Jupyter Notebooks Do Not Use the Internet**: \n", + "\n", + "Although a Jupyter notebook opens in your browser, *everything is happening locally on your machine*. You don't need to be connected to the internet to work on a Jupyter notebook! The notebook server that you ran in your terminal is simply routing communication from your browser to your local machine. For instance, it is sending code to your CPython interpreter to be executed.\n", + "
    \n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Notebook Cells \n", + "Whereas a Python console only allows you to work on one line of code at a time, a notebook allows you to write code within \"cells\" and to execute these chunks of code cell-by-cell. In the first cell, write the lines of code:\n", + "\n", + "```python\n", + "x = 3\n", + "y = 4\n", + "```\n", + "then press `+`. This will execute all of the code within the given cell (in this instance, assigning the variables `x` and `y` with the values 3 and 4, respectively) and then creates a new cell below. In the next cell type the code:\n", + "\n", + "```python\n", + "x + y\n", + "```\n", + "and hit `+` to execute this code. The number 7 will appear beneath the cell - this, of course, is the value that is returned when `3 + 4` is evaluated: \n", + "\n", + "![jupyter notebook example](attachments/jupyter_early.png)\n", + "\n", + "Notice that the notebook \"knows\" about its variables across its cells. This doesn't just work from top to bottom - you can define `z = 2` in the third cell, and then execute code that references `z` in the first cell. What really matters is the *order* in which the cells are executed. Notice that `In[1]` denotes that the top cell with the first input-cell executed in the notebook, and `In[2]` denotes the second cell that was executed. \n", + "\n", + "Formally, the cells within a given notebook share a common \"namespace\": any variable defined in a cell can be referenced or redefined in any other cell within the notebook. On the other hand, separate notebooks are completely independent from one another. You can be working on multiple notebooks at once, and they will never \"know\" about one another. \n", + "\n", + "A major value of using a notebook is that you can rapidly edit these cells (say, change `x = 3` to `x = 10`), and re-execute them to nimbly tinker with whatever code you are developing. Although simple, this is a hugely powerful environment for prototyping code. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## An Example Notebook\n", + "To show off a more exciting use-case, let's create a notebook that plots some data for us. We'll use matplotlib, a Python library that is used for plotting data, and NumPy, the premiere library for doing numerical work in Python. We will import these libraries for use in our code. Next we'll define some mathematical functions. And finally, we'll plot these functions evaluated on a large number of closely-spaced points on the domain." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:30.495595Z", + "iopub.status.busy": "2021-01-31T21:47:30.494594Z", + "iopub.status.idle": "2021-01-31T21:47:31.168637Z", + "shell.execute_reply": "2021-01-31T21:47:31.167635Z" + } + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# this tells Jupyter to embed matplotlib plots in the notebook\n", + "%matplotlib inline " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:31.173637Z", + "iopub.status.busy": "2021-01-31T21:47:31.172634Z", + "iopub.status.idle": "2021-01-31T21:47:31.183635Z", + "shell.execute_reply": "2021-01-31T21:47:31.183635Z" + } + }, + "outputs": [], + "source": [ + "def sinc(x):\n", + " return np.sin(x) / x\n", + "\n", + "def d_sinc(x):\n", + " \"derivative of sinc-function\"\n", + " return np.cos(x)/x - np.sin(x)/x**2" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:31.187635Z", + "iopub.status.busy": "2021-01-31T21:47:31.186634Z", + "iopub.status.idle": "2021-01-31T21:47:31.198636Z", + "shell.execute_reply": "2021-01-31T21:47:31.198636Z" + } + }, + "outputs": [], + "source": [ + "# evaluate functions at 1000 points evenly spaced in [-15, 15]\n", + "x = np.linspace(-15, 15, 1000)\n", + "f = sinc(x)\n", + "df = d_sinc(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "execution": { + "iopub.execute_input": "2021-01-31T21:47:31.233635Z", + "iopub.status.busy": "2021-01-31T21:47:31.232637Z", + "iopub.status.idle": "2021-01-31T21:47:31.719634Z", + "shell.execute_reply": "2021-01-31T21:47:31.720634Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
    " + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# plot the sinc-function and its derivative\n", + "fig, ax = plt.subplots()\n", + "ax.plot(x, f, color=\"red\", label=r\"$sinc(x)$\")\n", + "ax.plot(x, df, color=\"blue\", ls=\"--\", label=r\"$\\frac{d(sinc(x))}{dx}$\")\n", + "\n", + "\n", + "ax.set_title(\"Example Notebook Plot\")\n", + "ax.set_xlabel(r\"$x$ [radians]\")\n", + "\n", + "ax.grid(True)\n", + "ax.legend();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that this notebook interface is great for making adjustments to this plot. You can easily change the color or line-style of the plot and redraw it without having to recompute the functions. You simply re-execute the cell containing the plot code. This is especially nice when the numerical computations required to generate the curves are costly." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Familiarizing Yourself with Jupyter Notebooks\n", + "Here, we will review some essential keyboard shortcuts and notebook features, which will enable you to use notebooks competently. A notebook has two modes of operation: \n", + "\n", + "**Command Mode (Press** `` **to activate)** \n", + "\n", + "When in command mode, you can use keyboard shortcuts to create/delete/cut/paste notebook cells, and to change a cell's type between code and markdown modes. Your selected cell will be surrounded by a *blue* border when you are in command mode. For a complete listing of keyboard shortcuts, toward the top of the notebook click `Help > Keyboard Shortcuts`. The most critical shortcuts are:\n", + "\n", + "- create a new cell above the current cell: `a`\n", + "- create a new cell below the current cell: `b`\n", + "- delete the current cell: `dd`\n", + "- restart the notebook kernel (kill all executions and erase all defined variables): `00`\n", + "- change the current cell's type to \"Code\": `y`\n", + "- change the current cell's type to \"Markdown\": `m`\n", + "\n", + "**Edit Mode (Press** `` **to activate)** \n", + "\n", + "Edit mode simply permits you to type text into the selected cell. When in edit mode, the current cell will be surrounded by a *green* border. There are two commands for executing a cell:\n", + "\n", + "- execute current cell: `+`\n", + "- execute current cell and then create a new cell below: `+`\n", + "\n", + "By default, a cell will be a code-type cell, meaning that its content will be formatted and executed as Python code. Just as you saw when using the IPython notebook, `` can be used to perform autocomplete. Additionally, when your cursor is on the name of a Python function in your code, `+` will bring up a small window with the function's documentations string. This is *very* useful.\n", + "\n", + "![Looking up code documentation in a notebook](attachments/jp_docstring.PNG)\n", + "\n", + "### Markdown Cells\n", + "When a cell is set to Markdown type, its content will not be interpreted as Python code. Instead, its contents will be rendered as stylized text. Refer to [this page](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) as a reference for various markdown stylings. Using markdown cells allows you to create section and subsection headers for your notebook, you can [render LaTeX math equations](http://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Working%20With%20Markdown%20Cells.html#LaTeX-equations), embed images and videos in your notebook, and much more. In fact, every page in this website was created using Jupyter notebooks! Markdown-type cells are tremendously useful for creating high-quality, well-documented Jupyter notebooks. These are perfect for lab-report assignments.\n", + "\n", + "
    \n", + "\n", + "**Be Aware of Cell-Type**:\n", + "\n", + "If you ever find that your Python code isn't being formatted properly, and doesn't run at all when you execute the cell (you get no output, not even errors), there is a good chance that you have accidentally set the cell to be a 'Markdown'-type cell! Change the cell back to code-type by entering command mode (``) and pressing `y`.\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using Jupyter Notebooks with Other Languages\n", + "The Jupyter Notebook does not work exclusively with Python. A \"kernel\" can be developed in order to provide support for a given programming language in Jupyter. Indeed, kernels for several prominent programming languages are being developed for use with Jupyter: \n", + "\n", + "- [R](https://github.com/IRkernel/IRkernel)\n", + "- [Julia](https://github.com/JuliaLang/IJulia.jl)\n", + "- [Ruby](https://github.com/SciRuby/iruby)\n", + "- [C++](https://github.com/QuantStack/xeus-cling)\n", + "- [Haskell](https://github.com/gibiansky/IHaskell)\n", + "- [Go](https://github.com/gopherdata/gophernotes)\n", + "\n", + "The ever-growing list of available kernels for use with Jupyter can be found [here](https://github.com/jupyter/jupyter/wiki/Jupyter-kernels). It should be noted that these efforts are not all equally mature. For instance, whereas the Python and Julia kernels are robust, the Haskell kernel cannot run natively on Windows machines, and the C++ kernel is still in early development, as of writing this. \n", + "\n", + "### Jupyter Notebook Support in Visual Studio Code\n", + "Native Jupyter notebook support was [recently added to Visual Studio Code](https://devblogs.microsoft.com/python/announcing-support-for-native-editing-of-jupyter-notebooks-in-vs-code/). This means that you can now edit Jupyter notebooks within the [Visual Studio Code IDE](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html), and that you will benefit from added features like code-completion, debugging, and variable inspection." + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html b/docs_backup/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html index cd00735a..901877b7 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html +++ b/docs_backup/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html @@ -1,43 +1,47 @@ - - + - + - + Doing Numerical Work in Python — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -80,6 +84,7 @@ + + @@ -137,18 +143,20 @@ + +
    + + @@ -149,11 +158,13 @@ + +
      -
    • Docs »
    • +
    • »
    • Module 1: Getting Started with Python »
    • @@ -162,7 +173,7 @@
    • - + View page source @@ -178,214 +189,16 @@

      Basic Array Attributes

      -

      Armed with our understanding of multidimensional NumPy arrays, we now look at methods for programmatically inspecting an array’s attributes (e.g. its dimensionality). It is especially important to understand what an array’s “shape” is.

      +

      Armed with our understanding of multidimensional NumPy arrays, we now look at methods for programmatically inspecting an array’s attributes (e.g. its dimensionality). It is especially important to understand what an array’s “shape” is.

      We will use the following array to provide context for our discussion:

      -
      @@ -306,7 +314,6 @@

      Links to Official Documentation jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module3_IntroducingNumpy/BasicArrayAttributes.ipynb b/docs_backup/Module3_IntroducingNumpy/BasicArrayAttributes.ipynb new file mode 100644 index 00000000..c4830fe5 --- /dev/null +++ b/docs_backup/Module3_IntroducingNumpy/BasicArrayAttributes.ipynb @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Numpy array attributes, Difficulty: Easy, Category: Section\n", + " :keywords: ndim, shape, size, itemsize, dtype, examples" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Basic Array Attributes\n", + "Armed with our understanding of multidimensional NumPy arrays, we now look at methods for programmatically inspecting an array's attributes (e.g. its dimensionality). It is especially important to understand what an array's \"shape\" is.\n", + "\n", + "We will use the following array to provide context for our discussion:\n", + " \n", + "```python\n", + ">>> import numpy as np\n", + ">>> example_array = np.array([[[ 0, 1, 2, 3],\n", + "... [ 4, 5, 6, 7]],\n", + "...\n", + "... [[ 8, 9, 10, 11],\n", + "... [12, 13, 14, 15]],\n", + "...\n", + "... [[16, 17, 18, 19],\n", + "... [20, 21, 22, 23]]])\n", + "```\n", + "According to the preceding discussion, it is a 3-dimensional array structured such that:\n", + "\n", + " - axis-0 discerns which of the **3 sheets** to select from.\n", + " - axis-1 discerns which of the **2 rows**, in any sheet, to select from.\n", + " - axis-2 discerns which of the **4 columns**, in any sheet and row, to select from.\n", + "\n", + "**ndarray.ndim**: \n", + "\n", + "The number of axes (dimensions) of the array.\n", + "\n", + "```python\n", + "# dimensionality of the array\n", + ">>> example_array.ndim\n", + "3\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**ndarray.shape**:\n", + "\n", + "A tuple of integers indicating the number of elements that are stored along each dimension of the array. For a 2D-array with $N$ rows and $M$ columns, shape will be $(N, M)$. The length of this shape-tuple is therefore equal to the number of dimensions of the array.\n", + "\n", + "```python\n", + "# shape of the array\n", + ">>> example_array.shape\n", + "(3, 2, 4)\n", + "```\n", + "\n", + "**ndarray.size**:\n", + "\n", + "The total number of elements of the array. This is equal to the product of the elements of the array's shape.\n", + "```python\n", + "# size of the array: the number of elements it stores\n", + ">>> example_array.size\n", + "24\n", + "```\n", + "\n", + "**ndarray.dtype**:\n", + "\n", + "An object describing the data type of the elements in the array. Recall that NumPy's ND-arrays are *homogeneous*: they can only posses numbers of a uniform data type. \n", + "\n", + "```python\n", + "# `example_array` contains integers, each of which are stored using 32 bits of memory\n", + ">>> example_array.dtype\n", + "dtype('int32') \n", + "```\n", + "\n", + "**ndarray.itemsize**:\n", + "\n", + "The size, in bytes (8 bits is 1 byte), of each element of the array. For example, an array of elements of type `float64` has itemsize 8 $(= \\frac{64}{8})$, while an array of type `complex32` has itemsize 4 $(= \\frac{32}{8})$.\n", + "```python\n", + "# each integer in `example_array` is represented using 4 bytes (32 bits) of memory\n", + ">>> example_array.itemsize\n", + "4\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Links to Official Documentation\n", + "\n", + "- [Array attributes](https://numpy.org/doc/stable/reference/arrays.ndarray.html#array-attributes)" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module3_IntroducingNumpy/BasicIndexing.html b/docs_backup/Module3_IntroducingNumpy/BasicIndexing.html index 18fc5b5d..1c5a6cc7 100644 --- a/docs_backup/Module3_IntroducingNumpy/BasicIndexing.html +++ b/docs_backup/Module3_IntroducingNumpy/BasicIndexing.html @@ -1,45 +1,49 @@ - - + - + - + Introducing Basic and Advanced Indexing — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@

    + + @@ -170,11 +176,13 @@ + +
    @@ -376,7 +384,7 @@

    Ellipsis and Newaxis objects

    Reading Comprehension: Ellipsis

    -

    Given a \(N\)-dimensional array, x, index into x such that you axis entry-0 of axis-0, the last entry of axis-\(N-1\), slicing along all intermediate dimensions. \(N\) is at least \(2\).

    +

    Given a \(N\)-dimensional array, x, index into x such that you access entry-0 of axis-0, the last entry of axis-\(N-1\), slicing along all intermediate dimensions. \(N\) is at least \(2\).

    @@ -434,14 +442,14 @@

    Producing a View of an Arrayarray([ 3.31, 0.21, -3.77]) >>> np.shares_memory(new_subarray, z) -False +False

    Utilizing an array in a mathematical expression involving the arithmetic operators (+, -, *, /, //, **) returns an entirely distinct array, that does not share memory with the original array.

    # mathematical expressions like `subarray + 2`
     # produce distinct arrays, not views
     >>> np.shares_memory(subarray + 2, subarray)
    -False
    +False
     

    Thus updating a variable subarray via subarray = subarray + 2 does not overwrite the original data referenced by subarray. Rather, subarray + 2 assigns that new array to the variable subarray. NumPy does provide mechanisms for performing mathematical operations to directly update the underlying data of an array without having to create a distinct array. We will discuss these mechanisms in the next subsection.

    @@ -455,14 +463,14 @@

    Producing a View of an Arrayx? That is, in which cases do x and the created variable reference the same underlying array data? Check your work by using np.shares_memory.

      -
    • a1 = x
    • -
    • a2 = x[0, 0]
    • -
    • a3 = x[:, 0]
    • -
    • a4 = x[:, 0] + np.array([-1, -2, -3])
    • -
    • a5 = np.copy(x[:, 0])
    • -
    • a6 = x[np.newaxis]
    • -
    • a7 = x.reshape(2, 3, 2)
    • -
    • a8 = 2 + x
    • +
    • a1 = x

    • +
    • a2 = x[0, 0]

    • +
    • a3 = x[:, 0]

    • +
    • a4 = x[:, 0] + np.array([-1, -2, -3])

    • +
    • a5 = np.copy(x[:, 0])

    • +
    • a6 = x[np.newaxis]

    • +
    • a7 = x.reshape(2, 3, 2)

    • +
    • a8 = 2 + x

    @@ -470,9 +478,9 @@

    Producing a View of an Array

    Because basic indexing produces a view of an array’s underlying data, we must take time to understand the ways in which we can augment that underlying data, versus performing operations that produce an array with distinct data. Here we will see that:

      -
    • in-place assignments
    • -
    • augmented assignments
    • -
    • NumPy functions with the out argument
    • +
    • in-place assignments

    • +
    • augmented assignments

    • +
    • NumPy functions with the out argument

    can all be used to augment array data in-place.

    Performing an assignment on a view of a, i.e. a[:], instructs NumPy to perform the assignment to replace a’s data in-place.

    @@ -514,7 +522,7 @@

    In-Place Assignmentsarray([ 0, -1, -2, -3, -4]) >>> np.shares_memory(a, b) -True +True

    This view-assignment mechanism can be used update a subsection of an array in-place.

    @@ -557,7 +565,7 @@

    Augmented Assignments>>> b = a[0] >>> c = a[0] >>> np.shares_memory(a, b) and np.shares_memory(a, c) -True +True # updating `b` using a mathematical expression creates # a distinct array, which is divorced from `a` and `c` @@ -566,7 +574,7 @@

    Augmented Assignmentsarray([ 0, -1, -2, -3]) >>> np.shares_memory(a, b) -False +False # updating `c` using augmented assignment updates the # underlying data that `c` is a view of @@ -575,7 +583,7 @@

    Augmented Assignmentsarray([ 0, -2, -4, -6]) >>> np.shares_memory(a, c) -True +True # note that this update is reflected in `a` as well, # as it still shares memory with `c` @@ -597,7 +605,7 @@

    Specifying out< >>> a = np.array([0., 0.2, 0.4, 0.6, 0.8, 1.]) >>> b = a[:] >>> np.shares_memory(a, b) -True +True # specifying 'out=a' instructs NumPy # to overwrite the data referenced by `a` @@ -666,7 +674,6 @@

    Benefits and Risks of Augmenting Data In-Place
    # 5.
     >>> np.log(x[1:3], out=x[1:3])
    ->>> y += 3
     
    @@ -709,14 +720,14 @@

    Reading Comprehension Solutions -
  • arr[0]
  • -
  • arr[:-1, 0]
  • -
  • arr[(2, 3)]
  • -
  • arr[[2, 0]] ✘ (index is a list, not a tuple)
  • -
  • arr[np.array([2, 0])] ✘ (index is a numpy.ndarray, not a tuple)
  • -
  • arr[:, (2, 3)] ✘ (index contains a tuple; only int, slice, np.newaxis, Ellipsis allowed)
  • -
  • arr[slice(None), ...]
  • -
  • arr[(np.newaxis, 0, slice(1, 2), np.newaxis)]
  • +
  • arr[0]

  • +
  • arr[:-1, 0]

  • +
  • arr[(2, 3)]

  • +
  • arr[[2, 0]] ✘ (index is a list, not a tuple)

  • +
  • arr[np.array([2, 0])] ✘ (index is a numpy.ndarray, not a tuple)

  • +
  • arr[:, (2, 3)] ✘ (index contains a tuple; only int, slice, np.newaxis, Ellipsis allowed)

  • +
  • arr[slice(None), ...]

  • +
  • arr[(np.newaxis, 0, slice(1, 2), np.newaxis)]

  • Views: Solution

    Given,

    @@ -727,14 +738,14 @@

    Reading Comprehension Solutionsx? That is, in which cases do x and the created variable reference the same underlying array data? Check your work by using np.shares_memory.

      -
    • a1 = x
    • -
    • a2 = x[0, 0] ✘; when basic indexing returns a single number, that number does not share memory with the parent array.
    • -
    • a3 = x[:, 0]
    • -
    • a4 = x[:, 0] + np.array([-1, -2, -3]) ✘; arithmetic operations on NumPy arrays create distinct arrays by default.
    • -
    • a5 = np.copy(x[:, 0]) ✘; numpy.copy informs NumPy to create a distinct copy of an array.
    • -
    • a6 = x[np.newaxis]
    • -
    • a7 = x.reshape(2, 3, 2)
    • -
    • a8 = 2 + x ✘; arithmetic operations on NumPy arrays create distinct arrays by default.
    • +
    • a1 = x

    • +
    • a2 = x[0, 0] ✘; when basic indexing returns a single number, that number does not share memory with the parent array.

    • +
    • a3 = x[:, 0]

    • +
    • a4 = x[:, 0] + np.array([-1, -2, -3]) ✘; arithmetic operations on NumPy arrays create distinct arrays by default.

    • +
    • a5 = np.copy(x[:, 0]) ✘; numpy.copy informs NumPy to create a distinct copy of an array.

    • +
    • a6 = x[np.newaxis]

    • +
    • a7 = x.reshape(2, 3, 2)

    • +
    • a8 = 2 + x ✘; arithmetic operations on NumPy arrays create distinct arrays by default.

    Augmenting Array Data In-Place: Solution

    Given,

    @@ -796,29 +807,29 @@

    Reading Comprehension Solutions - - - - - - + +

    -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -827,7 +838,6 @@

    Reading Comprehension Solutions jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module3_IntroducingNumpy/BasicIndexing.ipynb b/docs_backup/Module3_IntroducingNumpy/BasicIndexing.ipynb new file mode 100644 index 00000000..8160ac87 --- /dev/null +++ b/docs_backup/Module3_IntroducingNumpy/BasicIndexing.ipynb @@ -0,0 +1,805 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Numpy array basic indexing, Difficulty: Medium, Category: Section\n", + " :keywords: basic index, slice, no copy index, multidimensional array, nd array, view, reverse, axis" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introducing Basic and Advanced Indexing\n", + "\n", + "Thus far we have seen that we can access the contents of a NumPy array by specifying an integer or slice-object as an index for each one of its dimensions. Indexing into and slicing along the dimensions of an array are known as basic indexing. NumPy also provides a sophisticated system of \"advanced indexing\", which permits us powerful means for accessing elements of an array that is flexible beyond specifying integers and slices along axes. For example, we can use advanced indexing to access all of the negative-valued elements from `x`.\n", + "\n", + "```python\n", + "# demonstrating basic indexing and advanced indexing\n", + ">>> import numpy as np\n", + ">>> x = np.array([[ -5, 2, 0, -7],\n", + "... [ -1, 9, 3, 8],\n", + "... [ -3, -3, 4, 6]])\n", + "\n", + "# Access the column-1 of row-0 and row-2.\n", + "# This is an example of basic indexing. \n", + "# A \"view\" of the underlying data in `x`\n", + "# is produced; no data is copied.\n", + ">>> x[::2, 1]\n", + "array([ 2, -3])\n", + "\n", + "# An example of advanced indexing.\n", + "# Access all negative elements in `x`.\n", + "# This produces a copy of the accessed data.\n", + ">>> x[x < 0]\n", + "array([-5, -7, -1, -3, -3])\n", + "```\n", + "\n", + "We will see that, where basic indexing provides us with a *view* of the data within the array, without making a copy of it, advanced indexing requires that a copy of the accessed data be made. Here, we will define basic indexing and understand the nuances of working with views of arrays. The next section, then, is dedicated to understanding advanced indexing. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic Indexing\n", + "We begin this subsection by defining precisely what basic indexing is. Next, we will touch on each component of this definition, and lastly we will delve into the significance of basic indexing in the way it permits us to reference the underlying data of an array without copying it.\n", + "\n", + "
    \n", + "\n", + "**Definition: Basic Indexing**: \n", + "\n", + "Given an $N$-dimensional array, `x`, `x[index]` invokes **basic indexing** whenever `index` is a *tuple* containing any combination of the following types of objects:\n", + "\n", + "- integers\n", + "- [slice](http://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/SequenceTypes.html#Slicing) objects\n", + "- [Ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) objects\n", + "- [numpy.newaxis](http://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/Broadcasting.html#Inserting-Size-1-Dimensions-into-An-Array) objects\n", + "\n", + "Accessing the contents of an array via basic indexing *does not create a copy of those contents*. Rather, a \"view\" of the same underlying data is produced.\n", + "
    \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Indexing with Integers and Slice Objects\n", + "Our discussion of [accessing data along multiple dimensions of a NumPy array](http://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.html) already provided a comprehensive rundown on the use of integers and slices to access the contents of an array. According to the preceding definition, *these were all examples of basic indexing*.\n", + "\n", + "To review the material discussed in that section, recall that one can access an individual element or a \"subsection\" of an $N$-dimensional array by specifying $N$ integers or slice-objects, or a combination of the two. We also saw that, when supplied fewer-than $N$ indices, NumPy will automatically \"fill-in\" the remaining indices with trailing slices. Keep in mind that the indices start at 0, such that the 4th column in `x` corresponds to column-3.\n", + "\n", + "```python \n", + "# Accessing the element located\n", + "# at row-1, last-column of `x`\n", + ">>> x[1, -1]\n", + "8\n", + "\n", + "# Access the subarray of `x`\n", + "# contained within the first two rows\n", + "# and the first three columns\n", + ">>> x[:2, :3]\n", + "array([[-5, 2, 0],\n", + " [-1, 9, 3]])\n", + "\n", + "# NumPy fills in \"trailing\" slices\n", + "# if we don't supply as many indices\n", + "# as there are dimensions in that array\n", + ">>> x[0] # equivalent to x[0, :]\n", + "array([-5, 2, 0, -7])\n", + "```\n", + "\n", + "Recall that the familiar [slicing](http://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/SequenceTypes.html#Slicing) syntax actually forms `slice` objects \"behind the scenes\".\n", + "\n", + "```python\n", + "# Reviewing the `slice` object\n", + "\n", + "# equivalent: x[:2, :3]\n", + ">>> x[slice(None, 2), slice(None, 3)]\n", + "array([[-5, 2, 0],\n", + " [-1, 9, 3]])\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using a Tuple as an N-dimensional Index\n", + "According to its definition, we must supply our array-indices as a tuple in order to invoke basic indexing. As it turns out, we have been forming tuples of indices all along! That is, every time that we index into an array using the syntax `x[i, j, k]`, we are actually forming a [tuple](http://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/SequenceTypes.html#Tuples) containing those indices. That is, `x[i, j, k]` is equivalent to `x[(i, j, k)]`.\n", + "\n", + "`x[i, j, k]` forms the tuple `(i, j, k)` and passes that to the array's \"get-item\" mechanism. Thus, `x[0, 3]` is equivalent to `x[(0, 3)]`. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```python\n", + "# N-dimensional indexing utilizes tuples:\n", + "# `x[i, j, k]` is equivalent to `x[(i, j, k)]`\n", + "\n", + "# equivalent: x[1, -1]\n", + ">>> x[(1, -1)] \n", + "8\n", + "\n", + "# equivalent: x[:2, :3]\n", + ">>> x[(slice(None, 2), slice(None, 3))] \n", + "array([[-5, 2, 0],\n", + " [-1, 9, 3]])\n", + "\n", + "# equivalent: x[0]\n", + ">>> x[(0,)]\n", + "array([-5, 2, 0, -7])\n", + "```\n", + "\n", + "All objects used in this \"get-item\" syntax are packed into a tuple. For instance, `x[0, (0, 1)]` is equivalent to `x[(0, (0, 1))]`. You may be surprised to find that this is a valid index. However, see that *it does not invoke basic indexing*; the index used here is a tuple that contains an integer *and another tuple*, which is not permitted by the rules of basic indexing.\n", + "\n", + "Finally, note that the rules of basic indexing specifically call for a *tuple* of indices. Supplying a list of indices triggers advanced indexing rather than basic indexing!\n", + "\n", + "```python\n", + "# basic indexing specifically requires a tuple\n", + ">>> x[(1, -1)] \n", + "8\n", + "\n", + "# indexing with a list triggers advanced indexing\n", + ">>> x[[1, -1]]\n", + "array([[-1, 9, 3, 8],\n", + " [-3, -3, 4, 6]])\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ellipsis and Newaxis objects\n", + "Recall from our discussion of broadcasting, that the `numpy.newaxis` object can be passed as an index to an array, in order to [insert a size-1 dimension into the array](http://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/Broadcasting.html#Inserting-Size-1-Dimensions-into-An-Array).\n", + "\n", + "```python\n", + "# inserting size-1 dimensions with `np.newaxis`\n", + ">>> x.shape\n", + "(3, 4)\n", + "\n", + ">>> x[np.newaxis, :, :, np.newaxis].shape\n", + "(1, 3, 4, 1)\n", + "\n", + "# forming the index as an explicit tuple\n", + ">>> x[(np.newaxis, slice(None), slice(None), np.newaxis)].shape\n", + "(1, 3, 4, 1)\n", + "```\n", + "\n", + "We can also use the built-in `Ellipsis` object in order to insert slices into our index such that the index has as many entries as the array has dimensions. In the same way that `:` can be used to represent a `slice` object, `...` can be used to represent an `Ellipsis` object.\n", + "\n", + "```python\n", + ">>> y = np.array([[[ 0, 1, 2, 3],\n", + "... [ 4, 5, 6, 7]],\n", + "... \n", + "... [[ 8, 9, 10, 11],\n", + "... [12, 13, 14, 15]],\n", + "... \n", + "... [[16, 17, 18, 19],\n", + "... [20, 21, 22, 23]]])\n", + "\n", + "# equivalent: `y[:, :, 0]`\n", + ">>> y[..., 0]\n", + "array([[ 0, 4],\n", + " [ 8, 12],\n", + " [16, 20]])\n", + "\n", + "# using an explicit tuple\n", + ">>> y[(Ellipsis, 0)]\n", + "array([[ 0, 4],\n", + " [ 8, 12],\n", + " [16, 20]])\n", + "\n", + "# equivalent: `y[0, :, 1]`\n", + ">>> y[0, ..., 1]\n", + "array([1, 5])\n", + "```\n", + "\n", + "An index cannot possess more than one `Ellipsis` entry. This can be extremely useful when working with arrays of varying dimensionalities. To access column-0 along all dimensions of an array, `z`, would look like `z[:, 0]` for a 2D array, `z[:, :, 0]` for a 3D array, and so on. `z[..., 0]` succinctly encapsulates all iterations of this. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Takeaway:** \n", + "\n", + "Basic indexing is triggered whenever a tuple of: integer, `slice`, `numpy.newaxis`, and/or `Ellipsis` objects, is used as an index for a NumPy array. An array produced via basic indexing is a *view* of the same underlying data as the array that was indexed into; no data is copied through basic indexing. \n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + " \n", + "**Reading Comprehension: Ellipsis**\n", + "\n", + "Given a $N$-dimensional array, `x`, index into `x` such that you access entry-0 of axis-0, the last entry of axis-$N-1$, slicing along all intermediate dimensions. $N$ is at least $2$.\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + " \n", + "**Reading Comprehension: Basic Indexing**\n", + "\n", + "Given a shape-(4, 3) array,\n", + "\n", + "```python\n", + ">>> arr = np.array([[ 0, 1, 2, 3],\n", + "... [ 4, 5, 6, 7],\n", + "... [ 8, 9, 10, 11]])\n", + "```\n", + "\n", + "which of the following indexing schemes perform basic indexing? That is, in which instances does the index satisfy the rules of basic indexing?\n", + "\n", + " - `arr[0]`\n", + " - `arr[:-1, 0]`\n", + " - `arr[(2, 3)]`\n", + " - `arr[[2, 0]]`\n", + " - `arr[np.array([2, 0])]`\n", + " - `arr[(0, 1), (2, 3)]`\n", + " - `arr[slice(None), ...]`\n", + " - `arr[(np.newaxis, 0, slice(1, 2), np.newaxis)]`\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Producing a View of an Array\n", + "As stated above, using basic indexing does not return a copy of the data being accessed, rather it produces a *view* of the underlying data. NumPy provides the function `numpy.shares_memory` to determine if two arrays refer to the same underlying data.\n", + "\n", + "```python\n", + ">>> z = np.array([[ 3.31, 4.71, 0.4 ],\n", + "... [ 0.21, 2.85, 3.21],\n", + "... [-3.77, 4.53, -1.15]])\n", + "\n", + "# `subarray` is column-0 of `z`, via\n", + "# basic indexing\n", + ">>> subarray = z[:, 0]\n", + ">>> subarray\n", + "array([ 3.31, 0.21, -3.77])\n", + "\n", + "# `subarray` is a view of the array data \n", + "# referenced by `z`\n", + ">>> np.shares_memory(subarray, z)\n", + "True\n", + "```\n", + "\n", + "A single number returned by basic indexing *does not* share memory with the parent array.\n", + "```python\n", + ">>> z[0, 0]\n", + "3.31\n", + "\n", + ">>> np.shares_memory(z[0, 0], z)\n", + "False\n", + "```\n", + "The function `numpy.copy` can be used to create a copy of an array, such that it no longer shares memory with any other array.\n", + "\n", + "```python\n", + "# creating a distinct copy of an array\n", + ">>> new_subarray = np.copy(subarray)\n", + ">>> new_subarray\n", + "array([ 3.31, 0.21, -3.77])\n", + "\n", + ">>> np.shares_memory(new_subarray, z)\n", + "False\n", + "```\n", + "\n", + "Utilizing an array in a mathematical expression involving the arithmetic operators (`+, -, *, /, //, **`) returns an entirely distinct array, that does not share memory with the original array.\n", + "\n", + "```python\n", + "# mathematical expressions like `subarray + 2`\n", + "# produce distinct arrays, not views\n", + ">>> np.shares_memory(subarray + 2, subarray)\n", + "False\n", + "```\n", + "\n", + "Thus updating a variable `subarray` via `subarray = subarray + 2` does *not* overwrite the original data referenced by `subarray`. Rather, `subarray + 2` assigns that new array to the variable `subarray`. NumPy does provide mechanisms for performing mathematical operations to directly update the underlying data of an array without having to create a distinct array. We will discuss these mechanisms in the next subsection." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + " \n", + "**Reading Comprehension: Views**\n", + "\n", + "Given, \n", + "\n", + "```python\n", + "x = np.array([[ 0, 1, 2, 3],\n", + " [ 4, 5, 6, 7],\n", + " [ 8, 9, 10, 11]])\n", + "```\n", + "\n", + "Which of the following expressions create views of `x`? That is, in which cases do `x` and the created variable reference the same underlying array data? Check your work by using `np.shares_memory`.\n", + "\n", + "- `a1 = x`\n", + "- `a2 = x[0, 0]`\n", + "- `a3 = x[:, 0]`\n", + "- `a4 = x[:, 0] + np.array([-1, -2, -3])`\n", + "- `a5 = np.copy(x[:, 0])`\n", + "- `a6 = x[np.newaxis]`\n", + "- `a7 = x.reshape(2, 3, 2)`\n", + "- `a8 = 2 + x`\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Augmenting the Underlying Data of an Array \n", + "Because basic indexing produces a *view* of an array's underlying data, we must take time to understand the ways in which we can *augment* that underlying data, versus performing operations that produce an array with distinct data. Here we will see that:\n", + "\n", + "- in-place assignments \n", + "- augmented assignments\n", + "- NumPy functions with the `out` argument \n", + "\n", + "can all be used to augment array data in-place. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### In-Place Assignments\n", + "\n", + "The assignment operator, `=`, can be used to update an array's data in-place. Consider the array `a`, and its view `b`.\n", + "```python\n", + ">>> a = np.array([0, 1, 2, 3, 4])\n", + ">>> b = a[:]\n", + ">>> np.shares_memory(a, b)\n", + "True\n", + "```\n", + "\n", + "Assigning a new array to `a` simply changes the data that `a` references, divorcing `a` and `b`, and leaving `b` unchanged.\n", + "```python\n", + "# `a` is now assigned to reference a distinct array \n", + ">>> a = np.array([0, -1, -2, -3, -4])\n", + "\n", + "# `b` still references the original data\n", + ">>> b\n", + "array([0, 1, 2, 3, 4])\n", + "\n", + ">>> np.shares_memory(a, b)\n", + "False\n", + "```\n", + "\n", + "Performing an assignment on a *view* of `a`, i.e. `a[:]`, instructs NumPy to perform the assignment to replace `a`'s data in-place. \n", + "\n", + "```python\n", + "# reinitialize `a` and `b`. \n", + "# `b` is again a view of `a`\n", + ">>> a = np.array([0, 1, 2, 3, 4])\n", + ">>> b = a[:]\n", + "\n", + "# assigning an array to a *view* of `a` \n", + "# causes NumPy to update the data in-place\n", + ">>> a[:] = np.array([0, -1, -2, -3, -4])\n", + ">>> a\n", + "array([ 0, -1, -2, -3, -4])\n", + "\n", + "# `b` a view of the same data, thus\n", + "# it is affected by this in-place assignment\n", + ">>> b\n", + "array([ 0, -1, -2, -3, -4])\n", + "\n", + ">>> np.shares_memory(a, b)\n", + "True\n", + "```\n", + "\n", + "This view-assignment mechanism can be used update a subsection of an array in-place.\n", + "\n", + "```python\n", + ">>> p = np.array([[ 0, 1, 2, 3],\n", + "... [ 4, 5, 6, 7],\n", + "... [ 8, 9, 10, 11]])\n", + ">>> q = p[0, :]\n", + "\n", + "# Assign row-0, column-0 the value -40\n", + "# and row-0, column-2 the value -50\n", + ">>> p[0, ::2] = (-40, -50)\n", + "\n", + "# broadcast-assign -1 to a subsection of `p`\n", + ">>> p[1:, 2:] = -1\n", + ">>> p\n", + "array([[-40, 1, -50, 3],\n", + " [ 4, 5, -1, -1],\n", + " [ 8, 9, -1, -1]])\n", + "```\n", + "Again, this updates the underlying data, and thus all views of this data reflect this change.\n", + "```python\n", + "# `q` is still a view of row-0 of `p`\n", + ">>> q\n", + "array([-40, 1, -50, 3])\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Augmented Assignments\n", + "Recall from our discussion of basic mathematical expressions in Python, that [augmented assignment expressions](http://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Augmented-Assignment-Statements) provide a nice shorthand notation for updating the value of a variable. For example, the assignment expression `x = x + 5` can be rewritten using the augmented assignment `x += 5`. \n", + "\n", + "While `x += 5` is truly only a shorthand in the context of basic Python objects (integers floats, etc.), *augmented assignments on NumPy arrays behave fundamentally different than their long-form counterparts*. Specifically, they directly update the underlying data referenced by the updated array, rather than creating a distinct array, thus affecting any arrays that are views of that data. We will demonstrate this here.\n", + "\n", + "```python\n", + "# Demonstrating that augmented assignments on NumPy\n", + "# arrays update the underlying data reference by that\n", + "# array.\n", + ">>> a = np.array([[ 0, 1, 2, 3],\n", + "... [ 4, 5, 6, 7],\n", + "... [ 8, 9, 10, 11]])\n", + "\n", + "# `b` and `c` are both views of row-0 of `a`, via basic indexing\n", + ">>> b = a[0]\n", + ">>> c = a[0]\n", + ">>> np.shares_memory(a, b) and np.shares_memory(a, c)\n", + "True\n", + "\n", + "# updating `b` using a mathematical expression creates\n", + "# a distinct array, which is divorced from `a` and `c`\n", + ">>> b = b * -1\n", + ">>> b\n", + "array([ 0, -1, -2, -3])\n", + "\n", + ">>> np.shares_memory(a, b)\n", + "False\n", + "\n", + "# updating `c` using augmented assignment updates the \n", + "# underlying data that `c` is a view of\n", + ">>> c *= -2\n", + ">>> c\n", + "array([ 0, -2, -4, -6])\n", + "\n", + ">>> np.shares_memory(a, c)\n", + "True\n", + "\n", + "# note that this update is reflected in `a` as well,\n", + "# as it still shares memory with `c`\n", + ">>> a\n", + "array([[ 0, -2, -4, -6],\n", + " [ 4, 5, 6, 7],\n", + " [ 8, 9, 10, 11]])\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Specifying `out` to Perform NumPy Operations In-Place \n", + "There is no reason why we should only be able to augment data using arithmetic operations. Indeed, [NumPy's various mathematical functions](https://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/VectorizedOperations.html#NumPy%E2%80%99s-Mathematical-Functions) have an optional keyword argument, `out`, which can be used to specify where to \"store\" the result of the mathematical operation. By default, the operation will create a distinct array in memory, leaving the input data unaffected.\n", + "\n", + "```python\n", + "# Specifying the 'out' argument in a `numpy.exp` \n", + "# to augment the data of an array\n", + "\n", + "# `b` is a view of `a`\n", + ">>> a = np.array([0., 0.2, 0.4, 0.6, 0.8, 1.])\n", + ">>> b = a[:]\n", + ">>> np.shares_memory(a, b)\n", + "True\n", + "\n", + "# specifying 'out=a' instructs NumPy\n", + "# to overwrite the data referenced by `a`\n", + ">>> np.exp(a, out=a)\n", + "array([ 1., 1.22140276, 1.4918247, 1.8221188, 2.22554093, 2.71828183])\n", + "\n", + "# `b` is still a view of the now-augmented data\n", + ">>> b\n", + "array([ 1., 1.22140276, 1.4918247, 1.8221188, 2.22554093, 2.71828183])\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Benefits and Risks of Augmenting Data In-Place\n", + "It is critical to understand the relationship between arrays and the underlying data that they reference. *Operations that augment data in-place are more efficient than their counterparts that must allocate memory for a new array.* That is, an expression like `array += 3` is more efficient than `array = array + 3`. \n", + "\n", + "That being said, to *unwittingly* augment the data of an array, and thus affect all views of that data, is a big mistake; this produces hard-to-find bugs in the code of novice NumPy users. See that the following function, `add_3`, will change the data of the input array.\n", + "\n", + "```python\n", + "# updating an array in-place within a function\n", + "def add_3(x):\n", + " x += 3 \n", + " return x\n", + "\n", + ">>> x = np.array([0, 1, 2])\n", + ">>> y = add_3(x)\n", + ">>> y\n", + "array([3, 4, 5])\n", + "\n", + "# `x` is updated each time `f(x)` is called\n", + ">>> x\n", + "array([3, 4, 5])\n", + "```\n", + "\n", + "This is hugely problematic unless you intended for `add_3` to affect the input array. To remedy this, you can simply begin the function by making a copy of the input array; afterwards you can freely augment this copied data.\n", + "```python\n", + "def add_3(x):\n", + " x = np.copy(x)\n", + " x += 3 \n", + " return x\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Reading Comprehension: Augmenting Array Data In-Place**\n", + "\n", + "Given, \n", + "\n", + "```python\n", + "x = np.array([[ 0., 1., 2., 3.],\n", + " [ 4., 5., 6., 7.],\n", + " [ 8., 9., 10., 11.]])\n", + "\n", + "y = x[0, :]\n", + "```\n", + "\n", + "Which of the following expressions updates the data originally referenced by `x`?\n", + "\n", + "```python \n", + "# 1.\n", + ">>> x += 3\n", + "```\n", + "\n", + "```python \n", + "# 2.\n", + ">>> y *= 2.4\n", + "```\n", + "\n", + "```python \n", + "# 3.\n", + ">>> x = x + 3\n", + "```\n", + "\n", + "```python \n", + "# 4.\n", + ">>> y = np.copy(y)\n", + ">>> y += 3\n", + "```\n", + "\n", + "```python \n", + "# 5.\n", + ">>> np.log(x[1:3], out=x[1:3])\n", + "```\n", + "\n", + "```python \n", + "# 6.\n", + ">>> y[:] = y + 2\n", + "```\n", + "\n", + "```python \n", + "# 7.\n", + ">>> x = np.square(x)\n", + "```\n", + "\n", + "```python \n", + "# 8.\n", + ">>> x[:] = 0\n", + "```\n", + "\n", + "```python \n", + "# 9.\n", + ">>> def f(z): z /= 3\n", + ">>> f(y)\n", + "```\n", + "\n", + "```python\n", + "# 10.\n", + ">>> np.square(y, out=y)\n", + "```\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Takeaway:** \n", + "\n", + "Assignments to views of an array, augmented assignments, and NumPy functions that provide an `out` argument, are all methods for augmenting the data of an array in-place. This will affect any arrays that are views of that data. Furthermore, these in-place operations are more efficient than their counterparts that allocate memory for a new array. That being said, in-place data augmentation must not be used haphazardly, for this will inevitably lead to treacherous bugs in one's code.\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Links to Official Documentation\n", + "\n", + "- [Basic indexing](https://numpy.org/doc/stable/reference/arrays.indexing.html#indexing)\n", + "- [Definition of 'view'](https://numpy.org/doc/stable/glossary.html#term-view)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reading Comprehension Solutions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Ellipsis: Solution**\n", + "\n", + "Given a $N$-dimensional array, `x`, index into `x` such that you axis entry-0 of axis-0, the last entry of axis-$(N-1)$, slicing along all intermediate dimensions. $N$ is at least $2$.\n", + "\n", + "Using an `Ellipsis` object in the index allows us to signal NumPy to insert the slices along the $N - 2$ intermediate axis of `x`:\n", + "\n", + "`x[0, ..., -1]` or `x[0, Ellipsis, -1]`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Basic Indexing: Solution**\n", + "\n", + "In which instances does the index used satisfy the rules of basic indexing?\n", + "\n", + " - `arr[0]` ✔\n", + " - `arr[:-1, 0]` ✔\n", + " - `arr[(2, 3)]` ✔\n", + " - `arr[[2, 0]]` ✘ (index is a `list`, not a `tuple`)\n", + " - `arr[np.array([2, 0])]` ✘ (index is a `numpy.ndarray`, not a `tuple`)\n", + " - `arr[:, (2, 3)]` ✘ (index contains a tuple; only `int`, `slice`, `np.newaxis`, `Ellipsis` allowed)\n", + " - `arr[slice(None), ...]` ✔\n", + " - `arr[(np.newaxis, 0, slice(1, 2), np.newaxis)]` ✔" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Views: Solution**\n", + "\n", + "Given, \n", + "\n", + "```python\n", + "x = np.array([[ 0, 1, 2, 3],\n", + " [ 4, 5, 6, 7],\n", + " [ 8, 9, 10, 11]])\n", + "```\n", + "\n", + "Which of the following expressions create views `x`? That is, in which cases do `x` and the created variable reference the same underlying array data? Check your work by using `np.shares_memory`.\n", + "\n", + "- `a1 = x` ✔\n", + "- `a2 = x[0, 0]` ✘; when basic indexing returns a single number, that number does not share memory with the parent array.\n", + "- `a3 = x[:, 0]` ✔\n", + "- `a4 = x[:, 0] + np.array([-1, -2, -3])` ✘; arithmetic operations on NumPy arrays create distinct arrays by default.\n", + "- `a5 = np.copy(x[:, 0])` ✘; `numpy.copy` informs NumPy to create a distinct copy of an array.\n", + "- `a6 = x[np.newaxis]` ✔\n", + "- `a7 = x.reshape(2, 3, 2)` ✔\n", + "- `a8 = 2 + x` ✘; arithmetic operations on NumPy arrays create distinct arrays by default." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Augmenting Array Data In-Place: Solution**\n", + "\n", + "Given, \n", + "\n", + "```python\n", + "x = np.array([[ 0., 1., 2., 3.],\n", + " [ 4., 5., 6., 7.],\n", + " [ 8., 9., 10., 11.]])\n", + "\n", + "y = x[0, :]\n", + "```\n", + "\n", + "Which of the following expressions updates the data originally referenced by `x`?\n", + "\n", + "```python \n", + "# 1.\n", + ">>> x += 3 ✔\n", + "```\n", + "\n", + "```python \n", + "# 2.\n", + ">>> y *= 2.4 ✔\n", + "```\n", + "\n", + "```python \n", + "# 3.\n", + ">>> x = x + 3 ✘\n", + "```\n", + "\n", + "```python \n", + "# 4.\n", + ">>> y = np.copy(y)\n", + ">>> y += 3 ✘\n", + "```\n", + "\n", + "```python \n", + "# 5.\n", + ">>> np.log(x[1:3], out=x[1:3]) ✔\n", + "```\n", + "\n", + "```python \n", + "# 6.\n", + ">>> y[:] = y + 2 ✔\n", + "```\n", + "\n", + "```python \n", + "# 7.\n", + ">>> x = np.square(x) ✘\n", + "```\n", + "\n", + "```python \n", + "# 8.\n", + ">>> x[:] = 0 ✔\n", + "```\n", + "\n", + "```python \n", + "# 9.\n", + ">>> def f(z): z /= 3\n", + ">>> f(y) ✔\n", + "```\n", + "\n", + "```python \n", + "# 10.\n", + ">>> np.square(y, out=y) ✔\n", + "```" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module3_IntroducingNumpy/Broadcasting.html b/docs_backup/Module3_IntroducingNumpy/Broadcasting.html index 1731ff3f..4ada3896 100644 --- a/docs_backup/Module3_IntroducingNumpy/Broadcasting.html +++ b/docs_backup/Module3_IntroducingNumpy/Broadcasting.html @@ -1,45 +1,49 @@ - - + - + - + Array Broadcasting — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ + + @@ -169,11 +175,13 @@ + +
    -

    Refer to the official NumPy documentation for the complete list of available array datatypes.

    +

    Refer to the official NumPy documentation for the complete list of available array datatypes.

    Joining Arrays Together

    @@ -382,17 +390,17 @@

    Joining Arrays Togetherarray([ 1, 2, 3, -1, -2, -3])

    -

    A complete listing of functions for joining arrays can be found in the official NumPy documentation. There are also corresponding functions for splitting an array into independent arrays.

    +

    A complete listing of functions for joining arrays can be found in the official NumPy documentation. There are also corresponding functions for splitting an array into independent arrays.

    @@ -402,29 +410,29 @@

    Links to Official Documentation - - - - - - + + -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -433,7 +441,6 @@

    Links to Official Documentation jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.ipynb b/docs_backup/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.ipynb new file mode 100644 index 00000000..012497e2 --- /dev/null +++ b/docs_backup/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.ipynb @@ -0,0 +1,265 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Creating numpy arrays, Difficulty: Easy, Category: Section\n", + " :keywords: create array, ndarray, ones, random, zeros, empty, examples, arange, linspace, reshape, hstack, vstack" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Functions for Creating NumPy Arrays \n", + "This section presents standard methods for creating NumPy arrays of varying shapes and contents. NumPy provides a laundry list of functions for creating arrays:\n", + "\n", + "```python\n", + ">>> import numpy as np\n", + "\n", + "# creating an array from a Python sequence\n", + ">>> np.array([i**2 for i in range(5)])\n", + "array([ 0, 1, 4, 9, 16])\n", + "\n", + "# creating an array filled with ones\n", + ">>> np.ones((2, 4))\n", + "array([[ 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1.]])\n", + "\n", + "# creating an array of evenly-spaced points\n", + ">>> np.linspace(0, 10, 5)\n", + "array([ 0. , 2.5, 5. , 7.5, 10. ])\n", + "\n", + "# creating an array by sampling 10 numbers \n", + "# randomly from a mean-1, std-dev-5 normal\n", + "# distribution\n", + ">>> np.random.normal(1, 5, 10)\n", + "array([ 2.549537 , 2.75144951, 0.60031823, 3.75185732, 4.65543858,\n", + " 0.55779525, 1.15574987, -1.98461337, 5.39771083, -7.81395192])\n", + "\n", + "# creating an array of a specified datatype\n", + ">>> np.array([1.5, 3.20, 5.78], dtype=int)\n", + "array([1, 3, 5])\n", + "```\n", + "\n", + "## Creating Arrays from Python Sequences\n", + "You can create an array from a Python `list` or `tuple` by using NumPy's `array` function. NumPy will interpret the structure of the data it receives to determine the dimensionality and shape of the array. For example, a single list of numbers will be used to create a 1-dimensional array: \n", + "\n", + "```python\n", + "# a list of numbers will become a 1D-array\n", + ">>> np.array([1., 2., 3.]) # shape: (3,)\n", + "array([ 1., 2., 3.])\n", + "```\n", + "\n", + "Nested lists/tuples will be used to construct multidimensional arrays. For example, a \"list of equal-length lists of numbers\" will lead to a 2-dimensional array; each of the inner-lists comprises a row of the array. Thus a list of two, length-three lists will produce a (2,3)-shaped array:\n", + " \n", + "```python\n", + "# a list of lists of numbers will produce a 2D-array\n", + ">>> np.array([[1., 2., 3.], [4., 5., 6.]]) # shape: (2, 3)\n", + "array([[ 1., 2., 3.],\n", + " [ 4., 5., 6.]])\n", + "```\n", + "\n", + "A \"list of equal-length lists, of equal-length lists of numbers\" creates a 3D-array, and so on. Recall that using repeated concatenation, `[0]*3` will produce `[0, 0, 0]`. Using this, let's create two lists, each containing three lists, each containing four zeros; feeding this to `np.array` thus produces a 2x3x4 array of zeros:\n", + "```python\n", + "# A list of lists of lists of zeros creates a 3D-array\n", + ">>> np.array([[[0]*4]*3]*2)\n", + "array([[[0, 0, 0, 0],\n", + " [0, 0, 0, 0],\n", + " [0, 0, 0, 0]],\n", + "\n", + " [[0, 0, 0, 0],\n", + " [0, 0, 0, 0],\n", + " [0, 0, 0, 0]]])\n", + "```\n", + "\n", + "You will seldom use lists to form high-dimensional arrays like this. Instead, there are other array-creation functions that are more amendable to generating high-dimensional data, which we will introduce next. For example, we will see that the `np.zeros` function is a much more civilized way to create a high-dimensional array of zeros. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Warning!** \n", + "\n", + "You actually *can* create an array from lists of *unequal* lengths. The resulting array is **not** an ND-array as it has no well-defined dimensionality. Instead, something called an *object-array* is produced, which does not benefit from the majority of NumPy's features. This is a relatively obscure feature of the NumPy library, and should be avoided unless you really know what you're doing!\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating Constant Arrays: `zeros` and `ones`\n", + "NumPy provides the functions `zeros` and `ones`, which will fill an array of user-specified shape with 0s and 1s, respectively:\n", + "\n", + "```python\n", + "# create a 3x4 array of zeros\n", + ">>> np.zeros((3, 4))\n", + "array([[ 0., 0., 0., 0.],\n", + " [ 0., 0., 0., 0.],\n", + " [ 0., 0., 0., 0.]])\n", + "\n", + "# create a shape-(4,) array of ones\n", + ">>> np.ones((4,))\n", + "array([ 1., 1., 1., 1.])\n", + "```\n", + "\n", + "NumPy provides additional functions for creating constant-valued arrays. Please refer to [the official documentation](https://numpy.org/doc/stable/reference/routines.array-creation.html#ones-and-zeros) for a complete listing. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating Sequential Arrays: `arange` and `linspace`\n", + "The [arange](https://numpy.org/doc/stable/reference/generated/numpy.arange.html#numpy.arange) function allows you to initialize a sequence of integers based on a starting point (inclusive), stopping point (exclusive), and step size. This is very similar to the `range` function; however `arange` immediately creates this sequence as an array, whereas `range` produces a generator.\n", + "```python\n", + ">>> np.arange(0, 10, 1) # start (included): 0, stop (excluded): 10, step:1 \n", + "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\n", + "\n", + "# supplying one value to `arange` amounts to specifying the stop value \n", + "# start=0 and step=1 are then used as defaults\n", + ">>> np.arange(10) # equivalent to: start: 0, stop: 10, step:1 \n", + "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\n", + "\n", + ">>> np.arange(-5, 6, 2) # start (included): -5, stop (excluded): 6, step:2 \n", + "array([-5, -3, -1, 1, 3, 5])\n", + "```\n", + "\n", + "The [linspace](https://numpy.org/doc/stable/reference/generated/numpy.linspace.html) function allows you to generate $N$ *evenly-spaced* points within a user-specified interval $[i, j]$ ($i$ and $j$ are included in the interval). This is often used to generate a domain of values on which to evaluate a mathematical function (e.g. if you want to the sine function from $-\\pi$ to $\\pi$ on a finely-divided grid).\n", + "\n", + "```python\n", + "# generate five evenly-spaced points on the interval [-1, 1]\n", + ">>> np.linspace(-1, 1, 5)\n", + "array([-1. , -0.5, 0. , 0.5, 1. ])\n", + "\n", + "# generate two evenly-spaced points on the interval [3, 4]\n", + ">>> np.linspace(3, 4, 2)\n", + "array([ 3., 4.])\n", + "\n", + "# generate 100 evenly-spaced points on the interval [-pi, pi]\n", + ">>> np.linspace(-np.pi, np.pi, 100)\n", + "array([-3.14159265, ..., 3.14159265])\n", + "```\n", + "\n", + "Numpy has other functions for creating sequential arrays, such as producing an array spaced evenly on a log-scaled interval. See the [official documentation](https://numpy.org/doc/stable/reference/routines.array-creation.html#numerical-ranges) for a complete listing." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating Arrays Using Random Sampling\n", + "Several functions can be accessed from `np.random`, which populate arrays of a user-specified shape by drawing randomly from a specified statistical distribution:\n", + "```python\n", + "# create a shape-(3,3) array by drawing its entries randomly\n", + "# from the uniform distribution [0, 1) \n", + ">>> np.random.rand(3,3)\n", + "array([[ 0.09542611, 0.13183498, 0.39836068],\n", + " [ 0.7358235 , 0.77640024, 0.74913595],\n", + " [ 0.37702688, 0.86617624, 0.39846429]])\n", + "\n", + "# create a shape-(5,) array by drawing its entries randomly\n", + "# from a mean-0, variance-1 normal (a.k.a. Gaussian) distribution\n", + ">>> np.random.randn(5)\n", + "array([-1.11262121, -0.35392007, 0.4245215 , -0.81995588, 0.65412323])\n", + "```\n", + "There are [many more functions](https://numpy.org/doc/stable/reference/routines.random.html#distributions) to read about that allow you to draw from a wide variety of statistical distributions. This only scratches the surface of random number generation in NumPy.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating an Array with a Specified Data Type\n", + "Each of the preceding functions used to create an array can be passed a so-called 'keyword' argument, `dtype`, which instructs NumPy to use a specified data type when producing the contents of the array.\n", + "\n", + "```python\n", + "# populate an array using 32-bit floating point numbers\n", + ">>> np.array([1, 2, 3], dtype=\"float32\") \n", + "array([ 1., 2., 3.], dtype=float32)\n", + "\n", + "# default data type produced by `arange` is 32-bit integers\n", + ">>> np.arange(0, 4).dtype \n", + "dtype('int32')\n", + "\n", + "# the data type produced by `arange` can be specified otherwise\n", + ">>> np.arange(0, 4, dtype=\"float16\")\n", + "array([ 0., 1., 2., 3.], dtype=float16)\n", + "\n", + "# generate shape-(4,4) array of 64-bit complex-valued 0s\n", + ">>> np.zeros((4, 4), dtype=\"complex64\")\n", + "array([[ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n", + " [ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n", + " [ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n", + " [ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]], dtype=complex64)\n", + "```\n", + "\n", + "Refer to [the official NumPy documentation](https://numpy.org/doc/stable/user/basics.types.html#array-types-and-conversions-between-types) for the complete list of available array datatypes." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Joining Arrays Together\n", + "Similar to Python lists and tuples, NumPy arrays can be concatenated together. However, because NumPy's arrays can be multi-dimensional, we can choose the dimension along which arrays are joined. \n", + "```python\n", + "# demonstrating methods for joining arrays \n", + ">>> x = np.array([1, 2, 3])\n", + ">>> y = np.array([-1, -2, -3])\n", + "\n", + "# stack `x` and `y` \"vertically\"\n", + ">>> np.vstack([x, y])\n", + "array([[ 1, 2, 3],\n", + " [-1, -2, -3]])\n", + "\n", + "# stack `x` and `y` \"horizontally\"\n", + ">>> np.hstack([x, y])\n", + "array([ 1, 2, 3, -1, -2, -3])\n", + "```\n", + "\n", + "A complete listing of functions for joining arrays can be [found in the official NumPy documentation](https://numpy.org/doc/stable/reference/routines.array-manipulation.html#joining-arrays). There are also corresponding functions for splitting an array into independent arrays." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Links to Official Documentation\n", + "\n", + "- [Constant arrays](https://numpy.org/doc/stable/reference/routines.array-creation.html#ones-and-zeros)\n", + "- [numpy.array](https://numpy.org/doc/stable/reference/generated/numpy.array.html#numpy-array)\n", + "- [Sequential arrays](https://numpy.org/doc/stable/reference/routines.array-creation.html#numerical-ranges)\n", + "- [Random distributions](https://numpy.org/doc/stable/reference/routines.random.html#distributions)\n", + "- [Array types](https://numpy.org/doc/stable/user/basics.types.html#array-types-and-conversions-between-types)\n", + "- [Joining arrays](https://numpy.org/doc/stable/reference/routines.array-manipulation.html#joining-arrays)" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module3_IntroducingNumpy/IntroducingTheNDarray.html b/docs_backup/Module3_IntroducingNumpy/IntroducingTheNDarray.html index 6faf56f5..1128e9bd 100644 --- a/docs_backup/Module3_IntroducingNumpy/IntroducingTheNDarray.html +++ b/docs_backup/Module3_IntroducingNumpy/IntroducingTheNDarray.html @@ -1,45 +1,49 @@ - - + - + - + Introducing the ND-array — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ + + @@ -155,11 +161,13 @@ + +
      -
    • Docs »
    • +
    • »
    • Module 3: The Essentials of NumPy »
    • @@ -168,7 +176,7 @@
    • - + View page source @@ -187,13 +195,13 @@ /* CSS overrides for sphinx_rtd_theme */ /* 24px margin */ -.nbinput.nblast, -.nboutput.nblast { +.nbinput.nblast.container, +.nboutput.nblast.container { margin-bottom: 19px; /* padding has already 5px */ } /* ... except between code cells! */ -.nblast + .nbinput { +.nblast.container + .nbinput.container { margin-top: -19px; } @@ -209,17 +217,17 @@

      Introducing the ND-array

      It is time to start familiarizing ourselves with NumPy, the premiere library for doing numerical work in Python. To use this package, we need to be sure to “import” the NumPy module into our code:

      -
      import numpy as np
      +
      import numpy as np
       

      You could have run import numpy instead, but the prescribed method allows us to use the abbreviation ‘np’ throughout our code, instead of having to write ‘numpy’. This is a very common abbreviation to use.

      The ND-array (N-dimensional array) is the star of the show for NumPy. This array simply stores a sequence of numbers. Like a Python list, you can access individual entries in this array by “indexing” into the array, and you can access a sub-sequence of the array by “slicing” it. So what distinguishes NumPy’s ND-array from a Python list, and why is there a whole numerical library that revolves around this array? There are two major features that makes the ND-array special. It can:

        -
      1. Provide an interface for its underlying data to be accessed along multiple dimensions.
      2. -
      3. Rapidly perform mathematical operations over all of its elements, or over patterned subsequences of its elements, using compiled C code instead of Python; this is a process called vectorization.
      4. +
      5. Provide an interface for its underlying data to be accessed along multiple dimensions.

      6. +
      7. Rapidly perform mathematical operations over all of its elements, or over patterned subsequences of its elements, using compiled C code instead of Python; this is a process called vectorization.

      Let’s take a sneak peek to see what this module has in store. The following code creates an ND-array containing the numbers 0-8:

      -
      >>> import numpy as np
      +
      >>> import numpy as np
       >>> x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8])
       
      @@ -229,7 +237,7 @@

      Introducing the ND-arraynumpy.ndarray >>> isinstance(x, np.ndarray) -True +True

      We can “reshape” this array so that its contents can be accessed along 2 dimensions:

      @@ -277,9 +285,9 @@

      Introducing the ND-array

      Links to Official Documentation

      @@ -289,29 +297,29 @@

      Links to Official Documentation - - - - - - + +

      -

      - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

      - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. -
    @@ -320,7 +328,6 @@

    Links to Official Documentation jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module3_IntroducingNumpy/IntroducingTheNDarray.ipynb b/docs_backup/Module3_IntroducingNumpy/IntroducingTheNDarray.ipynb new file mode 100644 index 00000000..a3731239 --- /dev/null +++ b/docs_backup/Module3_IntroducingNumpy/IntroducingTheNDarray.ipynb @@ -0,0 +1,135 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Introduction to numpy arrays, Difficulty: Easy, Category: Section\n", + " :keywords: numpy array, ndarray, introduction, overview" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introducing the ND-array\n", + "It is time to start familiarizing ourselves with NumPy, the premiere library for doing numerical work in Python. To use this package, we need to be sure to \"import\" the NumPy module into our code:\n", + "\n", + "```python\n", + "import numpy as np\n", + "```\n", + "\n", + "You could have run `import numpy` instead, but the prescribed method allows us to use the abbreviation 'np' throughout our code, instead of having to write 'numpy'. This is a very common abbreviation to use.\n", + "\n", + "The ND-array (N-dimensional array) is the star of the show for NumPy. This array simply stores a sequence of numbers. Like a Python list, you can access individual entries in this array by \"indexing\" into the array, and you can access a sub-sequence of the array by \"slicing\" it. So what distinguishes NumPy's ND-array from a Python list, and why is there a whole numerical library that revolves around this array? There are two major features that makes the ND-array special. It can:\n", + "\n", + " 1. Provide an interface for its underlying data to be accessed along multiple dimensions.\n", + " 2. Rapidly perform mathematical operations over all of its elements, or over patterned subsequences of its elements, using compiled C code instead of Python; this is a process called vectorization.\n", + " \n", + "Let's take a sneak peek to see what this module has in store. The following code creates an ND-array containing the numbers 0-8:\n", + "\n", + "```python\n", + ">>> import numpy as np\n", + ">>> x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8])\n", + "```\n", + "\n", + "This object belongs to the NumPy-defined type `numpy.ndarray`.\n", + "\n", + "```python\n", + "# An ND-array belongs to the type `numpy.ndarray`\n", + ">>> type(x)\n", + "numpy.ndarray\n", + "\n", + ">>> isinstance(x, np.ndarray)\n", + "True\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can \"reshape\" this array so that its contents can be accessed along 2 dimensions:\n", + "```python\n", + ">>> x = x.reshape(3,3)\n", + ">>> x\n", + "array([[0, 1, 2],\n", + " [3, 4, 5],\n", + " [6, 7, 8]])\n", + "```\n", + "\n", + "We will utilize one of NumPy's \"vectorized\" functions to square each entry in the array (without us needing to write a for-loop) \n", + "```python\n", + ">>> np.power(x, 2) # can also be calculated using the shorthand: x**2\n", + "array([[ 0, 1, 4],\n", + " [ 9, 16, 25],\n", + " [36, 49, 64]], dtype=int32)\n", + "```\n", + "\n", + "Let's take the mean value along the three distinct rows of our data:\n", + "```python\n", + ">>> np.mean(x, axis=1)\n", + "array([ 1., 4., 7.])\n", + "```\n", + "\n", + "We can use broadcasting to raise each column of `x` to a different power:\n", + "```python\n", + ">>> x ** np.array([0., 1., 2.])\n", + "array([[ 1., 1., 4.],\n", + " [ 1., 4., 25.],\n", + " [ 1., 7., 64.]])\n", + "```\n", + "\n", + "Basic indexing allows us to access multi-dimensional slices of `x`:\n", + "```python\n", + ">>> x[:2, :3]\n", + "array([[0, 1, 2],\n", + " [3, 4, 5]])\n", + "```\n", + "\n", + "Advanced indexing can be used to access all even-valued entries of `x`; let's update `x` so that all of its even-valued entries are multiplied by -1:\n", + "\n", + "```python\n", + ">>> x[x % 2 == 0] *= -1\n", + ">>> x\n", + "array([[ 0, 1, -2],\n", + " [ 3, -4, 5],\n", + " [-6, 7, -8]])\n", + "```\n", + "\n", + "By the end of this module, these code snippets should make good sense, and NumPy's tremendous utility should be clear." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Links to Official Documentation\n", + "\n", + "- [The N-dimensional array](https://numpy.org/doc/stable/reference/arrays.ndarray.html)\n", + "- [NumPy Basics](https://numpy.org/doc/stable/user/basics.html#numpy-basics)\n", + "- [NumPy reference](https://numpy.org/doc/stable/reference/index.html)" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module3_IntroducingNumpy/Problems/Approximating_pi.html b/docs_backup/Module3_IntroducingNumpy/Problems/Approximating_pi.html index 0de96ed8..39fdc687 100644 --- a/docs_backup/Module3_IntroducingNumpy/Problems/Approximating_pi.html +++ b/docs_backup/Module3_IntroducingNumpy/Problems/Approximating_pi.html @@ -1,43 +1,47 @@ - - + - + - + Playing Darts and Estimating Pi — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -82,6 +86,7 @@ + + @@ -152,11 +158,13 @@ + +
      -
    • Docs »
    • +
    • »
    • Module 3: Problems »
    • @@ -165,7 +173,7 @@
    • - + View page source @@ -184,31 +192,45 @@ /* CSS for nbsphinx extension */ /* remove conflicting styling from Sphinx themes */ -div.nbinput, -div.nbinput div.prompt, -div.nbinput div.input_area, -div.nbinput div[class*=highlight], -div.nbinput div[class*=highlight] pre, -div.nboutput, -div.nbinput div.prompt, -div.nbinput div.output_area, -div.nboutput div[class*=highlight], -div.nboutput div[class*=highlight] pre { - background: none; +div.nbinput.container div.prompt *, +div.nboutput.container div.prompt *, +div.nbinput.container div.input_area pre, +div.nboutput.container div.output_area pre, +div.nbinput.container div.input_area .highlight, +div.nboutput.container div.output_area .highlight { border: none; - padding: 0 0; + padding: 0; margin: 0; box-shadow: none; } +div.nbinput.container > div[class*=highlight], +div.nboutput.container > div[class*=highlight] { + margin: 0; +} + +div.nbinput.container div.prompt *, +div.nboutput.container div.prompt * { + background: none; +} + +div.nboutput.container div.output_area .highlight, +div.nboutput.container div.output_area pre { + background: unset; +} + +div.nboutput.container div.output_area div.highlight { + color: unset; /* override Pygments text color */ +} + /* avoid gaps between output lines */ -div.nboutput div[class*=highlight] pre { +div.nboutput.container div[class*=highlight] pre { line-height: normal; } /* input/output containers */ -div.nbinput, -div.nboutput { +div.nbinput.container, +div.nboutput.container { display: -webkit-flex; display: flex; align-items: flex-start; @@ -216,92 +238,104 @@ width: 100%; } @media (max-width: 540px) { - div.nbinput, - div.nboutput { + div.nbinput.container, + div.nboutput.container { flex-direction: column; } } /* input container */ -div.nbinput { +div.nbinput.container { padding-top: 5px; } /* last container */ -div.nblast { +div.nblast.container { padding-bottom: 5px; } /* input prompt */ -div.nbinput div.prompt pre { +div.nbinput.container div.prompt pre { color: #307FC1; } /* output prompt */ -div.nboutput div.prompt pre { +div.nboutput.container div.prompt pre { color: #BF5B3D; } /* all prompts */ -div.nbinput div.prompt, -div.nboutput div.prompt { - min-width: 5ex; - padding-top: 0.4em; - padding-right: 0.4em; - text-align: right; - flex: 0; +div.nbinput.container div.prompt, +div.nboutput.container div.prompt { + width: 4.5ex; + padding-top: 5px; + position: relative; + user-select: none; } + +div.nbinput.container div.prompt > div, +div.nboutput.container div.prompt > div { + position: absolute; + right: 0; + margin-right: 0.3ex; +} + @media (max-width: 540px) { - div.nbinput div.prompt, - div.nboutput div.prompt { + div.nbinput.container div.prompt, + div.nboutput.container div.prompt { + width: unset; text-align: left; padding: 0.4em; } - div.nboutput div.prompt.empty { + div.nboutput.container div.prompt.empty { padding: 0; } + + div.nbinput.container div.prompt > div, + div.nboutput.container div.prompt > div { + position: unset; + } } /* disable scrollbars on prompts */ -div.nbinput div.prompt pre, -div.nboutput div.prompt pre { +div.nbinput.container div.prompt pre, +div.nboutput.container div.prompt pre { overflow: hidden; } /* input/output area */ -div.nbinput div.input_area, -div.nboutput div.output_area { - padding: 0.4em; +div.nbinput.container div.input_area, +div.nboutput.container div.output_area { -webkit-flex: 1; flex: 1; overflow: auto; } @media (max-width: 540px) { - div.nbinput div.input_area, - div.nboutput div.output_area { + div.nbinput.container div.input_area, + div.nboutput.container div.output_area { width: 100%; } } /* input area */ -div.nbinput div.input_area { +div.nbinput.container div.input_area { border: 1px solid #e0e0e0; border-radius: 2px; - background: #f5f5f5; + /*background: #f5f5f5;*/ } /* override MathJax center alignment in output cells */ -div.nboutput div[class*=MathJax] { +div.nboutput.container div[class*=MathJax] { text-align: left !important; } /* override sphinx.ext.imgmath center alignment in output cells */ -div.nboutput div.math p { +div.nboutput.container div.math p { text-align: left; } /* standard error */ -div.nboutput div.output_area.stderr { +div.nboutput.container div.output_area.stderr { background: #fdd; } @@ -345,6 +379,28 @@ .ansi-bold { font-weight: bold; } .ansi-underline { text-decoration: underline; } + +div.nbinput.container div.input_area div[class*=highlight] > pre, +div.nboutput.container div.output_area div[class*=highlight] > pre, +div.nboutput.container div.output_area div[class*=highlight].math, +div.nboutput.container div.output_area.rendered_html, +div.nboutput.container div.output_area > div.output_javascript, +div.nboutput.container div.output_area:not(.rendered_html) > img{ + padding: 5px; + margin: 0; +} + +/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */ +div.nbinput.container div.input_area > div[class^='highlight'], +div.nboutput.container div.output_area > div[class^='highlight']{ + overflow-y: hidden; +} + +/* hide copybtn icon on prompts (needed for 'sphinx_copybutton') */ +.prompt a.copybtn { + display: none; +} + /* Some additional styling taken form the Jupyter notebook CSS */ div.rendered_html table { border: none; @@ -382,13 +438,13 @@ /* CSS overrides for sphinx_rtd_theme */ /* 24px margin */ -.nbinput.nblast, -.nboutput.nblast { +.nbinput.nblast.container, +.nboutput.nblast.container { margin-bottom: 19px; /* padding has already 5px */ } /* ... except between code cells! */ -.nblast + .nbinput { +.nblast.container + .nbinput.container { margin-top: -19px; } @@ -416,13 +472,13 @@

      Playing Darts and Estimating Pi\(N_{total}\) is the total number of darts thrown, and \(N_{circle}\) is the number of darts that land within the circle. Thus simply by keeping tally of where the darts land, you can begin to estimate the value of \(\pi\)!

      Problem 1

      -

      Write code that simulates the dart throwing and tallying process, and keep a running estimate of \(\pi\) as “darts are being thrown”. For simplicity, you can assume that the board is centered at \((0, 0)\), and that \(r = 1\) (the radius of the circle). Use numpy.random.rand (link to docs) to randomly generate the positions on the board where the darts land. Do this for \(N = 10,000\) darts in +

      Write code that simulates the dart throwing and tallying process, and keep a running estimate of \(\pi\) as “darts are being thrown”. For simplicity, you can assume that the board is centered at \((0, 0)\), and that \(r = 1\) (the radius of the circle). Use numpy.random.rand (link to docs) to randomly generate the positions on the board where the darts land. Do this for \(N = 10,000\) darts in total. For each dart thrown determine whether or not it landed within the circle, and update your estimate of \(\pi\) according to the formula: \(N_{circle} / N_{total} \approx \pi / 4\)

      Keep in mind that each dart can land in \((x \in [-1, 1], y \in [-1, 1])\) and that a dart that lands at \((x, y)\) falls within the circle if

      \begin{equation} \sqrt{x^2 + y^2} < 1 -\end{equation}

      You can start this problem by writing a solution that uses explicit for-loops to help make clear the solution. That being said, you should strive to write a fully-vectorized solution (i.e. compute the running estimation of \(\pi\) during \(10,000\) dart throws without any explicit for-loops).

      +\end{equation}

      You can start this problem by writing a solution that uses explicit for-loops to help make clear the solution. That being said, you should strive to write a fully-vectorized solution (i.e. compute the running estimation of \(\pi\) during \(10,000\) dart throws without any explicit for-loops).

    Relevant Reading

    @@ -432,7 +488,7 @@

    Relevant Reading

    Tips

    -

    It is helpful to know about NumPy’s cumulative-sum function, numpy.cumsum. This is useful for keeping a running tally - i.e. keeping the history of the number of darts that have fallen within the circle, and not just the current count.

    +

    It is helpful to know about NumPy’s cumulative-sum function, numpy.cumsum. This is useful for keeping a running tally - i.e. keeping the history of the number of darts that have fallen within the circle, and not just the current count.

    Solution (Unvectorized)

    @@ -493,8 +549,9 @@

    Solution (Unvectorized)
    [4]:
     

    -
    -
    +
    + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@
    + + @@ -149,11 +155,13 @@ + +

    Recall that the is operator checks to see if two items reference the exact same object in your computer’s memory. Also recall that the built-in isinstance function checks to see if an object is an instance of a class/type. These will help us understand the relationship between class objects, their instances, and references to objects.

    @@ -290,10 +298,10 @@

    Object Identity and Creating an Instance# d1 is not Dummy; it is an instance of Dummy >>> d1 is Dummy -False +False >>> isinstance(d1, Dummy) -True +True

    See that Dummy is to d1 as list is to [1, 4, "a"]

    @@ -305,10 +313,10 @@

    Object Identity and Creating an Instance<__main__.Dummy at 0x2ae8f666f60> >>> d2 is d1 # `d2` and `d1` are distinct instances of `Dummy` -False +False >>> isinstance(d2, Dummy) -True +True

    Python’s rules for referencing objects with variables still apply here: assigning an object to a variable, be it a class object or an instance, does not create a distinct copy of that object. The variable merely references that object, serving only as an alias for it.

    @@ -316,7 +324,7 @@

    Object Identity and Creating an Instance>>> A = Dummy >>> A is Dummy -True +True # creates an instance of `Dummy`, using `A` >>> dummy_instance = A() @@ -324,13 +332,13 @@

    Object Identity and Creating an Instance<__main__.Dummy at 0x2ae8f65fcf8> >>> isinstance(dummy_instance, A) # equivalent to `isinstance(dummy_instance, Dummy)` -True +True # `var` references the Dummy-instance `dummy_instance` >>> var = dummy_instance >>> var is dummy_instance -True +True # setting a new value to `var.x` is equivalent to # setting that value to `dummy_instance.x` @@ -364,11 +372,11 @@

    Object Identity and Creating an Instancey and y1 share?

    Next, identify each of the following objects as a class object or an instance (and if instance, an instance of what)

      -
    • "hello world"
    • -
    • True
    • -
    • int
    • -
    • {"a" : 22}
    • -
    • tuple
    • +
    • "hello world"

    • +
    • True

    • +
    • int

    • +
    • {"a" : 22}

    • +
    • tuple

    Now that we know the basics of how to create an instance of a class, understand the relationship between class objects and instances, and understand the distinction between instances that are independent from one another, we can move on to learning about creating instance-level attributes for our class.

    @@ -406,18 +414,18 @@

    Defining Instance-Level Attributes: the Person (this is very important):

      -
    • Invoking Person("Kamasi") first creates an instance of Person as if there was no __init__ method specified. The resulting object does not yet have a name attribute. It only has the class-level attribute x.
    • -
    • Next, that instance of Person is passed to __init__ as the argument self, and "Kamasi", which we provided explicitly, is passed as the argument name.
    • -
    • With these arguments, Person.__init__(self, "Kamasi") executes its body of instructions. Specifically, self.name = name sets the attribute name on self, using the value "Kamasi".
    • -
    • Having finished executing the __init__ method, Person("Kamasi") resolves by returning the instance-object that was created.
    • +
    • Invoking Person("Kamasi") first creates an instance of Person as if there was no __init__ method specified. The resulting object does not yet have a name attribute. It only has the class-level attribute x.

    • +
    • Next, that instance of Person is passed to __init__ as the argument self, and "Kamasi", which we provided explicitly, is passed as the argument name.

    • +
    • With these arguments, Person.__init__(self, "Kamasi") executes its body of instructions. Specifically, self.name = name sets the attribute name on self, using the value "Kamasi".

    • +
    • Having finished executing the __init__ method, Person("Kamasi") resolves by returning the instance-object that was created.

    We now have the ability to define and set attributes on an instance-level! Understanding this process is critical to mastering object oriented programming in Python. Let’s create several Person-instances, all stored in a list:

    -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. -
    @@ -601,7 +609,6 @@

    Reading Comprehension Solutions jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module4_OOP/ClassInstances.ipynb b/docs_backup/Module4_OOP/ClassInstances.ipynb new file mode 100644 index 00000000..746deeb3 --- /dev/null +++ b/docs_backup/Module4_OOP/ClassInstances.ipynb @@ -0,0 +1,521 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Class instances versus objects, Difficulty: Medium, Category: Section\n", + " :keywords: instance, class creation, init, self, isinstance" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Instances of a Class\n", + "\n", + "Thus far we have learned about the syntax for defining a new class of object, specifying its name, attributes, and methods (which are attributes that are functions). Once we leave the scope of the class definition, a class object is formed - the resulting *class object* is the singular object that encapsulates our class definition. We seldom will want to pass around or manipulate this class object once it is created. Rather, we will want to use it to create individual *instances* of that class. To be more concrete, `list` is a class object (remember that \"class\" and \"type\" are synonymous) - it is the same sort of object that is produced when a `class` definition is executed. As you saw in [Module 2](http://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Lists), we can use this class object to create individual *instances* of the list class, each one containing its own sequence of items.\n", + "\n", + "```python\n", + "# using the class object `list` to create list-instances\n", + ">>> list() # create a `list`-instance that is empty\n", + "[]\n", + "\n", + ">>> list((1, 2, 3)) # create a `list`-instance containing 1, 2, and 3\n", + "[1, 2, 3]\n", + "\n", + "# `a` and `b` are distinct instances of the list class/type\n", + "# even though they contain the same sequence of integers\n", + ">>> a = list((1, 2, 3))\n", + ">>> b = list((1, 2, 3))\n", + ">>> a is b\n", + "False\n", + "\n", + ">>> isinstance(a, list)\n", + "True\n", + "\n", + ">>> isinstance(b, list)\n", + "True\n", + "\n", + "# Calling the append method on `a` only affects that particular \n", + "# list-instance.\n", + ">>> a.append(-1)\n", + ">>> a\n", + "[1, 2, 3, -1]\n", + "\n", + ">>> b\n", + "[1, 2, 3]\n", + "```\n", + "\n", + "Each of these instances share the common attributes `append`, `count`, `reverse`, and so on, as specified in the definition of Python's list class, which is encapsulated by the `list` class object. That being said, the specific content of any given list is an attribute of that particular list instance; that is, the content of a particular list is an *instance attribute* rather than a class attribute. Thus far, we do not have the ability to create instance-level attributes. Let's change that.\n", + "\n", + "Suppose that we want to make our own `Person` class. Each person should have her/his own name, thus the name should be an instance-level attribute. We will learn to define a special initialization method that allows us to define and set instance-level attributes. In the context of `Person`, this will allow us to give each person their own name:\n", + "\n", + "```python\n", + ">>> class Person:\n", + "... def __init__(self, name):\n", + "... self.name = name\n", + "\n", + ">>> emmy = Person(\"Emmy\")\n", + ">>> niels = Person(\"Niels\")\n", + "\n", + ">>> emmy.name\n", + "'Emmy'\n", + "\n", + ">>> niels.name\n", + "'Niels'\n", + "\n", + ">>> isinstance(emmy, Person)\n", + "True\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will learn about the `__init__` method and that peculiar `self` argument momentarily. First, we will learn about creating an instance object from a class object." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Object Identity and Creating an Instance\n", + "\n", + "Here we will learn the basic mechanism for creating an instance of a class. Consider the following trivial class definition:\n", + "\n", + "```python\n", + "class Dummy:\n", + " x = 1\n", + "```\n", + "\n", + "We can use the \"call\" syntax on `Dummy`, `Dummy()`, to create individual instances of this class:\n", + "\n", + "```python\n", + "# create an object that is an instance of our Dummy class\n", + ">>> d1 = Dummy()\n", + "\n", + ">>> isinstance(d1, Dummy)\n", + "True\n", + "```\n", + "\n", + "Recall that the `is` operator checks to see if two items reference the exact same object in your computer's memory. Also recall that the built-in `isinstance` function checks to see if an object is an instance of a class/type. These will help us understand the relationship between class objects, their instances, and references to objects.\n", + "\n", + "```python\n", + "# `Dummy` is the class object that encapsulates\n", + "# our class definition\n", + ">>> Dummy\n", + "__main__.Dummy\n", + "\n", + "# `d1` is an object that is an instance of our Dummy class.\n", + "# this instance resides at some memory address (0x2ae8f68f2e8)\n", + ">>> d1\n", + "<__main__.Dummy at 0x2ae8f68f2e8>\n", + "\n", + "# d1 is not Dummy; it is an instance of Dummy\n", + ">>> d1 is Dummy \n", + "False\n", + "\n", + ">>> isinstance(d1, Dummy)\n", + "True\n", + "```\n", + "See that `Dummy` is to `d1` as `list` is to `[1, 4, \"a\"]` \n", + "\n", + "Let's create another instance of `Dummy`. It is important to understand that this new instance is *distinct* from the one that we already created.\n", + "\n", + "```python\n", + "# `d2` is a new instance of our Dummy class.\n", + "# It resides at a distinct memory address (0x2ae8f666f60)\n", + ">>> d2 = Dummy()\n", + ">>> d2\n", + "<__main__.Dummy at 0x2ae8f666f60>\n", + "\n", + ">>> d2 is d1 # `d2` and `d1` are distinct instances of `Dummy`\n", + "False\n", + "\n", + ">>> isinstance(d2, Dummy)\n", + "True\n", + "```\n", + "\n", + "Python's [rules for referencing objects with variables](http://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Variables_and_Assignment.html) still apply here: assigning an object to a variable, be it a class object or an instance, does not create a distinct copy of that object. The variable merely references that object, serving only as an alias for it.\n", + "\n", + "```python\n", + "# `A` references `Dummy`\n", + ">>> A = Dummy\n", + "\n", + ">>> A is Dummy\n", + "True\n", + "\n", + "# creates an instance of `Dummy`, using `A`\n", + ">>> dummy_instance = A() \n", + ">>> dummy_instance \n", + "<__main__.Dummy at 0x2ae8f65fcf8>\n", + "\n", + ">>> isinstance(dummy_instance, A) # equivalent to `isinstance(dummy_instance, Dummy)`\n", + "True\n", + "\n", + "# `var` references the Dummy-instance `dummy_instance`\n", + ">>> var = dummy_instance\n", + "\n", + ">>> var is dummy_instance\n", + "True\n", + "\n", + "# setting a new value to `var.x` is equivalent to \n", + "# setting that value to `dummy_instance.x`\n", + ">>> var.x = 22\n", + ">>> dummy_instance.x\n", + "22\n", + "\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Reading Comprehension: Class Initialization**\n", + "\n", + "Using the `Dummy` class defined above, create a list consisting of 10 *distinct* instances of this type. Write code to explicitly verify that each entry is distinct from the other, and that each entry is an instance of the `Dummy` class.\n", + "\n", + "Then, create a tuple that contains a *single* instance of `Dummy` stored ten times. Write code to explicitly verify that the entries all reference the exact same object, and that each entry is an instance of the `Dummy` class.\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Reading Comprehension: Terminology**\n", + "\n", + "Given:\n", + "```python\n", + ">>> class Cat:\n", + "... pass\n", + "\n", + ">>> x = Cat\n", + ">>> y = Cat()\n", + ">>> x1 = x\n", + ">>> x2 = x()\n", + ">>> y1 = y\n", + "```\n", + "\n", + "What relationship do `x` and `Cat` share?\n", + "\n", + "What relationship do `y` and `Cat` share?\n", + "\n", + "What relationship do `x` and `y` share?\n", + "\n", + "What relationship do `x2` and `y` share?\n", + "\n", + "What relationship do `y` and `y1` share?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, identify each of the following objects as a class object or an instance (and if instance, an instance of what)\n", + "\n", + " - `\"hello world\"`\n", + " - `True`\n", + " - `int`\n", + " - `{\"a\" : 22}`\n", + " - `tuple`\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we know the basics of how to create an instance of a class, understand the relationship between class objects and instances, and understand the distinction between instances that are independent from one another, we can move on to learning about creating instance-level attributes for our class." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Defining Instance-Level Attributes: the `__init__` Method\n", + "\n", + "As demonstrated in the `Person` class that we defined earlier in this section, and the `Rectangle` class that we defined in this module's introduction section, there is a special method, `__init__`, that allows us to define instance-level attributes for our class. This is a critically-important method, which we will leverage often. Note that the name of this is: \"underscore-underscore-init-underscore-underscore\", which can be pronounced as \"dunder-init\" (where \"dunder\" stands for double-underscore). \n", + "\n", + "Consider the slightly-modified definition of `Person`, which also includes the class-attribute `x`:\n", + "\n", + "```python\n", + "class Person:\n", + " x = 1 # this sets a class-level attribute, common to all instances of `Person`\n", + " \n", + " def __init__(self, name):\n", + " \"\"\" This method is executed every time we create a new `Person` instance. \n", + " `self` is the object instance being created.\"\"\"\n", + " self.name = name # set the attribute `name` to the Person-instance `self`\n", + " \n", + " # __init__ cannot not return any value other than `None`. Its sole purpose is to affect\n", + " # `self`, the instance of `Person` that is being created.\n", + "```\n", + "\n", + "Invoking `Person()` actually calls `__init__()` \"under the hood\", and any argument that we feed to `Person()` gets passed to `__init__`. Looking at our definition of `__init__` it looks like we must pass two values to this method: `self` and `name`. This first argument, `self`, actually represents the object instance of `Person` that is being created. Python will pass the appropriate object for `self` to `__init__` automatically, thus we need only worry about passing a value for `name`. \n", + "\n", + "Let's make an instance of our `Person` class, passing the string `\"Kamasi\"` as the name:\n", + "\n", + "```python\n", + "# Creates the instance `self`, passes it \n", + "# and `\"Kamasi\"` to `Person.__init__`, and then\n", + "# returns the instance-object that was created\n", + ">>> p = Person(\"Kamasi\") \n", + "\n", + ">>> p.name # access the instance-attribute `name`\n", + "'Kamasi'\n", + ">>> p.x # access the class-attribute `x`\n", + "1\n", + "```\n", + "\n", + "Here is what is going on \"under the hood\" when we create this instance of `Person` (**this is very important**):\n", + "\n", + "- Invoking `Person(\"Kamasi\")` first creates an instance of `Person` as if there was no `__init__` method specified. The resulting object does not yet have a `name` attribute. It only has the class-level attribute `x`.\n", + "- Next, that instance of `Person` is passed to `__init__` as the argument `self`, and `\"Kamasi\"`, which we provided explicitly, is passed as the argument `name`. \n", + "- With these arguments, `Person.__init__(self, \"Kamasi\")` executes its body of instructions. Specifically, `self.name = name` sets the attribute `name` on `self`, using the value `\"Kamasi\"`. \n", + "- Having finished executing the `__init__` method, `Person(\"Kamasi\")` resolves by returning the instance-object that was created.\n", + "\n", + "We now have the ability to define and set attributes on an instance-level! Understanding this process is critical to mastering object oriented programming in Python. Let's create several `Person`-instances, all stored in a list:\n", + "\n", + "```python\n", + "# creating several instances of `Person`\n", + ">>> list_of_people = [Person(n) for n in (\"Fermi\", \"Noether\", \"Euler\")]\n", + "\n", + ">>> for person in list_of_people:\n", + "... print(person.name)\n", + "... print(person.x)\n", + "Fermi\n", + "1\n", + "Noether\n", + "1\n", + "Euler\n", + "1\n", + "```\n", + "\n", + "Updating the class-level attribute `x` of `Person` affects all instances of `Person`:\n", + "```python\n", + "# setting a new value to the class-attribute `x`\n", + ">>> Person.x = 22 \n", + "\n", + "# this affects all instances of `Person`\n", + ">>> for person in list_of_people:\n", + "... print(person.name)\n", + "... print(person.x)\n", + "Fermi\n", + "22\n", + "Noether\n", + "22\n", + "Euler\n", + "22\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Reading Comprehension: Instance Attributes**\n", + "\n", + "Define a class, `Tmp`, that has three instance attributes: `x`, `y`, and `z`. `x` and `y` should be numbers that are set according to values passed to the instance creation, and `z` should be the product of these two values. \n", + "\n", + "For example:\n", + "```python\n", + ">>> tmp = Tmp(2.1, 3.0)\n", + ">>> tmp.x\n", + "2.1\n", + "\n", + ">>> tmp.y\n", + "3.0\n", + "\n", + ">>> tmp.z\n", + "6.3\n", + "```\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You should now have a grasp of how the special `__init__` method can be used to define and set instance-level attributes for your classes. Furthermore, the basic process by which invoking class instantiation produces an instance object which then automatically gets passed to `__init__` as the `self` argument, should be salient. In the following section, we will encounter three varieties of methods: instance methods, class methods, and static methods. Additionally, we will encounter even more so-called \"special methods\", similar to `__init__`, which can be used to more broadly specify how your class behaves and interacts with Python's operators. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reading Comprehension Solutions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Solution: Class Initialization**\n", + "\n", + "Using the `Dummy` class defined above, create a list consisting of 10 *distinct* instances of this type\n", + "\n", + "```python\n", + "# will call `Dummy()` once for each iteration\n", + ">>> list_of_dummies = [Dummy() for i in range(10)] \n", + "\n", + "# note the distinct memory addresses\n", + ">>> list_of_dummies\n", + "[<__main__.Dummy at 0x1d50de89940>,\n", + " <__main__.Dummy at 0x1d50de896d8>,\n", + " <__main__.Dummy at 0x1d50de897b8>,\n", + " <__main__.Dummy at 0x1d50de89a20>,\n", + " <__main__.Dummy at 0x1d50de89ac8>,\n", + " <__main__.Dummy at 0x1d50de89a58>,\n", + " <__main__.Dummy at 0x1d50de899e8>,\n", + " <__main__.Dummy at 0x1d50de89a90>,\n", + " <__main__.Dummy at 0x1d50de89b00>,\n", + " <__main__.Dummy at 0x1d50de89b38>]\n", + "```\n", + "\n", + "Write code to explicitly verify that each entry is distinct from the other, and that each entry is an instance of the `Dummy` class.\n", + "\n", + "```python\n", + ">>> from itertools import combinations\n", + "# `combinations(list_of_dummies, 2)` loops over all pairs of entries\n", + "# in `list_of_dummies`\n", + ">>> all(a is not b for a,b in combinations(list_of_dummies, 2))\n", + "True\n", + "\n", + ">>> all(isinstance(a, Dummy) for a in list_of_dummies)\n", + "True\n", + "```\n", + "\n", + "Create a tuple contains a *single* instance of `Dummy` ten times. Note here that we initialize `Dummy` once, and that the tuple-comprehension merely populates the tuple with that same instance ten times. \n", + "```python\n", + ">>> dummy = Dummy() # a single instance of `Dummy`\n", + ">>> tuple_of_dummy = tuple(dummy for i in range(10))\n", + "\n", + "# note that the memory addresses are identical\n", + ">>> tuple_of_dummy\n", + "(<__main__.Dummy at 0x1d50de887b8>,\n", + " <__main__.Dummy at 0x1d50de887b8>,\n", + " <__main__.Dummy at 0x1d50de887b8>,\n", + " <__main__.Dummy at 0x1d50de887b8>,\n", + " <__main__.Dummy at 0x1d50de887b8>,\n", + " <__main__.Dummy at 0x1d50de887b8>,\n", + " <__main__.Dummy at 0x1d50de887b8>,\n", + " <__main__.Dummy at 0x1d50de887b8>,\n", + " <__main__.Dummy at 0x1d50de887b8>,\n", + " <__main__.Dummy at 0x1d50de887b8>)\n", + "```\n", + "\n", + "Write code to explicitly verify that the entries all reference the exact same object, and that each entry is an instance of the `Dummy` class.\n", + "\n", + "```python\n", + ">>> all(dummy is i for i in tuple_of_dummy)\n", + "True\n", + "\n", + ">>> all(isinstance(a, Dummy) for a in tuple_of_dummy)\n", + "True\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Reading Comprehension: Terminology**\n", + "\n", + "Given:\n", + "```python\n", + ">>> class Cat:\n", + "... pass\n", + "\n", + ">>> x = Cat\n", + ">>> y = Cat()\n", + ">>> x1 = x\n", + ">>> x2 = x()\n", + ">>> y1 = y\n", + "```\n", + "\n", + "What relationship do `x` and `Cat` share?: `x` and `Cat` reference the same class object.\n", + "\n", + "What relationship do `y` and `Cat` share?: `y` is an instance of the `Cat` class.\n", + "\n", + "What relationship do `x` and `y` share?: `x` references `Cat`, and `y` is an instance of `Cat`. Thus `y` is an instance of `x`.\n", + "\n", + "What relationship do `x2` and `y` share?: They are independent instances of `Cat`\n", + "\n", + "What relationship do `y` and `y1` share?: They reference the same instance of `Cat`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Identify each of the following objects as a class object or an instance (and if so, an instance of what)\n", + "\n", + " - `\"hello world\"`: An instance of the `str` type (a.k.a class)\n", + " - `True`: an instance of the `bool` type\n", + " - `int`: a class object describing integers\n", + " - `{\"a\" : 22}`: an instance of the `dict` type \n", + " - `tuple`: a class object describing tuples" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Reading Comprehension: Instance Attributes**\n", + "\n", + "Define a class, `Tmp`, that has three instance attributes: `x`, `y`, and `z`. `x` and `y` should be numbers that are set according to values passed to the instance creation, and `z` should be the product of these two values.\n", + "\n", + "```python\n", + "class Tmp:\n", + " def __init__(self, x, y):\n", + " self.x = x\n", + " self.y = y\n", + " self.z = x * y\n", + "```\n", + "\n", + "```python\n", + ">>> test = Tmp(8, 5)\n", + ">>> test.x\n", + "8\n", + ">>> test.y\n", + "5\n", + ">>> test.z\n", + "40\n", + "```" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module4_OOP/Inheritance.html b/docs_backup/Module4_OOP/Inheritance.html index 6e7bf62c..ced38a6b 100644 --- a/docs_backup/Module4_OOP/Inheritance.html +++ b/docs_backup/Module4_OOP/Inheritance.html @@ -1,45 +1,49 @@ - - + - + - + Inheritance — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ + + @@ -155,11 +161,13 @@ + +

    The built-in issubclass function allows us to verify the relationship between Square and Rectangle.

    # `Square` and `Rectangle` are distinct classes
     >>> Square is not Rectangle
    -True
    +True
     
     # `Square` is a subclass of `Rectangle`
     >>> issubclass(Square, Rectangle)
    -True
    +True
     
     # `my_square is an both an instance of `Square` and `Rectangle`
     >>> isinstance(my_square, Square)
    -True
    +True
     
     >>> isinstance(my_square, Rectangle)
    -True
    +True
     
    @@ -324,29 +332,29 @@

    Links to Official Documentation - - - - - - + + -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -355,7 +363,6 @@

    Links to Official Documentation jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module4_OOP/Inheritance.ipynb b/docs_backup/Module4_OOP/Inheritance.ipynb new file mode 100644 index 00000000..ed3850e0 --- /dev/null +++ b/docs_backup/Module4_OOP/Inheritance.ipynb @@ -0,0 +1,183 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Class inheritance, Difficulty: Easy, Category: Section\n", + " :keywords: inherit, object oriented, overwrite, sub class, issubclass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Inheritance\n", + "A final topic for us to discuss in this introduction to object oriented programming is the concept of inheritance. Working with inheritance provides powerful abstractions and elegant code re-use - it permits a class to inherit and build off of the attributes of another class.\n", + "\n", + "Let's immediately consider an example of inheritance in action. Let's revisit the `Rectangle` class that we wrote in the introduction to this module.\n", + "\n", + "```python\n", + "class Rectangle:\n", + " \"\"\" A class of Python object that describes the properties of a rectangle\"\"\"\n", + " def __init__(self, width, height, center=(0, 0)):\n", + " self.width = width \n", + " self.height = height \n", + " self.center = center\n", + "\n", + " def __repr__(self):\n", + " return \"Rectangle(width={w}, height={h}, center={c})\".format(h=self.height,\n", + " w=self.width,\n", + " c=self.center)\n", + "\n", + " def compute_area(self):\n", + " return self.width * self.height\n", + "```\n", + "\n", + "Now suppose that we also want to write a `Square` class, such that only a single side length need be specified to determine its size. Recognize that a square is a special type of rectangle - one whose width and height are equal. In light of this, we ought to leverage the code that we already wrote for `Rectangle`. We can do this by defining a `Square` class that is a *subclass* of `Rectangle`. This means that `Square` will *inherit* all of the attributes of `Rectangle`, including its methods. Let's proceed with writing this subclass:\n", + "\n", + "```python\n", + "# Creating Square, a subclass of Rectangle\n", + "class Square(Rectangle):\n", + " def __init__(self, side, center=(0, 0)):\n", + " # equivalent to `Rectangle.__init__(self, side, side, center)`\n", + " super().__init__(side, side, center)\n", + "```\n", + "\n", + "Specifying `class Square(Rectangle)` signals that `Square` is a subclass of `Rectangle` and thus it will have inherited the attributes of `Rectangle`. Next, see that we overwrote the `__init__` method that `Square` inherited; instead of accepting a height and a width, `Square` should by specified by a single side length. Within this new `__init__` method, we pass in that single side length as both the width and height to `Rectangle.__init__`. `super` always refers to the \"super class\" or \"parent class\" of a given class, thus `super` is `Rectangle` here.\n", + "\n", + "Having defined our subclass, we can leverage the other methods of `Rectangle` as-is. Let's see `Square` in action:\n", + "\n", + "```python\n", + "# create a square of side-length 2\n", + ">>> my_square = Square(2)\n", + "\n", + "# using the inherited `get_area` method\n", + ">>> my_square.get_area()\n", + "4\n", + "\n", + "# a square is a rectangle with equal height/width\n", + ">>> my_square\n", + "Rectangle(width=2, height=2, center=(0.0, 0.0))\n", + "\n", + ">>> my_square.width == my_square.height\n", + "True\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The built-in `issubclass` function allows us to verify the relationship between `Square` and `Rectangle`.\n", + "\n", + "```python\n", + "# `Square` and `Rectangle` are distinct classes\n", + ">>> Square is not Rectangle\n", + "True\n", + "\n", + "# `Square` is a subclass of `Rectangle`\n", + ">>> issubclass(Square, Rectangle)\n", + "True\n", + "\n", + "# `my_square is an both an instance of `Square` and `Rectangle`\n", + ">>> isinstance(my_square, Square)\n", + "True\n", + "\n", + ">>> isinstance(my_square, Rectangle)\n", + "True\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Summary of Inheritance" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In general, if you have a class `A`, then you can define a subclass of `A` via:\n", + "\n", + "```python\n", + "\n", + "class A:\n", + " attr = 0\n", + " \n", + " def method(self):\n", + " return 0\n", + " \n", + "# `B` is a subclass of `A`\n", + "class B(A):\n", + " # inherits `attr` and `method`\n", + " b_attr = -2 # class attribute distinct to `B`\n", + " \n", + " def method(self):\n", + " # overwrites inherited `method`\n", + " return -1\n", + "```\n", + "\n", + "`B` will have inherited all of the attributes and methods of `A`. Defining attributes and methods within the definition of `B` will overwrite those that already exist in `A`. `B` is also free to have its own distinct attributes and methods be defined, irrespective of `A`.\n", + "\n", + "```python\n", + ">>> issubclass(B, A)\n", + "True\n", + "\n", + ">>> A.attr\n", + "0\n", + "\n", + ">>> A().method()\n", + "0\n", + "\n", + ">>> B.attr\n", + "0\n", + "\n", + ">>> B().method()\n", + "-1\n", + "\n", + ">>> B.b_attr\n", + "-2\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have only scratched the surface of the topic of class inheritance. That being said, this section does convey the essential functionality and utility of class inheritance. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Links to Official Documentation\n", + "\n", + "- [Official Tutorial: Inheritance](https://docs.python.org/3/tutorial/classes.html#inheritance)" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module4_OOP/Introduction_to_OOP.html b/docs_backup/Module4_OOP/Introduction_to_OOP.html index 6d3b806b..54813c0b 100644 --- a/docs_backup/Module4_OOP/Introduction_to_OOP.html +++ b/docs_backup/Module4_OOP/Introduction_to_OOP.html @@ -1,45 +1,49 @@ - - + - + - + Introduction to Object Oriented Programming — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ + + @@ -155,11 +161,13 @@ + +
    @@ -331,29 +339,29 @@

    Links to Official Documentation - - - - - - + + -

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. - @@ -362,7 +370,6 @@

    Links to Official Documentation jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module4_OOP/Introduction_to_OOP.ipynb b/docs_backup/Module4_OOP/Introduction_to_OOP.ipynb new file mode 100644 index 00000000..4a454768 --- /dev/null +++ b/docs_backup/Module4_OOP/Introduction_to_OOP.ipynb @@ -0,0 +1,199 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Introducing object oriented programming in python, Difficulty: Easy, Category: Section\n", + " :keywords: class, type, creation, definition, intro, overview, basics, meaning" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction to Object Oriented Programming\n", + "\n", + "Our first foray into the essentials of Python introduced us to the [basic object types: numbers, strings, and lists](http://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html). Likewise, our discussion of NumPy was centered around the [N-dimensional array](http://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/IntroducingTheNDarray.html). These types of objects are distinguished in large part by the different functions that are bound to them. Functions bound to objects are known as **methods**. For example, where a string possesses methods designed to manipulate its sequence of characters, a NumPy array possesses methods for operating on the numerical data bound to that array.\n", + "\n", + "```python\n", + "# Different types of objects can possess different methods \n", + "\n", + ">>> string = \"hello world\"\n", + ">>> string.capitalize() # use the string-method `capitalize`\n", + "'Hello world'\n", + "\n", + ">>> import numpy as np\n", + ">>> array = np.array([[0, 1, 2],\n", + "... [3, 4, 5]])\n", + ">>> array.sum() # use the array-method `sum`\n", + "15\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "More generally, an object can possess data, known as **attributes**, which summarize information about that object. For example, the array-attributes `ndim` and `shape` provide information about the indexing-layout of that array's numerical data.\n", + "\n", + "```python\n", + "# accessing an object's attributes\n", + ">>> array.ndim\n", + "2\n", + ">>> array.shape\n", + "(2, 3)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this module, we will learn to define our own, customized object types with distinct collections of attributes and methods. In this way, we will be using Python as an \"objected oriented\" programming language; this will greatly expand our capabilities as Python users, and deepen our understanding of the language itself.\n", + "\n", + "As a sneak peek example, let's create our own class of objects known as `Rectangle`:\n", + "\n", + "```python\n", + "class Rectangle:\n", + " \"\"\" A Python object that describes the properties of a rectangle \"\"\"\n", + " def __init__(self, width, height, center=(0.0, 0.0)):\n", + " \"\"\" Sets the attributes of a particular instance of `Rectangle`.\n", + "\n", + " Parameters\n", + " ----------\n", + " width : float\n", + " The x-extent of this rectangle instance.\n", + "\n", + " height : float\n", + " The y-extent of this rectangle instance.\n", + "\n", + " center : Tuple[float, float], optional (default=(0, 0))\n", + " The (x, y) position of this rectangle's center\"\"\"\n", + " self.width = width \n", + " self.height = height \n", + " self.center = center\n", + " \n", + " def __repr__(self):\n", + " \"\"\" Returns a string to be used as a printable representation \n", + " of a given rectangle.\"\"\"\n", + " return \"Rectangle(width={w}, height={h}, center={c})\".format(h=self.height,\n", + " w=self.width,\n", + " c=self.center)\n", + "\n", + " def compute_area(self):\n", + " \"\"\" Returns the area of this rectangle \n", + "\n", + " Returns\n", + " -------\n", + " float\"\"\"\n", + " return self.width * self.height\n", + "\n", + " def compute_corners(self):\n", + " \"\"\" Computes the (x, y) corner-locations of this rectangle, starting with the\n", + " 'top-right' corner, and proceeding clockwise. \n", + "\n", + " Returns\n", + " -------\n", + " List[Tuple[float, float], Tuple[float, float], Tuple[float, float], Tuple[float, float]]\"\"\"\n", + " cx, cy = self.center\n", + " dx = self.width / 2.0\n", + " dy = self.height / 2.0\n", + " return [(cx + x, cy + y) for x,y in ((dx, dy), (dx, -dy), (-dx, -dy), (-dx, dy))]\n", + "```\n", + "\n", + "An instance of this `Rectangle` class is an individual rectangle whose *attributes* include its width, height, and center-location. Additionally, we can use the rectangle's *methods* (its attributes that are functions) to compute its area and the locations of its corners. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```python\n", + "# create a rectangle of width 4, height 10, centered at (0, 0)\n", + "# here __init__ is executed and the width/height/center attributes are set\n", + ">>> rect1 = Rectangle(4, 10) \n", + "\n", + "# the __repr__ method defines how a rectangle instance will be displayed here\n", + "# in the console\n", + ">>> rect1 \n", + "Rectangle(width=4, height=10, center=(0, 0))\n", + "\n", + "# compute the area for this particular rectangle\n", + ">>> rect1.compute_area() \n", + "40\n", + "\n", + "# compute the corner-locations of this rectangle\n", + ">>> rect1.compute_corners() \n", + "[(2.0, 5.0), (2.0, -5.0), (-2.0, -5.0), (-2.0, 5.0)]\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Just like any other Python object that we have encountered, we can put our `Rectangle`s in lists, store them as values in dictionaries, pass them to functions, reference them with multiple variables, and so on.\n", + "\n", + "Popular STEM, data analysis, and machine learning Python libraries rely heavily on the ability to define custom classes of Python objects. For example, [pandas](https://pandas.pydata.org/) defines a spreadsheet-like `DataFrame` class; [PyTorch](https://pytorch.org/), [MXNet](https://mxnet.incubator.apache.org/), and [TensorFlow](https://www.tensorflow.org/) each define tensor classes that are capable of [automatic differentiation](https://en.wikipedia.org/wiki/Automatic_differentiation), which is critically important for training neural networks. Understanding Python's class system will greatly improve your ability to leverage libraries like these (Shameless plug: refer to [MyGrad](https://mygrad.readthedocs.io) if you are interested in seeing a simple pure-Python/NumPy implementation of an auto-differentiation library). \n", + "\n", + "Moving forward, we will discuss the essential *class definition*, which will permit us to define our own class (a.k.a. type) of object. Next, we will learn about creating distinct *instances* of a given object type and about defining methods. This will lead to our first encounter with *special methods*, which enable us to affect how our object type behaves with Python's various operators. For example, we can define how the `+` operator interacts with our objects. Lastly, we will briefly discuss the concept of class inheritance. \n", + "\n", + "
    \n", + "\n", + "**Takeaway:**\n", + "\n", + "The goal of this module is to understand how to define and utilize our own class of Python objects. This will greatly mature our understanding of Python as an object-oriented language, and will expand our ability to fully leverage all of Python's features. \n", + "\n", + "
    \n", + "\n", + "## Class vs Type: An Important Note on Terminology\n", + "Before proceeding any further, it is worthwhile to draw our attention to the fact that the terms \"type\" and \"class\" are practically synonymous in Python. Thus far, we have only encountered the term \"type\" to distinguish objects from one another, e.g. `1` belongs to the type `int` and `\"cat\"` belongs to the type `str`. However, we will soon study *class* definitions for making new types objects, and soon introduce functions like `issubclass` into our lexicon. That being said, know that *class* and *type* mean the same thing! There are historical reasons for the coexistence of these two terms, but [since Python 2.2](https://www.python.org/download/releases/2.2/descrintro/) concepts of type and class have been unified.\n", + "\n", + "In practice, people tend to reserve the word \"type\" to refer to built-in types (e.g. `int` and `str`) and \"class\" to refer to user-defined types. Again, in the modern versions of Python, these terms carry no practical distinction." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Takeaway:**\n", + "\n", + "The terms \"type\" and \"class\" are synonymous; they both refer to the encapsulating definition of a specific type/class of Python object, with all of its attributes. Although they are not treated synonymously within the Python language - we will write class definitions, not type definitions, and we will use `type` to inspect an object and not `class` - these distinctions are merely relics of versions of Python long passed.\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Links to Official Documentation\n", + "\n", + "- [Python Tutorial: A First Look at Classes](https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes)" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module4_OOP/Methods.html b/docs_backup/Module4_OOP/Methods.html index 36088bd0..21e566c7 100644 --- a/docs_backup/Module4_OOP/Methods.html +++ b/docs_backup/Module4_OOP/Methods.html @@ -1,45 +1,49 @@ - - + - + - + Methods — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ + + @@ -160,11 +166,13 @@ + +

    whose differences are relatively minor but are important to understand. The functions “append” and “capitalize” are both examples of instance methods, specifically, as they are designed to be invoked by a particular list instance and string instance, respectively.

    We have already worked with the instance method __init__, which is special in that it is reserved by Python to be executed whenever class-initialization is invoked. Similarly, the special instance method __add__ informs how an object interacts with the + operator. For example, float.__add__ specifies that + will sum the values of float instances, whereas list.__add__ specifies that + will concatenate list instances together. We will conclude our discussion of @@ -283,7 +291,7 @@

    Instance Methods# returned by, `func` >>> out = inst.func() >>> inst is out -True +True

    Note that this “under the hood” behavior only occurs when the method is being called from an instance; this is why we didn’t face this issue when invoking func from Dummy - Dummy is a class object, not an instance. Thus, inst.func() is equivalent to Dummy.func(inst):

    @@ -349,7 +357,7 @@

    Class Methods# `Dummy.class_func()` returns `Dummy` >>> out = Dummy.class_func() >>> out is Dummy -True +True # `Dummy` gets passed as `cls` automatically # even when `class_func` is called from an instance @@ -360,15 +368,15 @@

    Class Methodsdict.fromkeys is an example of a class method that takes in an iterable, and returns a dictionary whose keys are the elements of that iterable, and whose values all default to None.

    -
    >>> dict.fromkeys("abcd")
    +
    >>> dict.fromkeys("abcd", 2.3)
     {'a': 2.3, 'b': 2.3, 'c': 2.3, 'd': 2.3}
     
    -

    It is sensible that this is a class method rather than an instance method, as the method creates a brand new dictionary from scratch. It need only have access to the dict object (i.e. the cls argument) so that it can construct the dictionary. The following is what an implementation of fromkeys could look like, were we to define dict ourselves:

    +

    It is sensible that this is a class method rather than an instance method, as the method creates a brand new dictionary from scratch. It need only have access to the dict object (i.e. the cls argument) so that it can construct the dictionary. The following is what an implementation of fromkeys could look like, were we to define dict ourselves:

    class dict:
         # assume all other dictionary methods are defined here
         @classmethod
    -    def fromkeys(cls, iterable, value=None):
    +    def fromkeys(cls, iterable, value=None):
             """ Creates a dictionary whose keys are the elements of `iterable`. All
             keys map to `value`.
     
    @@ -419,7 +427,8 @@ 

    Reading Comprehension SolutionsDummy so that its instance method func accepts two arguments: the instance object that Python automatically passes and the argument x, which we want func to return unchanged.

    -
    We will rewite func to accept an argument called ‘self’, which will accept the instance object that is passed “under the hood” , and ‘x’. As you will see in the reading, the name argument ‘self’ is simply used by convention.
    +

    We will rewite func to accept an argument called ‘self’, which will accept the instance object that is passed “under the hood” , and ‘x’. As you will see in the reading, the name argument ‘self’ is simply used by convention.

    +

    @@ -478,7 +488,6 @@

    Reading Comprehension Solutions jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module4_OOP/Methods.ipynb b/docs_backup/Module4_OOP/Methods.ipynb new file mode 100644 index 00000000..9690edff --- /dev/null +++ b/docs_backup/Module4_OOP/Methods.ipynb @@ -0,0 +1,341 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: The different kinds of class methods, Difficulty: Medium, Category: Section\n", + " :keywords: instance, class method, static method, property, abstract method, class funtion" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Methods\n", + "\n", + "Recall that a method is an attribute of a class that is a function. For example, \"append\" is a method that is defined for the `list` class and \"capitalize\" is a method of the `str` (string) class. \n", + "\n", + "```python\n", + "# create an instance of the `list` class/type\n", + "# and invoke the instance method `append`\n", + ">>> a = [1, 2, 3]\n", + ">>> a.append(-1)\n", + ">>> a\n", + "[1, 2, 3, -1]\n", + "\n", + "# create an instance of the `str` class/type\n", + "# and invoke the instance method `capitalize`\n", + ">>> b = \"moo\"\n", + ">>> b.capitalize()\n", + "'Moo'\n", + "```\n", + "\n", + "Here we will encounter three varieties of methods:\n", + "\n", + "- instance methods\n", + "- class methods\n", + "- static methods\n", + "\n", + "whose differences are relatively minor but are important to understand. The functions \"append\" and \"capitalize\" are both examples of instance methods, specifically, as they are designed to be invoked by a particular list instance and string instance, respectively.\n", + "\n", + "We have already worked with the instance method `__init__`, which is special in that it is reserved by Python to be executed whenever class-initialization is invoked. Similarly, the special instance method `__add__` informs how an object interacts with the `+` operator. For example, `float.__add__` specifies that `+` will sum the values of `float` instances, whereas `list.__add__` specifies that `+` will concatenate `list` instances together. We will conclude our discussion of methods by surveying a number of these special methods - they will greatly bolster our ability to define convenient, user-friendly classes." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instance Methods\n", + "An *instance method* is defined whenever a function definition is specified within the body of a class. This may seem trivial but there is still a significant nuance that must be cleared up, which is that '`self`' is the defacto first-argument for any instance method. This is something that we encountered when working with `__init__`. Let's proceed naively so that we will hit a very common error, which will bring this matter to light. We begin by creating a class with an instance method that simply accepts one argument and then returns that argument unchanged:\n", + "\n", + "```python\n", + "class Dummy:\n", + " def func(x): \n", + " \"\"\" An instance method that returns `x` unchanged. \n", + " This is a bad version of this instance method!\"\"\"\n", + " return x\n", + "``` \n", + "\n", + "We can call this method from the class object `Dummy` itself, and it will behave as-expected:\n", + "```python\n", + ">>> Dummy.func(2)\n", + "2\n", + "```\n", + "but something strange happens when we try to call `func` from an instance of `Dummy`:\n", + "```python\n", + "# calling `func` from an instance of `Dummy` produces\n", + "# an unexpected error\n", + ">>> inst = Dummy()\n", + ">>> inst.func(2)\n", + "TypeError: func() takes 1 positional argument but 2 were given\n", + "```\n", + "At first glance, this error message doesn't seem to make any sense. It is indeed true that `func` only accepts one argument - we specified that it should accept the argument `x` in its function definition. How is it that `inst.func(2)` specifies *two* arguments? It seems like we are solely passing `2` to our method. Herein lies an extremely important detail:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Important!**\n", + "\n", + "When you call an instance method (e.g. `func`) from an instance object (e.g. `inst`), Python automatically passes that instance object as the first argument, in addition to any other arguments that were passed in by the user.\n", + "\n", + "
    \n", + "\n", + "So according to this, `inst` is being passed as the argument `x` and we are attempting to pass `2` as a second argument to the method; this explains the error message complaining about passing `func` two arguments. By this logic we should be able to call `a.func()` and see that `inst` is being passed as the argument `x` - recall that `func` is defined to simply return `x` unchanged. Let's confirm this:\n", + "\n", + "```python\n", + "# verifying that `inst` is being passed as the first argument \n", + "# of the instance-method `func`\n", + "\n", + "# note the memory address of the Dummy-instance `inst`\n", + ">>> inst\n", + "<__main__.Dummy at 0x284f0008da0>\n", + "\n", + "# `inst.func()` automatically receives `inst` as the \n", + "# input argument, which is then returned unchanged\n", + ">>> inst.func()\n", + "<__main__.Dummy at 0x284f0008da0>\n", + "\n", + "# `inst` is indeed being passed to, and\n", + "# returned by, `func`\n", + ">>> out = inst.func()\n", + ">>> inst is out\n", + "True\n", + "```\n", + "\n", + "*Note that this \"under the hood\" behavior only occurs when the method is being called from an instance*; this is why we didn't face this issue when invoking `func` from `Dummy` - `Dummy` is a class object, not an instance. Thus, `inst.func()` is equivalent to `Dummy.func(inst)`:\n", + "\n", + "```python\n", + ">>> out = Dummy.func(inst)\n", + ">>> out is inst\n", + "True\n", + "```\n", + "\n", + "In its current form, there is no way for us to pass an argument to `func` when we are calling it from an instance of `Dummy`. To solve this issue, we will refactor our definition of `func` to anticipate the passing of the instance object as the first argument." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The `self` Argument\n", + "We will want to define our instance methods in a way that anticipates that Python will automatically pass an instance object as the first argument. Thus if we want our method to accept $N$ external argument, we should define its signature to have $N+1$ arguments, with the understanding that Python will pass the instance object as the first argument. The accepted convention is to call this first argument `self`. There is no significance to this name beyond it being the widely-adopted convention among Python users; \"self\" is meant to indicate that the instance object is passing itself as the first argument of the method. Consider the following example:\n", + "\n", + "```python\n", + "# demonstrate the use of `self` in instance arguments\n", + "class Number:\n", + " def __init__(self, value):\n", + " self.value = value\n", + " \n", + " def add(self, new_value):\n", + " return self.value + new_value\n", + "```\n", + "\n", + "```python\n", + "# calls __init__, setting self.value = 4.0\n", + ">>> x = Number(4.0)\n", + "\n", + "# `x` gets passed to `self`\n", + ">>> x.add(2.0)\n", + "6.0\n", + "\n", + "# Calling the instance method from the class object.\n", + "# We must explicitly pass an object to `self`\n", + ">>> Number.add(x, 2.0)\n", + "6.0\n", + "```\n", + "\n", + "Note the utility of having `self` be automatically passed in as an argument to both `__init__` and `add`. An instance method is meant to have access to the instance object that is calling it - when you call `capitalize` from a string instance, it is obvious that you want to capitalize *that* specific string. It would be tedious and redundant if Python did not manage that automatically. \n", + "\n", + "Next, we will see that we can also define class-methods, which automatically have *class objects* get passed as their first arguments, and static methods, which do not have any objects passed to them under the hood." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Reading Comprehension: Invoking Instance Methods**\n", + "\n", + "Rewrite `Dummy` so that its instance method `func` accepts two arguments: the instance object that Python automatically passes and the argument `x`, which we want `func` to return unchanged. Create an instance of `Dummy` and call `func` from this instance and pass it the string `\"hi\"`, what will be returned? What will happen if you try to call `Dummy.func(\"hi\")`? Why? How can we modify this call from `Dummy` itself so that the method will work as desired? \n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Class Methods\n", + "A class method is similar to an instance method, but it has a *class object* passed as its first argument. Recall that, when an instance method is called from an instance object, that instance object is automatically passed as the first argument to the method. By contrast, when a *class method* is called from a either a class object or an instance object, the class object is automatically passed as the first argument to the method. Instead of calling this first argument `self`, the convention is to name it `cls`.\n", + "\n", + "To define a class method you must *decorate* the method definition with a special built-in decorator `classmethod`. We have not discussed decorators. Suffice it to know that this simply \"tags\" the method, so that Python knows to treat it like a class method instead of an instance method. The following demonstrates this decoration process:\n", + "\n", + "```python\n", + "class Dummy:\n", + " \n", + " @classmethod\n", + " def class_func(cls):\n", + " \"\"\" A class method defined to simply \n", + " return `cls` unchanged\"\"\"\n", + " return cls\n", + "```\n", + "\n", + "```python\n", + "# `Dummy` gets passed as `cls` automatically.\n", + "# We defined `class_func` to return `cls` unchanged\n", + ">>> Dummy.class_func()\n", + "__main__.Dummy\n", + "\n", + "# `Dummy.class_func()` returns `Dummy`\n", + ">>> out = Dummy.class_func()\n", + ">>> out is Dummy\n", + "True\n", + "\n", + "# `Dummy` gets passed as `cls` automatically\n", + "# even when `class_func` is called from an instance\n", + ">>> inst = Dummy()\n", + ">>> inst.class_func()\n", + ">>> inst.class_func()\n", + "__main__.Dummy\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`dict.fromkeys` is an example of a class method that takes in an iterable, and returns a dictionary whose keys are the elements of that iterable, and whose values all default to `None`.\n", + "\n", + "```python\n", + ">>> dict.fromkeys(\"abcd\", 2.3)\n", + "{'a': 2.3, 'b': 2.3, 'c': 2.3, 'd': 2.3}\n", + "```\n", + "\n", + "It is sensible that this is a class method rather than an instance method, as the method creates a brand new dictionary from scratch. It need only have access to the `dict` object (i.e. the `cls` argument) so that it can construct the dictionary. The following is what an implementation of `fromkeys` could look like, were we to define `dict` ourselves: \n", + "\n", + "```python\n", + "class dict:\n", + " # assume all other dictionary methods are defined here\n", + " @classmethod\n", + " def fromkeys(cls, iterable, value=None):\n", + " \"\"\" Creates a dictionary whose keys are the elements of `iterable`. All \n", + " keys map to `value`.\n", + " \n", + " Parameters\n", + " ----------\n", + " iterable: Iterable[Hashable]\n", + " An iterable of valid dictionary keys (i.e. any object that is hashable).\n", + " \n", + " value : Optional[Any]\n", + " The value that all of the keys will map to. Defaults to `None`.\n", + " \n", + " Returns\n", + " -------\n", + " dict \"\"\"\n", + " new_dict = cls() # equivalent to `dict()`: creates a new dictionary instance\n", + " for key in iterable:\n", + " new_dict[key] = value\n", + " return new_dict\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Static Methods\n", + "A static method is simply a method whose arguments must all be passed explicitly by the user. That is, Python doesn't pass anything to a static method automatically. The built-in decorator `staticmethod` is used to distinguish a method as being static rather than an instance method.\n", + "\n", + "```python\n", + "class Dummy:\n", + "\n", + " @staticmethod\n", + " def static_func():\n", + " \"\"\" A static method defined to always returns \n", + " the string `'hi'`\"\"\"\n", + " return 'hi'\n", + "```\n", + "\n", + "```python\n", + "# A static method can be called from a class object\n", + "# or an instance object; nothing gets passed to it \n", + "# automatically.\n", + ">>> Dummy.static_func()\n", + "'hi'\n", + "\n", + ">>> inst = Dummy()\n", + ">>> inst.static_func()\n", + "'hi'\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reading Comprehension Solutions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Invoking Instance Methods: Solution**\n", + "\n", + "Rewrite `Dummy` so that its instance method `func` accepts two arguments: the instance object that Python automatically passes and the argument `x`, which we want `func` to return unchanged.\n", + "\n", + "> We will rewite func to accept an argument called 'self', which will accept the instance object that is passed \"under the hood\" , and 'x'. As you will see in the reading, the name argument 'self' is simply used by convention. \n", + "\n", + "```python\n", + "class Dummy:\n", + " def func(self, x): \n", + " return x\n", + "```\n", + "\n", + "Create an instance of `Dummy` and call `func` from this instance and pass it the string `\"hi\"`.\n", + "\n", + "```python\n", + ">>> inst = Dummy()\n", + ">>> inst.func(\"hi\") # `inst` is passed to the argument `self`\n", + "'hi'\n", + "```\n", + "\n", + "What will happen if you try to call `Dummy.func(\"hi\")`? Why?\n", + "\n", + "> This will raise an error, which complains that func expects two arguments, and that we have only passed it one. Indeed, we will have only passed it the object \"hi\" and nothing else. Dummy is a class object, not an instance object. Thus Python does not do anything special \"under the hood\" when we call Dummy.func. We must pass something to the self argument. Because this particular method doesn't do anything with self, we can just pass it None, or any other object, really.\n", + "\n", + "```python\n", + "# Dummy.func(\"hi\") would raise an error\n", + ">>> Dummy(None, \"hi\")\n", + "'hi'\n", + "```" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module4_OOP/ObjectOrientedProgramming.html b/docs_backup/Module4_OOP/ObjectOrientedProgramming.html index 0818327b..e2e8356b 100644 --- a/docs_backup/Module4_OOP/ObjectOrientedProgramming.html +++ b/docs_backup/Module4_OOP/ObjectOrientedProgramming.html @@ -1,43 +1,47 @@ - - + - + - + Object Oriented Programming — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -80,6 +84,7 @@

    + +
    @@ -137,18 +143,20 @@ + +
      -
    • Docs »
    • +
    • »
    • Object Oriented Programming
    • - + View page source @@ -167,13 +175,13 @@ /* CSS overrides for sphinx_rtd_theme */ /* 24px margin */ -.nbinput.nblast, -.nboutput.nblast { +.nbinput.nblast.container, +.nboutput.nblast.container { margin-bottom: 19px; /* padding has already 5px */ } /* ... except between code cells! */ -.nblast + .nbinput { +.nblast.container + .nbinput.container { margin-top: -19px; } @@ -318,39 +326,39 @@

      Operator Overloadingself.denom = denom // factor

    -
    def __add__(self, other):
    +
    def __add__(self, other):
         ''' Overload the `+` operator for `self` on the left '''
         num = self.num * other.denom + self.denom * other.num
         denom = self.denom * other.denom
         return Rational(num, denom)
     
    -def __radd__(self, other):
    +def __radd__(self, other):
         ''' Overload the `+` operator for `self` on the right '''
         return self.__add__(other)
     
    -def __sub__(self, other):
    +def __sub__(self, other):
         ''' Overload the `-` operator '''
         num = self.num * other.denom - self.denom * other.num
         denom = self.denom * other.denom
         return Rational(num, denom)
     
    -def __rsub__(self, other):
    +def __rsub__(self, other):
         ''' Overload the `-` operator when `self` is on the right'''
         return Rational(-self.num, self.denom) + other
     
    -def __lt__(self, other):
    +def __lt__(self, other):
         ''' Overload the `<` operator '''
         return self.num * other.denom < self.denom * other.num
     
    -def __eq__(self, other):
    +def __eq__(self, other):
         ''' Overload the `==` operator '''
         return self.num == other.num and self.denom == other.denom
     
    -def __str__(self):
    +def __str__(self):
         ''' Overload the `str()` operator; useful for printing '''
         return '{} / {}'.format(self.num, self.denom)
     
    -def __repr__(self):
    +def __repr__(self):
         ''' Overload the repr, which is used in the console:
         >>> rat = Rational(1, 2)
         >>> rat
    @@ -363,10 +371,10 @@ 

    Operator OverloadingWe can now create Rationals and operate on them:

    >>> a = Rational(1, 2)
     >>> b = Rational(3, 4)
    ->>> print(a + b)
    +>>> print(a + b)
     5 / 4
     
    ->>> print(a - b)
    +>>> print(a - b)
     -1 / 4
     
    @@ -423,13 +431,13 @@

    raddReading Comprehension: Operator Overloading

    Using the __add__ and __sub__ implementations as a base, implement the operators:

      -
    • * (__mul__)
    • -
    • / (__truediv__)
    • -
    • ** (__pow__)
    • -
    • <= (__le__)
    • -
    • != (__ne__)
    • -
    • > (__gt__)
    • -
    • >= (__ge__)
    • +
    • * (__mul__)

    • +
    • / (__truediv__)

    • +
    • ** (__pow__)

    • +
    • <= (__le__)

    • +
    • != (__ne__)

    • +
    • > (__gt__)

    • +
    • >= (__ge__)

    for the Rational class.

    @@ -447,7 +455,7 @@

    Reading Comprehension Solutionself.denom = denom // factor

    -
    def __add__(self, other):
    +
    def __add__(self, other):
         ''' Overload the `+` operator
     
         Note that this works with non-Rationals if `self` is on the left, as in:
    @@ -461,7 +469,7 @@ 

    Reading Comprehension Solutiondenom = self.denom * other.denom return Rational(num, denom) -def __radd__(self, other): +def __radd__(self, other): ''' Overload the `+` operator This works with non-Rationals for `self` on the right: @@ -470,71 +478,71 @@

    Reading Comprehension Solution ''' return self.__add__(other) -def __sub__(self, other): +def __sub__(self, other): ''' Overload the `-` operator ''' num = self.num * other.denom - self.denom * other.num denom = self.denom * other.denom return Rational(num, denom) -def __rsub__(self, other): +def __rsub__(self, other): ''' Overload the `-` operator when `self` is on the right''' return Rational(-self.num, self.denom) + other -def __mul__(self, other): +def __mul__(self, other): ''' Overload the `*` operator ''' num = self.num * other.num denom = self.denom * other.denom return Rational(num, denom) -def __rmul__(self, other): +def __rmul__(self, other): ''' Overload the `*` operator for `self` on the right ''' return self.__mul__(other) -def __truediv__(self, other): +def __truediv__(self, other): ''' Overload the `/` operator ''' num = self.num * other.denom denom = self.denom * other.num return Rational(num, denom) -def __rtruediv__(self, other): +def __rtruediv__(self, other): ''' Overload the `/` overator for `self` on the right ''' return Rational(self.denom, self.num) * other -def __pow__(self, power): +def __pow__(self, power): ''' Overload the `**` operator ''' num = self.num ** power denom = self.denom ** power return Rationa(num, denom) -def __lt__(self, other): +def __lt__(self, other): ''' Overload the `<` operator ''' return self.num * other.denom < self.denom * other.num -def __le__(self, other): +def __le__(self, other): ''' Overload the `<=` operator ''' return self.num * other.denom <= self.denom * other.num -def __eq__(self, other): +def __eq__(self, other): ''' Overload the `==` operator ''' return self.num == other.num and self.denom == other.denom -def __ne__(self, other): +def __ne__(self, other): ''' Overload the `!=` operator ''' return not self == other -def __gt__(self, other): +def __gt__(self, other): ''' Overload the `>` operator ''' return self.num * other.denom > self.denom * other.num -def __ge__(self, other): +def __ge__(self, other): ''' Overload the `>=` operator ''' return self.num * other.denom >= self.denom * other.num -def __str__(self): +def __str__(self): ''' Overload the `str()` operator; useful for printing ''' return '{} / {}'.format(self.num, self.denom) -def __repr__(self): +def __repr__(self): ''' Overload the repr, which is used in the console: >>> rat = Rational(1, 2) >>> rat @@ -557,20 +565,25 @@

    Reading Comprehension Solution

    - © Copyright 2019, Ryan Soklaski + © Copyright 2021, Ryan Soklaski.

    - Built with Sphinx using a theme provided by Read the Docs. + + + + Built with Sphinx using a + + theme + + provided by Read the Docs. -
    @@ -579,7 +592,6 @@

    Reading Comprehension Solution jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module4_OOP/ObjectOrientedProgramming.ipynb b/docs_backup/Module4_OOP/ObjectOrientedProgramming.ipynb new file mode 100644 index 00000000..ae8e1fb4 --- /dev/null +++ b/docs_backup/Module4_OOP/ObjectOrientedProgramming.ipynb @@ -0,0 +1,467 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Object Oriented Programming\n", + "Up until now, we've written functions that encapsulate code for easy re-use. We can pass data to our functions, which may operate on them and return results. However, we have been limited in the types of data we can work with. This section introduces the concept of object-oriented programming (often referred to as OOP).\n", + "\n", + "An *object* bundles together data and functions. For example, a Python [List](https://docs.python.org/3/tutorial/datastructures.html) is an object. It contains data (its elements) and functions (such as `sort`, `append` and `count`)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Defining Objects\n", + "When we define our own objects, we will write a *class* containing data and functions. Let's start with a simple example:\n", + "\n", + "```python\n", + "class Rectangle:\n", + " def __init__(self, width=1, height=1):\n", + " self.width = width\n", + " self.height = height\n", + " \n", + " def get_area(self):\n", + " return self.width * self.height\n", + "```\n", + "\n", + "We've defined a `Rectangle` object, which has two pieces of data that it keeps track of: `width` and `height`. It also has a function `get_area` that we can invoke, in much the same way we would create a list and call its `append` function. We can create a `Rectangle` in much the same way we might create a list:\n", + "\n", + "```python\n", + ">>> rect = Rectangle(2, 3)\n", + "```\n", + "\n", + "The `__init__` function is a special function that is executed when we create an object. Its purpose is to perform any *initialization* (hence its name) that ought to occur when the object is being created. In our case, we initialize the width and height of our `Rectangle`. Note that a parameter of our `__init__` method is `self`, which refers to the object we are creating.\n", + "\n", + "We can call functions that our `Rectangle` has associated with it:\n", + "\n", + "```python\n", + ">>> rect.get_area()\n", + "6\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inheritance\n", + "Working with objects provides powerful abstractions and an incredible amount of code re-use. For example, let's implement a `Square` class. One way to write `Square` would be the following:\n", + "\n", + "```python\n", + "class Square:\n", + " def __init__(self, side=1):\n", + " self.side = side\n", + " \n", + " def get_area(self):\n", + " return self.side ** 2\n", + "```\n", + "\n", + "However, we can take advantage of the code we've already written for `Rectangle`. We know that a square is a rectangle. Inheritance exactly follows this *is a* relationship. We can thus write our `Square` class to *inherit from* our `Rectangle` class:\n", + "\n", + "```python\n", + "class Square(Rectangle):\n", + " def __init__(self, side=1):\n", + " super().__init__(side, side)\n", + "```\n", + "\n", + "Here we're saying that a `Square` *is a* `Rectangle`. This means that `Square` *inherits* all of the data and functions inside `Rectangle`. Let's make sure:\n", + "\n", + "```python\n", + ">>> my_square = Square(2)\n", + ">>> my_square.get_area()\n", + "4\n", + "\n", + ">>> my_square.width\n", + "2\n", + "```\n", + "\n", + "The `super()` call refers to `Square`'s *super* class, or *parent* class, which is `Rectangle`. We're calling the `__init__` method of `Rectangle`, and passing it `side` for both `width` and `height`.\n", + "\n", + "In this way, we're able to re-use all the code that we already wrote for `Rectangle` so that we don't have to re-implement our `get_area` function. We can also show that our square is a rectangle, but our rectangle is not a square:\n", + "\n", + "```python\n", + ">>> isinstance(my_square, Square)\n", + "True\n", + "\n", + ">>> isinstance(my_square, Rectangle)\n", + "True\n", + "\n", + ">>> isinstance(rect, Square)\n", + "False\n", + "\n", + ">>> isinstance(rect, Rectangle)\n", + "True\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Operator Overloading\n", + "\n", + "Recall a few operators in Python: `+`, `-`, `*`, `/`, and so on. As you know, these operators behave differently depending on context:\n", + "\n", + "```python\n", + ">>> 2 + 3\n", + "5\n", + "\n", + ">>> 'a' + 'b'\n", + "'ab'\n", + "```\n", + "\n", + "This is because the string and integer classes have *overloaded* these operators. Observe what happens when we try to use the subtraction operator on a string:\n", + "\n", + "```python\n", + ">>> 'a' - 'b'\n", + "Traceback (most recent call last):\n", + " File \"\", line 1, in \n", + "TypeError: unsupported operand type(s) for -: 'str' and 'str'\n", + "```\n", + "\n", + "What's really going on here is the subtraction operator is a *function* that takes two parameters. The string class does not implement the subtraction function, so the operand type `str` is unrecognized. You can think of what's going on under the hood as this:\n", + "\n", + "```\n", + "a - b => subtract(a, b)\n", + "```\n", + "\n", + "Implementing an operator inside your own class is called *overloading* that operator. Here we will define a `Rational` class that keeps track of rational numbers. We'll overload several common operators so we can perform common functions on our `Rational`s.\n", + "\n", + "```python\n", + "def gcd(a, b):\n", + " ''' Greatest Common denom (GCD)\n", + " \n", + " Parameters\n", + " ----------\n", + " a : Integral\n", + " \n", + " b : Integral\n", + " \n", + " Returns\n", + " -------\n", + " int\n", + " The greatest common denom of `a` and `b`.\n", + " '''\n", + " if a == 0:\n", + " return b\n", + " if b == 0:\n", + " return a\n", + " if a == 1:\n", + " return 1\n", + " if b == 1:\n", + " return 1\n", + "\n", + " if a > 0 and b > 0:\n", + " return gcd(b, a % b) if a >= b else gcd(a, b % a)\n", + " if a < 0 and b < 0:\n", + " return gcd(-a, -b)\n", + " if a < b:\n", + " return gcd(-a, b)\n", + " return gcd(a, -b)\n", + "\n", + "class Rational:\n", + " ''' A rational number (a/b, where a and b are integers) '''\n", + " def __init__(self, num=0, denom=1):\n", + " assert denom != 0, \"Cannot have zero in the denom\"\n", + "\n", + " if denom < 0:\n", + " num = -num\n", + " denom = -denom\n", + "\n", + " factor = gcd(num, denom)\n", + " \n", + " self.num = num // factor\n", + " self.denom = denom // factor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " def __add__(self, other):\n", + " ''' Overload the `+` operator for `self` on the left '''\n", + " num = self.num * other.denom + self.denom * other.num\n", + " denom = self.denom * other.denom\n", + " return Rational(num, denom)\n", + " \n", + " def __radd__(self, other):\n", + " ''' Overload the `+` operator for `self` on the right '''\n", + " return self.__add__(other)\n", + "\n", + " def __sub__(self, other):\n", + " ''' Overload the `-` operator '''\n", + " num = self.num * other.denom - self.denom * other.num\n", + " denom = self.denom * other.denom\n", + " return Rational(num, denom)\n", + " \n", + " def __rsub__(self, other):\n", + " ''' Overload the `-` operator when `self` is on the right'''\n", + " return Rational(-self.num, self.denom) + other\n", + "\n", + " def __lt__(self, other):\n", + " ''' Overload the `<` operator '''\n", + " return self.num * other.denom < self.denom * other.num\n", + "\n", + " def __eq__(self, other):\n", + " ''' Overload the `==` operator '''\n", + " return self.num == other.num and self.denom == other.denom\n", + "\n", + " def __str__(self):\n", + " ''' Overload the `str()` operator; useful for printing '''\n", + " return '{} / {}'.format(self.num, self.denom)\n", + "\n", + " def __repr__(self):\n", + " ''' Overload the repr, which is used in the console:\n", + " >>> rat = Rational(1, 2)\n", + " >>> rat\n", + " Rational(1, 2)\n", + " '''\n", + " return 'Rational({}, {})'.format(self.num, self.denom)\n", + "```\n", + "\n", + "We can now create `Rational`s and operate on them:\n", + "\n", + "```python\n", + ">>> a = Rational(1, 2)\n", + ">>> b = Rational(3, 4)\n", + ">>> print(a + b)\n", + "5 / 4\n", + "\n", + ">>> print(a - b)\n", + "-1 / 4\n", + "```\n", + "\n", + "We'll take some time now to walk through some of the details behind what we implemented. By now, the `__init__` function should look pretty familiar to you. A `Rational` object can take 0 parameters (which gives you the `Rational` $\\frac{0}{1}$), 1 parameter (which gives you $\\frac{a}{1}$), or 2 parameters (which gives you $\\frac{a}{b}$). We've overloaded several common operators:\n", + "\n", + "##### __add__\n", + "By overloading the `__add__` function, we allow the `+` operator to be used with `Rational`s. For example, we can add two `Rational`s together:\n", + "\n", + "```python\n", + ">>> Rational(7, 2) + Rational(1, 7)\n", + "Rational(51, 14)\n", + "```\n", + "\n", + "#### __radd__\n", + "This may look a little strage at first; especially when you see that this function just calls `__add__`. Under the hood, our `__add__` function call really looks like this:\n", + "\n", + "```python\n", + ">>> r1 = Rational(1, 3)\n", + ">>> r2 = Rational(2, 5)\n", + ">>> r1.__add__(r2) # same as r1 + r2\n", + "Rational(11, 15)\n", + "```\n", + "\n", + "That call is made because `r1` appears before the `+` operator. In some cases, the operand on the left might not have a `+` operator defined that is compatible with the type of operand on the right:\n", + "\n", + "```python\n", + ">>> r1 = Rational(1, 3)\n", + ">>> int(2).__add__(r1)\n", + "NotImplemented\n", + "```\n", + "\n", + "Now, an `int` doesn't know anything about our `Rational` class. Python is unable to resolve the `+` operator in that scenario. However, it will then look to see whether our `Rational` class has the `__radd__` function implemented, which means \"add on the right\" and is called when our object is on the right of the `+`. Now, our `Rational` class doesn't have an `__radd__` function that works with an `int` so unfortunately this won't work either. However, we can still observe that this is what's happening by examining the error message:\n", + "\n", + "```python\n", + ">>> 2 + Rational(1, 3)\n", + "AttributeError: 'int' object has no attribute 'denom'\n", + "```\n", + "\n", + "The call fails on the line\n", + "\n", + "```python\n", + "num = self.num * other.denom + self.denom * other.num\n", + "```\n", + "\n", + "in our `Rational` class. Python unsuccessfully tries to resolve the `int` class's `__add__` operator, then attempts to use our `Rational`'s `__radd__`.\n", + "\n", + "Since addition is commutative, we can simply call the `__add__` function from `__radd__` and things work like we expect them to. Notice that our `__rsub__` implementation is different from our `__sub__` implementation, since subtraction is not commutative. We can observe that these give different results, as they should:\n", + "\n", + "```python\n", + ">>> Rational(1) - Rational(1, 3)\n", + "Rational(2, 3)\n", + "\n", + ">>> Rational(1).__sub__(Rational(1, 3))\n", + "Rational(2, 3)\n", + "\n", + ">>> Rational(1).__rsub__(Rational(1, 3))\n", + "Rational(-2, 3)\n", + "\n", + ">>> Rational(1, 3) - Rational(1)\n", + "Raitonal(-2, 3)\n", + "```\n", + "\n", + "For an exhaustive list of available operators, see [the documentation](https://docs.python.org/3/library/operator.html)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Reading Comprehension: Operator Overloading**\n", + " \n", + "Using the `__add__` and `__sub__` implementations as a base, implement the operators:\n", + "\n", + "- `*` (`__mul__`)\n", + "- `/` (`__truediv__`)\n", + "- `**` (`__pow__`)\n", + "- `<=` (`__le__`)\n", + "- `!=` (`__ne__`)\n", + "- `>` (`__gt__`)\n", + "- `>=` (`__ge__`)\n", + "\n", + "for the `Rational` class.\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Reading Comprehension Solution\n", + "\n", + "```python\n", + "class Rational:\n", + " ''' A rational number (a/b, where a and b are integers) '''\n", + " def __init__(self, num=0, denom=1):\n", + " assert denom != 0, \"Cannot have zero in the denom\"\n", + "\n", + " if denom < 0:\n", + " num = -num\n", + " denom = -demoninator\n", + "\n", + " factor = gcd(num, denom)\n", + " \n", + " self.num = num // factor\n", + " self.denom = denom // factor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " def __add__(self, other):\n", + " ''' Overload the `+` operator \n", + " \n", + " Note that this works with non-Rationals if `self` is on the left, as in:\n", + " >>> Rational(1, 3) + 1\n", + " Rational(4, 3)\n", + " but does not with `self` on the right:\n", + " >>> 1 + Rational(1, 3)\n", + " # error!\n", + " '''\n", + " num = self.num * other.denom + self.denom * other.num\n", + " denom = self.denom * other.denom\n", + " return Rational(num, denom)\n", + " \n", + " def __radd__(self, other):\n", + " ''' Overload the `+` operator\n", + " \n", + " This works with non-Rationals for `self` on the right:\n", + " >>> 1 + Rational(1, 2)\n", + " Rational(3, 2)\n", + " '''\n", + " return self.__add__(other)\n", + "\n", + " def __sub__(self, other):\n", + " ''' Overload the `-` operator '''\n", + " num = self.num * other.denom - self.denom * other.num\n", + " denom = self.denom * other.denom\n", + " return Rational(num, denom)\n", + " \n", + " def __rsub__(self, other):\n", + " ''' Overload the `-` operator when `self` is on the right'''\n", + " return Rational(-self.num, self.denom) + other\n", + "\n", + " def __mul__(self, other):\n", + " ''' Overload the `*` operator '''\n", + " num = self.num * other.num\n", + " denom = self.denom * other.denom\n", + " return Rational(num, denom)\n", + " \n", + " def __rmul__(self, other):\n", + " ''' Overload the `*` operator for `self` on the right '''\n", + " return self.__mul__(other)\n", + "\n", + " def __truediv__(self, other):\n", + " ''' Overload the `/` operator '''\n", + " num = self.num * other.denom\n", + " denom = self.denom * other.num\n", + " return Rational(num, denom)\n", + " \n", + " def __rtruediv__(self, other):\n", + " ''' Overload the `/` overator for `self` on the right '''\n", + " return Rational(self.denom, self.num) * other\n", + " \n", + " def __pow__(self, power):\n", + " ''' Overload the `**` operator '''\n", + " num = self.num ** power\n", + " denom = self.denom ** power\n", + " return Rationa(num, denom)\n", + "\n", + " def __lt__(self, other):\n", + " ''' Overload the `<` operator '''\n", + " return self.num * other.denom < self.denom * other.num\n", + "\n", + " def __le__(self, other):\n", + " ''' Overload the `<=` operator '''\n", + " return self.num * other.denom <= self.denom * other.num\n", + "\n", + " def __eq__(self, other):\n", + " ''' Overload the `==` operator '''\n", + " return self.num == other.num and self.denom == other.denom\n", + "\n", + " def __ne__(self, other):\n", + " ''' Overload the `!=` operator '''\n", + " return not self == other\n", + "\n", + " def __gt__(self, other):\n", + " ''' Overload the `>` operator '''\n", + " return self.num * other.denom > self.denom * other.num\n", + "\n", + " def __ge__(self, other):\n", + " ''' Overload the `>=` operator '''\n", + " return self.num * other.denom >= self.denom * other.num\n", + " \n", + " def __str__(self):\n", + " ''' Overload the `str()` operator; useful for printing '''\n", + " return '{} / {}'.format(self.num, self.denom)\n", + "\n", + " def __repr__(self):\n", + " ''' Overload the repr, which is used in the console:\n", + " >>> rat = Rational(1, 2)\n", + " >>> rat\n", + " Rational(1, 2)\n", + " '''\n", + " return 'Rational({}, {})'.format(self.num, self.denom)\n", + "```\n", + "\n", + "```python\n", + "\n", + "```" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module4_OOP/Special_Methods.html b/docs_backup/Module4_OOP/Special_Methods.html index e50e6d4d..92c893ba 100644 --- a/docs_backup/Module4_OOP/Special_Methods.html +++ b/docs_backup/Module4_OOP/Special_Methods.html @@ -1,45 +1,49 @@ - - + - + - + Special Methods — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@

    + + @@ -157,11 +163,13 @@ + +
    @@ -574,7 +582,6 @@

    Links to Official Documentation jQuery(function () { SphinxRtdTheme.Navigation.enable(true); diff --git a/docs_backup/Module4_OOP/Special_Methods.ipynb b/docs_backup/Module4_OOP/Special_Methods.ipynb new file mode 100644 index 00000000..2537065a --- /dev/null +++ b/docs_backup/Module4_OOP/Special_Methods.ipynb @@ -0,0 +1,345 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Controlling behavior with special methods, Difficulty: Medium, Category: Section\n", + " :keywords: dunder method, special method, operator overload, repr, getitem, custom syntax, __init__" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Special Methods\n", + "In this section, we will learn about a variety of instance methods that are reserved by Python, which affect an object's high level behavior and its interactions with operators. These are known as special methods. `__init__` is an example of a special method; recall that it controls the process of creating instances of a class. Similarly, we will see that `__add__` controls the behavior of an object when it is operated on by the `+` symbol, for example. In general, the names of special methods take the form of `____`, where the two underscores preceed and succeed the name. Accordingly, special methods can also be referred to as \"dunder\" (double-underscore) methods. Learning to leverage special methods will enable us to design elegant and powerful classes of objects.\n", + "\n", + "These methods give us complete control over the various high-level interfaces that we use to interact with objects. Let's make a simple class with nonsensical behavior to demonstrate our ability to shape how our class behaves:\n", + "\n", + "```python\n", + "# Demonstrating (mis)use of special methods\n", + "class SillyClass:\n", + " def __getitem__(self, key):\n", + " \"\"\" Determines behavior of `self[key]` \"\"\"\n", + " return [True, False, True, False]\n", + " \n", + " def __pow__(self, other):\n", + " \"\"\" Determines behavior of `self ** other` \"\"\"\n", + " return \"Python Like You Mean It\"\n", + "```\n", + "\n", + "```python\n", + ">>> silly = SillyClass()\n", + "\n", + ">>> silly[None]\n", + "[True, False, True, False]\n", + "\n", + ">>> silly ** 2\n", + "'Python Like You Mean It'\n", + "```\n", + "This section is not meant to be a comprehensive treatment of special methods, which would require us to reach beyond our desired level of sophistication. The [official Python documentation](https://docs.python.org/3/reference/datamodel.html#special-method-names) provides a rigorous but somewhat inaccessible treatment of special methods. [Dive into Python 3](http://www.diveintopython3.net/special-method-names.html) has an excellent appendix on special methods. It is strongly recommended that readers consult this resource." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## String-Representations of Objects\n", + "The following methods determines how an object should be represented as a string in various contexts. For example, this text consistently utilizes the fact that passing an object to the Python console will prompt the console to print out a representation of that object as a string. That is,\n", + "\n", + "```python\n", + ">>> x = list((\"a\", 1, True))\n", + ">>> x\n", + "['a', 1, True]\n", + "```\n", + "\n", + "Under the hood, the special method `x.__repr__` is being called to obtain this string representation whenever an object is displayed in a console/notebook like this. The method returns the string `\"['a', 1, True]\"`, which is then printed out to the console. This is an extremely useful for creating classes whose objects can be inspected conveniently in a Python console or in a Jupyter notebook. Similarly `__str__` returns the string that will be produced when `str` is called on the object.\n", + "\n", + "|Method| Signature | Explanation |\n", + "|---|---|---|\n", + "|Returns string for a printable representation of object|`__repr__(self)`|`repr(x)` invokes `x.__repr__()`, this is also invoked when an object is returned by a console|\n", + "|Returns string representation of an object|`__str__(self)`|`str(x)` invokes `x.__str__()`|" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A well-implemented `__repr__` method can greatly improve the convenience of working with a class. For example, let's add this method to our `ShoppingList` class that we wrote in the preceding section; the `__repr__` will create a string with our shopping items on a bulleted list with purchased items crossed out:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```python\n", + "def strike(text):\n", + " \"\"\" Renders string with strike-through characters through it.\n", + " \n", + " `strike('hello world')` -> '̶h̶e̶l̶l̶o̶ ̶w̶o̶r̶l̶d'\n", + " \n", + " Notes\n", + " -----\n", + " \\u0336 is a special strike-through unicode character; it\n", + " is not unique to Python.\"\"\"\n", + " return ''.join('\\u0336{}'.format(c) for c in text)\n", + "\n", + "class ShoppingList:\n", + " def __init__(self, items):\n", + " self._needed = set(items)\n", + " self._purchased = set()\n", + "\n", + " def __repr__(self):\n", + " \"\"\" Returns formatted shopping list as a string with \n", + " purchased items being crossed out.\n", + " \n", + " Returns\n", + " -------\n", + " str\"\"\"\n", + " if self._needed or self._purchased:\n", + " remaining_items = [str(i) for i in self._needed]\n", + " purchased_items = [strike(str(i)) for i in self._purchased]\n", + " # You wont find the • character on your keyboard. I simply \n", + " # googled \"unicode bullet point\" and copied/pasted it here. \n", + " return \"• \" + \"\\n• \".join(remaining_items + purchased_items)\n", + " \n", + " def add_new_items(self, items): \n", + " self._needed.update(items) \n", + "\n", + " def mark_purchased_items(self, items):\n", + " self._purchased.update(set(items) & self._needed)\n", + " self._needed.difference_update(self._purchased)\n", + "```\n", + "\n", + "```python\n", + "# demonstrating `ShoppingList.__repr__`\n", + ">>> l = ShoppingList([\"grapes\", \"beets\", \"apples\", \"milk\", \"melon\", \"coffee\"])\n", + ">>> l.mark_purchased_items([\"grapes\", \"beets\", \"milk\"])\n", + ">>> l\n", + "• melon\n", + "• apples\n", + "• coffee\n", + "• ̶g̶r̶a̶p̶e̶s\n", + "• ̶m̶i̶l̶k\n", + "• ̶b̶e̶e̶t̶s\n", + "```\n", + "\n", + "See that this simple method makes it much easier for us to inspect the state of our shopping list when we are working in a console/notebook environment." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Interfacing with Mathematical Operators\n", + "The following special methods control how an object interacts with `+`, `*`, `**`, and other mathematical operators. A full listing of all the special methods used to emulate numeric types can be found [here](https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types)\n", + "\n", + "|Method| Signature | Explanation |\n", + "|---|---|---|\n", + "|Add|`__add__(self, other)`|`x + y` invokes `x.__add__(y)`|\n", + "|Subtract|`__sub__(self, other)`|`x - y` invokes `x.__sub__(y)`|\n", + "|Multiply|`__mul__(self, other)`|`x * y` invokes `x.__mul__(y)`|\n", + "|Divide|`__truediv__(self, other)`|`x / y` invokes `x.__truediv__(y)`|\n", + "|Power|`__pow__(self, other)`|`x ** y` invokes `x.__pow__(y)`|\n", + "\n", + "You may be wondering why division has the peculiar name `__truediv__`, whereas the other operators have more sensible names. This is an artifact of the transition from Python 2 to Python 3; [the default integer-division was replaced by float-division](http://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Number-Types), and thus `__div__` was replaced by `__truediv__` for the sake of 2-3 compatibility. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's give `ShoppingList` an `__add__` method so that we can merge shopping lists using the `+` operator. Rather than redefine the entire `ShoppingList` class, we can simply define this as a function and use `setattr` to set it as a method to our existing class.\n", + "\n", + "```python\n", + "def __add__(self, other):\n", + " \"\"\" Add the unpurchased and purchased items from another shopping\n", + " list to the present one.\n", + " \n", + " Parameters\n", + " ----------\n", + " other : ShoppingList\n", + " The shopping list whose items we will add to the present one.\n", + " Returns\n", + " -------\n", + " ShoppingList\n", + " The present shopping list, with items added to it.\"\"\"\n", + " new_list = ShoppingList([])\n", + " # populate new_list with items from `self` and `other`\n", + " for l in [self, other]:\n", + " new_list.add_new_items(l._needed)\n", + "\n", + " # add purchased items to list, then mark as purchased\n", + " new_list.add_new_items(l._purchased) \n", + " new_list.mark_purchased_items(l._purchased) \n", + " return new_list\n", + "```\n", + "\n", + "```python\n", + "# set `__add__` as a method of `ShoppingList`\n", + ">>> setattr(ShoppingList, \"__add__\", __add__)\n", + "```\n", + "\n", + "Now let's create a few shopping lists and combine them:\n", + "```python\n", + ">>> food = ShoppingList([\"milk\", \"flour\", \"salt\", \"eggs\"])\n", + ">>> food.mark_purchased_items([\"flour\", \"salt\"])\n", + "\n", + ">>> office_supplies = ShoppingList([\"staples\", \"pens\", \"pencils\"])\n", + ">>> office_supplies.mark_purchased_items([\"pencils\"])\n", + "\n", + ">>> clothes = ShoppingList([\"t-shirts\", \"socks\"])\n", + "\n", + "# combine all three shopping lists\n", + ">>> food + office_supplies + clothes\n", + "• t-shirts\n", + "• eggs\n", + "• pens\n", + "• milk\n", + "• staples\n", + "• socks\n", + "• ̶f̶l̶o̶u̶r\n", + "• ̶s̶a̶l̶t\n", + "• ̶p̶e̶n̶c̶i̶l̶s\n", + "```\n", + "Overloading the `+` operator provides us with a sleek interface for merging multiple shopping lists in a sleek, readable way. `food + office_supplies + clothes` is equivalent to calling `(food.__add__(office_supplies)).__add__(clothes)`. It is obvious that the former expression is far superior." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating a Container-Like Class\n", + "The following special methods allow us to give our class a container interface, like that of a dictionary, set, or list. An exhaustive listing and discussion of these methods can be found [here](https://docs.python.org/3/reference/datamodel.html#emulating-container-types)\n", + "\n", + "|Method| Signature | Explanation |\n", + "|---|---|---|\n", + "|Length|`__len__(self)`|`len(x)` invokes `x.__len__()`|\n", + "|Get Item|`__getitem__(self, key)`|`x[key]` invokes `x.__getitem__(key)`|\n", + "|Set Item|`__setitem__(self, key, item)`|`x[key] = item` invokes `x.__setitem__(key, item)`|\n", + "|Contains|`__contains__(self, item)`|`item in x` invokes `x.__contains__(item)`|\n", + "|Iterator|`__iter__(self)`|`iter(x)` invokes `x.__iter__()`|\n", + "|Next|`__next__(self)`|`next(x)` invokes `x.__next__()`|" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To get a feel for these methods, let's create class that implements most aspects of a list's interface. We will store a list as an attribute of our class to keep track of the contents, but will implement special methods that \"echo\" the interface of the list.\n", + "\n", + "```python\n", + "class MyList:\n", + " def __init__(self, *args):\n", + " if len(args) == 1 and hasattr(args[0], '__iter__'):\n", + " # handles `MyList([1, 2, 3])\n", + " self._data = list(args[0])\n", + " else:\n", + " # handles `MyList(1, 2, 3)`\n", + " self._data = list(args)\n", + "\n", + " def __getitem__(self, index):\n", + " out = self._data[index]\n", + " # slicing should return a `MyList` instance\n", + " # otherwise, the individual element should be returned as-is\n", + " return MyList(out) if isinstance(index, slice) else out\n", + " \n", + " def __setitem__(self, key, value):\n", + " self._data[key] = value\n", + "\n", + " def __len__(self): \n", + " return len(self._data)\n", + "\n", + " def __repr__(self): \n", + " \"\"\" Use the character | as the delimiter for our list\"\"\"\n", + " # `self._data.__repr__()` returns '[ ... ]',\n", + " # thus we can slice to get the contents of the string\n", + " # and exclude the square-brackets, and add our own\n", + " # delimiters in their place\n", + " return \"|\" + self._data.__repr__()[1:-1] + \"|\"\n", + "\n", + " def __contains__(self, item): \n", + " return item in self._data\n", + "\n", + " def append(self, item):\n", + " self._data.append(item)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's appreciate the rich behavior that we get out of this simple class:\n", + "\n", + "```python\n", + "# MyList can accept any iterable as its\n", + "# first (and only) input argument\n", + ">>> x = MyList(\"hello\")\n", + ">>> x\n", + "|'h', 'e', 'l', 'l', 'o'|\n", + "\n", + "# MyList accepts an arbitrary number of arguments\n", + ">>> x = MyList(1, 2, 3, 4, 5)\n", + ">>> x\n", + "|1, 2, 3, 4, 5|\n", + "\n", + ">>> len(x)\n", + "5\n", + "\n", + "# getting an item\n", + ">>> x[0]\n", + "1\n", + "\n", + "# slicing returns a MyList instance\n", + ">>> x[2:4]\n", + "|3, 4|\n", + "\n", + "# setting an item\n", + ">>> x[0] = -1\n", + ">>> x\n", + "|-1, 2, 3, 4, 5|\n", + "\n", + "# checking membership\n", + ">>> 10 in x\n", + "False\n", + "\n", + ">>> MyList()\n", + "||\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Links to Official Documentation\n", + "\n", + "- [Special Methods](https://docs.python.org/3/reference/datamodel.html#special-method-names)\n", + "- [Emulating Numeric Types](https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types)\n", + "- [Emulating Container Types](https://docs.python.org/3/reference/datamodel.html#emulating-container-types)" + ] + } + ], + "metadata": { + "jupytext": { + "text_representation": { + "extension": ".md", + "format_name": "markdown", + "format_version": "1.2", + "jupytext_version": "1.9.1" + } + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs_backup/Module5_OddsAndEnds/Matplotlib.html b/docs_backup/Module5_OddsAndEnds/Matplotlib.html index 33689426..1c37b073 100644 --- a/docs_backup/Module5_OddsAndEnds/Matplotlib.html +++ b/docs_backup/Module5_OddsAndEnds/Matplotlib.html @@ -1,45 +1,49 @@ - - + - + - + Matplotlib — Python Like You Mean It + + + + + + + + - + - - - - - - - + + + + + + + - - - - - @@ -84,6 +88,7 @@ + + @@ -160,11 +166,13 @@ + +