diff --git a/.devcontainer.json b/.devcontainer.json
new file mode 100644
index 000000000..922a1238d
--- /dev/null
+++ b/.devcontainer.json
@@ -0,0 +1,89 @@
+// (delete the above line to manage this file manually)
+//////////////////////////////////////////////////////////////
+//
+// This file provides configuration options so that a PreTeXt
+// project can be edited and built using GitHub's Codespaces.
+// It is recommended to keep this in your repository even if you
+// do not use this feature, as it will allow other to explore
+// your project easily.
+// This file will be automatically generated by PreTeXt with the
+// latest updates unless you remove the first comment line above.
+//
+///////////////////////////////////////////////////////////////
+
+// commented out because we're not using this but ptx generates it automatically.
+
+// {
+// "name": "PreTeXt-Codespaces",
+
+// // This Docker image includes some LaTeX support, but is still not to large. Note that if you keep your codespace running, it will use up your GitHub free storage quota. Additional options are listed below.
+// "image": "oscarlevin/pretext:small",
+// // If you need to generate more complicated assets (such as sageplots) or use additional fonts when building to PDF, comment out the above line and uncomment the following line.
+// // "image": "oscarlevin/pretext:full",
+// // If you only intend to build for web and don't have any latex-image generated assets, you can use a smaller image:
+// // "image": "oscarlevin/pretext:lite",
+
+// // Add gh cli as a feature (to support codechat)
+// "features": {
+// "ghcr.io/devcontainers/features/github-cli:1": {}
+// },
+
+// // Respect the project's designated dependencies
+// "postCreateCommand": "pip install -r requirements.txt",
+
+// // Port forwarding
+// // ---------------
+// // This is needed by the CodeChat Server.
+// "forwardPorts": [
+// // The port used for a Thrift connection between the VSCode CodeChat
+// // extension and the CodeChat Server.
+// 27376,
+// // The port used for an HTTP connection from the CodeChat Client to
+// // the CodeChat Server.
+// 27377,
+// // The port used by a websocket connection between the CodeChat
+// // Server and the CodeChat Client.
+// 27378
+// ],
+// // See the [docs](https://containers.dev/implementors/json_reference/#port-attributes).
+// "portsAttributes": {
+// "27376": {
+// "label": "VSCode extension <-> CodeChat Server",
+// "requireLocalPort": true
+// },
+// "27377": {
+// "label": "CodeChat Client",
+// "requireLocalPort": true
+// },
+// "27378": {
+// "label": "CodeChat Client<->Server websocket",
+// "requireLocalPort": true
+// // This port needs to be public; however, there's no way to specify port visibility here. See `server.py` in the CodeChat Server for details.
+// }
+// },
+
+// // Configure tool-specific properties.
+// "customizations": {
+// "codespaces": {
+// "openFiles": ["source/main.ptx"]
+// },
+// "vscode": {
+// "settings": {
+// "editor.quickSuggestions": {
+// "other": "off"
+// },
+// "editor.snippetSuggestions": "top",
+// "xml.validation.enabled": false,
+// "CodeChat.CodeChatServer.Command": "CodeChat_Server"
+// },
+// "extensions": [
+// "ms-vscode.live-server",
+// "oscarlevin.pretext-tools",
+// "CodeChat.codechat"
+// ]
+// }
+// }
+
+// // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+// // "remoteUser": "root"
+// }
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 000000000..efa5f10a4
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,57 @@
+{
+ "name": "PreTeXt-Codespaces",
+
+ // This Docker image includes some LaTeX support, but is still not to large. Note that if you keep your codespace running, it will use up your GitHub free storage quota. Additional options are listed below.
+ "image": "oscarlevin/pretext:small",
+ // If you need to generate more complicated assets (such as sageplots) or use additional fonts when building to PDF, comment out the above line and uncomment the following line.
+ // "image": "oscarlevin/pretext:full",
+ // If you only intend to build for web and don't have any latex-image generated assets, you can use a smaller image:
+ // "image": "oscarlevin/pretext:lite",
+
+
+
+ // The following was the previous version of this file, which used the Codespaces base image. It is still available for reference, but is not recommended.
+ // "image": "mcr.microsoft.com/devcontainers/python:3",
+ // "features": {
+ // "ghcr.io/devcontainers/features/node:1": {},
+ // "ghcr.io/rocker-org/devcontainer-features/pandoc:1": {}
+ // },
+ // "forwardPorts": [
+ // 27377,
+ // 27378
+ // ],
+ // "portsAttributes": {
+ // "27378": {
+ // "label": "CodeChat",
+ // "onAutoForward": "openPreview",
+ // "requireLocalPort": true,
+ // "elevateIfNeeded": true,
+ // "protocol": "https"
+ // }
+ // },
+ // "onCreateCommand": "pip install pretext",
+ // // Use 'postCreateCommand' to run commands after the container is created.
+ // "postCreateCommand": "sudo bash ./.devcontainer/postCreateCommand.sh",
+
+ // Configure tool-specific properties.
+ "customizations": {
+ "codespaces": {
+ "openFiles": [
+ "source/main.ptx"
+ ]
+ },
+ "vscode": {
+ "settings": {
+ "editor.quickSuggestions": {
+ "other": "off"
+ },
+ "editor.snippetSuggestions": "top",
+ "xml.validation.enabled": false
+ },
+ "extensions": ["ms-vscode.live-server", "oscarlevin.pretext-tools"]
+ }
+ }
+
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+ // "remoteUser": "root"
+}
diff --git a/.github/workflows/pretext-cli.yml b/.github/workflows/pretext-cli.yml
new file mode 100644
index 000000000..22da9ab94
--- /dev/null
+++ b/.github/workflows/pretext-cli.yml
@@ -0,0 +1,94 @@
+# (delete the above line to manage this file manually)
+
+# commented out because we're not using this but ptx generates it automatically.
+
+# name: PreTeXt-CLI Actions
+# on:
+# # Runs on pull requests
+# pull_request:
+# branches: ["*"]
+# # Runs on pushes to main
+# push:
+# branches: ["main"]
+# # Runs on demand
+# workflow_dispatch:
+
+# jobs:
+# build:
+# runs-on: ubuntu-latest
+# container: oscarlevin/pretext:full
+
+# steps:
+# - name: Checkout source
+# uses: actions/checkout@v4
+
+# - name: install deps
+# run: pip install -r requirements.txt
+
+# - name: build deploy targets
+# run: pretext build --deploys
+# - name: stage deployment
+# run: pretext deploy --stage-only
+
+# - name: Bundle output/stage as artifact
+# uses: actions/upload-artifact@v4
+# with:
+# name: deploy
+# path: output/stage
+
+# deploy-cloudflare:
+# runs-on: ubuntu-latest
+# needs: build
+# if: vars.CLOUDFLARE_PROJECT_NAME != ''
+# permissions:
+# contents: read
+# deployments: write
+
+# steps:
+# - name: Download artifact
+# uses: actions/download-artifact@v4
+# with:
+# name: deploy
+# path: deploy
+# - name: Create 404.html
+# run: echo "404 page not found" >> deploy/404.html
+# - name: Publish to Cloudflare
+# uses: cloudflare/pages-action@v1
+# with:
+# apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+# accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+# projectName: ${{ vars.CLOUDFLARE_PROJECT_NAME }}
+# gitHubToken: ${{ secrets.GITHUB_TOKEN }}
+# branch: ${{ github.head_ref || github.ref_name }}
+# directory: deploy
+
+# deploy-ghpages:
+# runs-on: ubuntu-latest
+# needs: build
+# if: vars.PTX_ENABLE_DEPLOY_GHPAGES == 'yes' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
+# permissions:
+# contents: read
+# pages: write
+# id-token: write
+# concurrency:
+# group: "page"
+# cancel-in-progress: false
+# environment:
+# name: github-pages
+# url: ${{ steps.deployment.outputs.page_url }}
+# steps:
+# - name: Download website artifact
+# uses: actions/download-artifact@v4
+# with:
+# name: deploy
+# path: deploy
+# - name: Setup GitHub Pages
+# id: check
+# uses: actions/configure-pages@v4
+# - name: Upload artifact
+# uses: actions/upload-pages-artifact@v3
+# with:
+# path: deploy
+# - name: Deploy to Github Pages
+# id: deployment
+# uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index 7748bbf5d..c9179e8cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+# (delete the above line to manage this file manually)
__pycache__/
build_info
build
@@ -19,3 +20,107 @@ beta
output
published
pdf
+venv/
+cli.log
+
+# Boilerplate list of files in a PreTeXt project for git to ignore
+# ensure this file is tracked
+!.gitignore
+
+# don't track unpublished builds or stage (note: Runestone uses `published`)
+output
+published
+
+# don't track assets generated from source
+generated-assets
+
+# don't track the executables.ptx file
+executables.ptx
+
+# don't track node packages
+node_modules
+
+# don't track error logs
+.error_schema.log
+logs
+
+# don't track OS related files (windows/macos/linux)
+.DS_Store
+.DS_Store?
+._*
+.AppleDouble
+.LSOverride
+.Spotlight-V100
+.Trashes
+Icon
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+*.stackdump
+*.lnk
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+[Dd]esktop.ini
+.directory
+.fuse_hidden*
+.Trash-*
+.nfs*
+
+# Don't include VSCode generated files
+.vscode
+*.code-workspace
+
+# Don't inlucde SublimeText files
+# Cache files for Sublime Text
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+
+# Workspace files are user-specific
+*.sublime-workspace
+
+# Project files should be checked into the repository, unless a significant
+# proportion of contributors will probably not be using Sublime Text
+*.sublime-project
+
+# SFTP configuration file
+sftp-config.json
+sftp-config-alt*.json
+
+# Package control specific files
+Package Control.last-run
+Package Control.ca-list
+Package Control.ca-bundle
+Package Control.system-ca-bundle
+Package Control.cache/
+Package Control.ca-certs/
+Package Control.merged-ca-bundle
+Package Control.user-ca-bundle
+oscrypto-ca-bundle.crt
+bh_unicode_properties.cache
+
+# Sublime-github package stores a github token in this file
+# https://packagecontrol.io/packages/sublime-github
+GitHub.sublime-settings
+
+
+# Don't include Dropbox settings and caches
+.dropbox
+.dropbox.attr
+.dropbox.cache
+
+# Don't track codechat config (will be generated automatically)
+codechat_config.yaml
+
+# Don't track deprecated workflows
+.github/workflows/deploy.yml
+.github/workflows/test-build.yml
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..276991c5a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+# How to Think Like a Computer Scientist: Mines Edition
+This is a fork of the original [thinkcspy](https://github.com/runestoneinteractive/thinkcspy) made for Colorado School of Mines CSCI128:
+
+> This project began with the original How to Think Like a Computer Scientist text by Jeffrey Elkner, Peter Wentworth, Allen B. Downey, Chris Meyers, and Dario Mitchell. Since 2011 Brad Miller, David Ranum, Barbara Ericson, Mark Guzdial, and many others have built on the text making it interactive.
+
+> Programming is not a "spectator sport". It is something you do, something you participate in. It would make sense, then, that the book you use to learn programming should allow you to be active. That is our goal.
+
+> This book is meant to provide you with an interactive experience as you learn to program in Python. You can read the text, watch videos, and write and execute Python code. In addition to simply executing code, there is a unique feature called 'codelens' that allows you to control the flow of execution in order to gain a better understanding of how the program works.
+
+*Note: RST is deprecated, and the new pretext sources are in the pretext folder, but we will keep the _sources (old RST folder) directory until we are 100% sure that the book has been converted correctly and as thoroughly as possible.*
+
+## Development Environment
+Create and activate a virtual environment and install dependencies:
+
+`python -m venv venv`
+
+`source venv/bin/activate`
+
+`pip install -r requirements.txt`
+
+Then build the textbook: `pretext build web`
+
+..and finally, run the web server: `pretext view`
diff --git a/README.rst b/README.rst
deleted file mode 100644
index b1dce3d73..000000000
--- a/README.rst
+++ /dev/null
@@ -1,59 +0,0 @@
-How to Think Like a Computer Scientist: Interactive Edition
-===========================================================
-
-This project began with the original How to Think Like a Computer Scientist text by Jeffrey Elkner, Peter Wentworth, Allen B. Downey, Chris Meyers, and Dario Mitchell. Since 2011 Brad Miller, David Ranum, Barbara Ericson, Mark Guzdial, and many others have built on the text making it interactive.
-
-Programming is not a "spectator sport". It is something you do,
-something you participate in. It would make sense, then,
-that the book you use to learn programming should allow you to be active.
-That is our goal.
-
-This book is meant to provide you with an interactive experience as you learn
-to program in Python. You can read the text, watch videos,
-and write and execute Python code. In addition to simply executing code,
-there is a unique feature called 'codelens' that allows you to control the
-flow of execution in order to gain a better understanding of how the program
-works.
-
-.. image:: https://travis-ci.org/RunestoneInteractive/thinkcspy.svg?branch=master
- :target: https://travis-ci.org/RunestoneInteractive/thinkcspy
-
-Getting Started
-===============
-
-We have tried to make it as easy as possible for you to build and use this book.
-
-You can see and read this book online at `runestone.academy `_
-
-.. important:: The restructuredText version of this book is deprecated!
-
-Building with PreTeXt
----------------------
-
-1. Create a virtual environment
-2. pip install pretextbook
-3. To build run: pretext build web
-4. pretext view html
-
-Note: The pretext sources are in the pretext folder, we will keep the _sources folder until we are 100% sure that the book has been converted correctly and as thoroughly as possible.
-
-Building for Production on a Runestone Server
----------------------------------------------
-
-1. clone this repo to `httlacs` instead of `thinkcspy`
-2. Run `rsmanage addcourse` and add `httlacs` as course name and base course name
-3. Run `rsmanage build --ptx httlacs`
-
-
-Building with runestone
------------------------
-As mentioned above this method is deprecated, but will still work.
-Any updates to this book should be made in PreTeXt NOT RST.
-
-You can build it and host it yourself in just a few simple steps:
-
- 1. ``pip install -r requirements.txt`` -- Should install everything you need
- 2. ``runestone build`` -- will build the html and put it in ``./build/thinkcspy``
- 3. ``runestone serve`` -- will start a webserver and serve the pages locally from ``./build/thinkcspy``
-
-
diff --git a/_sources/ClassesBasics/Achangeofperspective.rst b/_sources/ClassesBasics/Achangeofperspective.rst
index f8e3aa12d..1e1b89d14 100644
--- a/_sources/ClassesBasics/Achangeofperspective.rst
+++ b/_sources/ClassesBasics/Achangeofperspective.rst
@@ -10,21 +10,12 @@
A change of perspective
-----------------------
-Throughout the earlier chapters, we wrote functions and called them using a syntax such as ``drawCircle(tess)``. This suggests that the
-function is the active agent. It says something like, *"Hey, drawCircle!
-Here's a turtle object for you to use to draw with."*
+Throughout the earlier chapters, we wrote functions and called them using a syntax such as ``printRange(lst)``. This suggests that the
+function is the active agent. It says something like, *"Hey, printRange!
+Here's a list for you to use to print with."*
-In object-oriented programming, the objects are considered the active agents.
-For example, in our early introduction to turtles, we used
-an object-oriented style. We said ``tess.forward(100)``, which
-asks the turtle to move itself forward by the given number of steps.
-An
-invocation like ``tess.circle()`` says *"Hey tess!
-Please use your circle method!"*
-
-
-
-This change in perspective is sometimes considered to be a more "polite" way to write programming instructions. However, it may not initially
+In object-oriented programming, the objects are considered the active agents. This change in perspective is sometimes considered to be a more "polite" way
+to write programming instructions. However, it may not initially
be obvious that it is useful. It turns out that often times shifting responsibility from
the functions onto the objects makes it possible to write more versatile
functions and makes it easier to maintain and reuse code.
diff --git a/_sources/ClassesBasics/AddingOtherMethodstoourClass.rst b/_sources/ClassesBasics/AddingOtherMethodstoourClass.rst
index 312dc3e7d..08973b292 100644
--- a/_sources/ClassesBasics/AddingOtherMethodstoourClass.rst
+++ b/_sources/ClassesBasics/AddingOtherMethodstoourClass.rst
@@ -20,8 +20,8 @@ We can group together the sensible operations, and the kinds of data
they apply to, and each instance of the class can have its own state.
A **method** behaves like a function but it is invoked on a specific
-instance. For example, with a turtle named ``tess``, ``tess.right(90)`` asks the ``tess`` object to perform its
-``right`` method and turn 90 degrees. Methods are accessed using dot notation.
+instance. For example, with a list named ``lst``, ``lst.append(90)`` asks the ``lst`` object to perform its
+``append`` method and add the integer 90 to the end of the list. Methods are accessed using dot notation.
Let's add two simple methods to allow a point to give us information about its state. The ``getX`` method, when invoked, will return the value of the x coordinate. The implementation of this method is straight forward since we already know how
to write functions that return values. One thing to notice is that even though the ``getX`` method does not need any other parameter information to do its work, there is still one formal parameter, ``self``. As we stated earlier, all methods defined in a class that operate on objects of that class will have ``self`` as their first parameter. Again, this serves as reference to the object itself which in turn gives access to the state data inside the object.
diff --git a/_sources/ClassesBasics/ObjectsRevisited.rst b/_sources/ClassesBasics/ObjectsRevisited.rst
index e1236bc4f..e0a5f95fb 100644
--- a/_sources/ClassesBasics/ObjectsRevisited.rst
+++ b/_sources/ClassesBasics/ObjectsRevisited.rst
@@ -12,13 +12,11 @@
Objects Revisited
-----------------
-In Python, every value is actually an object. Whether it be a turtle, a list, or even an integer, they are all objects. Programs manipulate those objects either by performing
+In Python, every value is actually an object. Whether it be a string, a list, or even an integer, they are all objects. Programs manipulate those objects either by performing
computation with them or by asking them to perform methods. To be more specific, we say that an object has
a **state** and a collection of **methods** that it can perform. The state of an object represents those things
-that the object knows about itself. For example, as we have seen with turtle objects, each turtle has a state consisting
-of the turtle's position, its color, its heading and so on. Each turtle also has the ability to go forward, backward, or turn right or left. Individual turtles are different in that even though they are
-all turtles, they differ in the specific values of the individual state attributes (maybe they are in a different location or have a different heading).
+that the object knows about itself. For example, each list has a state consisting
+of the items it contains, a length and so on. Each list also has the ability to add, delete, and sort the items inside of it. Individual lists are different in
+that even though they are all lists, they differ in the specific values of the individual state attributes (maybe they have different items inside them).
-.. image:: Figures/objectpic1.png
- :alt: Simple object has state and methods
diff --git a/_sources/ClassesBasics/ObjectsasArgumentsandParameters.rst b/_sources/ClassesBasics/ObjectsasArgumentsandParameters.rst
index 6cd2819a4..925c3a070 100644
--- a/_sources/ClassesBasics/ObjectsasArgumentsandParameters.rst
+++ b/_sources/ClassesBasics/ObjectsasArgumentsandParameters.rst
@@ -10,13 +10,8 @@
Objects as Arguments and Parameters
-------------------------------------
-You can pass an object as an argument in the usual way. We've already seen
-this in some of the turtle examples where we passed the turtle to
-some function like ``drawRectangle`` so that the function could
-control and use whatever turtle instance we passed to it.
-
-Here is a simple function called ``distance`` involving our new ``Point`` objects. The job of this function is to figure out the
-distance between two points.
+You can pass an object as an argument in the usual way. Here is a simple function called ``distance`` involving our new ``Point`` objects.
+The job of this function is to figure out the distance between two points.
.. activecode:: chp13_classes6
diff --git a/_sources/ClassesBasics/UserDefinedClasses.rst b/_sources/ClassesBasics/UserDefinedClasses.rst
index 6ea76a86b..0dfb99f2c 100644
--- a/_sources/ClassesBasics/UserDefinedClasses.rst
+++ b/_sources/ClassesBasics/UserDefinedClasses.rst
@@ -14,7 +14,7 @@
User Defined Classes
--------------------
-We've already seen classes like ``str``, ``int``, ``float`` and ``Turtle``. These were defined by Python and
+We've already seen classes like ``str``, ``int``, and ``float``. These were defined by Python and
made available for us to use. However, in many cases when we are solving problems we need to create data objects
that are related to the problem we are trying to solve. We need to create our own classes.
diff --git a/_sources/Files/FindingaFileonyourDisk.rst b/_sources/Files/FindingaFileonyourDisk.rst
index 56d915f14..b043969d0 100755
--- a/_sources/Files/FindingaFileonyourDisk.rst
+++ b/_sources/Files/FindingaFileonyourDisk.rst
@@ -45,9 +45,9 @@ but the same principles are in use. For example on windows the path might be
You can access files in sub-folders, also called directories, under your home directory
by adding a slash and the name of the folder. For example, if you had a file
-called ``hello.py`` in a folder called ``CS150`` that is inside a folder called
-``PyCharmProjects`` under your home directory, then the full name for the file
-``hello.py`` is ``/Users/yourname/PyCharmProjects/CS150/hello.py``.
+called ``hello.py`` in a folder called ``CS128`` that is inside a folder called
+``VSCodeProjects`` under your home directory, then the full name for the file
+``hello.py`` is ``/Users/yourname/VSCodeProjects/CS128/hello.py``.
This is called an *absolute file path*. An *absolute file path* typically
only works on a specific computer. Think about it for a second. What other
computer in the world is going to have an *absolute file path* that starts with
diff --git a/_sources/Files/WithStatements.rst b/_sources/Files/WithStatements.rst
index 4b18ca404..718bc0768 100644
--- a/_sources/Files/WithStatements.rst
+++ b/_sources/Files/WithStatements.rst
@@ -1,9 +1,6 @@
With Statements
---------------
-.. note::
- This section is a bit of an advanced topic and can be easily skipped. But with statements are becoming very common and it doesn't hurt to know about them in case you run into one in the wild.
-
Now that you have seen and practiced a bit with opening and closing files, there is another mechanism that Python provides for us that cleans up the often forgotten close. Forgetting to close a file does not necessarily cause a runtime error in the kinds of programs you typically write in an introductory CS course. However if you are writing a program that may run for days or weeks at a time that does a lot of file reading and writing you may run into trouble.
In version 2.5 Python introduced the concept of a context manager. The context manager automates the process of doing common operations at the start of some task, as well as automating certain operations at the end of some task. In the context of reading and writing a file, the normal operation is to open the file and assign it to a variable. At the end of working with a file the common operation is to make sure that file is closed.
diff --git a/_sources/Files/intro-WorkingwithDataFiles.rst b/_sources/Files/intro-WorkingwithDataFiles.rst
index fd5abfb27..8a8b7a8e3 100644
--- a/_sources/Files/intro-WorkingwithDataFiles.rst
+++ b/_sources/Files/intro-WorkingwithDataFiles.rst
@@ -14,7 +14,9 @@
Working with Data Files
=======================
-So far, the data we have used in this book have all been either coded right into the program, or have been entered by the user. In real life data reside in files. For example the images we worked with in the image processing unit ultimately live in files on your hard drive. Web pages, and word processing documents, and music are other examples of data that live in files. In this short chapter we will introduce the Python concepts necessary to use data from files in our programs.
+So far, the data we have used in this book have all been either coded right into the program, or have been entered by the user. In real life data reside in files.
+For example, web pages, word processing documents, and all data that live in files. In this short chapter we will introduce the Python concepts necessary to use
+data from files in our programs.
For our purposes, we will assume that our data files are text files--that is, files filled with characters. The Python programs that you write are stored as text files. We can create these files in any of a number of ways. For example, we could use a text editor to type in and save the data. We could also download the data from a website and then save it in a file. Regardless of how the file is created, Python will allow us to manipulate the contents.
diff --git a/_sources/Functions/Functionscancallotherfunctions.rst b/_sources/Functions/Functionscancallotherfunctions.rst
index 726f70981..28062ce48 100644
--- a/_sources/Functions/Functionscancallotherfunctions.rst
+++ b/_sources/Functions/Functionscancallotherfunctions.rst
@@ -62,94 +62,6 @@ for ``sum_of_squares``. As you step through you will notice that ``x``, and ``y
different values. This illustrates that even though they are named the same,
they are in fact, very different.
-Now we will look at another example that uses two functions. This example illustrates an
-important computer science problem solving technique called
-**generalization**. Assume we want to write a
-function to draw a square. The generalization step is to realize that a
-square is just a special kind of rectangle.
-
-To draw a rectangle we need to be able to call a function with different
-arguments for width and height. Unlike the case of the square,
-we cannot repeat the same thing 4 times, because the four sides are not equal.
-However, it is the case that drawing the bottom and right sides are the
-same sequence as drawing the top and left sides. So we eventually come up with
-this rather nice code that can draw a rectangle.
-
-.. code-block:: python
-
- def drawRectangle(t, w, h):
- """Get turtle t to draw a rectangle of width w and height h."""
- for i in range(2):
- t.forward(w)
- t.left(90)
- t.forward(h)
- t.left(90)
-
-The parameter names are chosen as single letters for conciseness.
-In real programs, we will insist on better variable names than this.
-The point is that the program doesn't "understand" that you're drawing a rectangle or that the
-parameters represent the width and the height. Concepts like rectangle, width, and height are meaningful
-for humans. They are not concepts that the program or the computer understands.
-
-*Thinking like a computer scientist* involves looking for patterns and
-relationships. In the code above, we've done that to some extent. We did
-not just draw four sides. Instead, we spotted that we could draw the
-rectangle as two halves and used a loop to repeat that pattern twice.
-
-But now we might spot that a square is a special kind of rectangle. A square
-simply uses the same value for both the height and the width.
-We already have a function that draws a rectangle, so we can use that to draw
-our square.
-
-.. code-block:: python
-
- def drawSquare(tx, sz): # a new version of drawSquare
- drawRectangle(tx, sz, sz)
-
-Here is the entire example with the necessary set up code.
-
-.. activecode:: ch04_3
- :nocodelens:
-
- import turtle
-
- def drawRectangle(t, w, h):
- """Get turtle t to draw a rectangle of width w and height h."""
- for i in range(2):
- t.forward(w)
- t.left(90)
- t.forward(h)
- t.left(90)
-
- def drawSquare(tx, sz): # a new version of drawSquare
- drawRectangle(tx, sz, sz)
-
- wn = turtle.Screen() # Set up the window
- wn.bgcolor("lightgreen")
-
- tess = turtle.Turtle() # create tess
-
- drawSquare(tess, 50)
-
- wn.exitonclick()
-
-
-
-There are some points worth noting here:
-
-* Functions can call other functions.
-* Rewriting ``drawSquare`` like this captures the relationship
- that we've spotted.
-* A caller of this function might say ``drawSquare(tess, 50)``. The parameters
- of this function, ``tx`` and ``sz``, are assigned the values of the tess object, and
- the integer 50 respectively.
-* In the body of the function, ``tz`` and ``sz`` are just like any other variable.
-* When the call is made to ``drawRectangle``, the values in variables ``tx`` and ``sz``
- are fetched first, then the call happens. So as we enter the top of
- function ``drawRectangle``, its variable ``t`` is assigned the tess object, and ``w`` and
- ``h`` in that function are both given the value 50.
-
-
So far, it may not be clear why it is worth the trouble to create all of these
new functions. Actually, there are a lot of reasons, but this example
demonstrates two:
@@ -163,10 +75,3 @@ demonstrates two:
#. Sometimes you can write functions that allow you to solve a specific
problem using a more general solution.
-
-.. admonition:: Lab
-
- * `Drawing a Circle <../Labs/lab04_01.html>`_ In this guided lab exercise we will work
- through a simple problem solving exercise related to drawing a circle with the turtle.
-
-
diff --git a/_sources/Functions/Functionsthatreturnvalues.rst b/_sources/Functions/Functionsthatreturnvalues.rst
index 51a0fa55c..cae049591 100644
--- a/_sources/Functions/Functionsthatreturnvalues.rst
+++ b/_sources/Functions/Functionsthatreturnvalues.rst
@@ -32,9 +32,7 @@ the absolute value:
In this example, the arguments to the ``abs`` function are 5 and -5.
-Some functions take more than one argument. For example the math module contains a function
-called
-``pow`` which takes two arguments, the base and the exponent.
+Some functions take more than one argument. For example the range function that we saw with ``for`` loops.
.. Inside the function,
.. the values that are passed get assigned to variables called **parameters**.
@@ -42,14 +40,9 @@ called
.. activecode:: ch04_5
:nocanvas:
- import math
- print(math.pow(2, 3))
+ print(list(range(4, 8)))
- print(math.pow(7, 4))
-
-.. note::
-
- Of course, we have already seen that raising a base to an exponent can be done with the ** operator.
+ print(list(range(1, 10)))
Another built-in function that takes more than one argument is ``max``.
@@ -65,17 +58,17 @@ return the maximum value sent. The arguments can be either simple values or
expressions. In the last example, 503 is returned, since it is larger than 33,
125, and 1. Note that ``max`` also works on lists of values.
-Furthermore, functions like ``range``, ``int``, ``abs`` all return values that
+Furthermore, functions like ``int``, ``abs`` all return values that
can be used to build more complex expressions.
.. index:: fruitful function
variable; global
global variable
-So an important difference between these functions and one like ``drawSquare`` is that
-``drawSquare`` was not executed because we wanted it to compute a value --- on the contrary,
-we wrote ``drawSquare`` because we wanted it to execute a sequence of steps that caused
-the turtle to draw a specific shape.
+So an important difference between these functions and one like ``printRange`` is that
+``printRange`` was not executed because we wanted it to compute a value --- on the contrary,
+we wrote ``printRange`` because we wanted it to execute a sequence of steps that caused
+the list's range to print.
Functions that return values are sometimes called **fruitful functions**.
In many other languages, a chunk that doesn't return a value is called a **procedure**,
diff --git a/_sources/Functions/functions.rst b/_sources/Functions/functions.rst
index 1d1380e0b..879251e0c 100644
--- a/_sources/Functions/functions.rst
+++ b/_sources/Functions/functions.rst
@@ -55,7 +55,7 @@ pattern:
indented the same amount -- *4 spaces is the Python standard* -- from
the header line.
-We've already seen the ``for`` loop which follows this pattern.
+We've already seen the ``while`` and ``for`` loops which follow this pattern.
In a function definition, the keyword in the header is ``def``, which is
followed by the name of the function and some *parameters* enclosed in
@@ -72,37 +72,27 @@ The figure below shows this relationship. A function needs certain information
This type of diagram is often called a **black-box diagram** because it only states the requirements from the perspective of the user. The user must know the name of the function and what arguments need to be passed. The details of how the function works are hidden inside the "black-box".
-Suppose we're working with turtles and a common operation we need is to draw
-squares. It would make sense if we did not have to duplicate all the steps each time we want to make a square. "Draw a square" can be thought of as an *abstraction* of a number of smaller steps. We will need to provide two pieces of information for the function to do its work: a turtle to do the drawing and a size for the side of the square. We could represent this using the following black-box diagram.
-
-.. image:: Figures/turtleproc.png
+Suppose we're working with lists of numeric data and a common operation we need is to find the size of the range of numbers in a list.
+It would make sense if we did not have to duplicate all the steps each time we want to find the size of the range. "printRange" can be thought of as an
+*abstraction* of a number of smaller steps. We will need to provide one piece of information for the function to do its work: the list we need the range of.
Here is a program containing a function to capture this idea. Give it a try.
.. activecode:: ch04_1
:nocodelens:
- import turtle
-
- def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
-
- for i in range(4):
- t.forward(sz)
- t.left(90)
-
-
- wn = turtle.Screen() # Set up the window and its attributes
- wn.bgcolor("lightgreen")
+ def printRange(lst):
+ """Prints the size of the range of lst."""
+ smallest = min(lst)
+ largest = max(lst)
+ print(largest - smallest)
- alex = turtle.Turtle() # create alex
- drawSquare(alex, 50) # Call the function to draw the square passing the actual turtle and the actual side size
- wn.exitonclick()
+ my_list1 = [1, 2, 3, 4, 5, 6]
+ printRange(my_list1)
-This function is named ``drawSquare``. It has two parameters --- one to tell
-the function which turtle to move around and the other to tell it the size
-of the square we want drawn. In the function definition they are called ``t`` and ``sz`` respectively. Make sure you know where the body of the function
+This function is named ``printRange``. It has one parameter --- a variable storing a list of numbers. In the function definition this parameter is called
+``lst``. Make sure you know where the body of the function
ends --- it depends on the indentation and the blank lines don't count for
this purpose!
@@ -129,9 +119,8 @@ Defining a new function does not make the function run. To do that we need a
``print``, ``range`` and ``int``. Function calls contain the name of the function to be
executed followed by a list of values in parentheses, called *arguments*, which are assigned
to the parameters in the function definition.
-So in the second to the last line of
-the program, we call the function, and pass ``alex`` as the turtle to be manipulated,
-and 50 as the size of the square we want.
+So in the last line of
+the program, we call the function, and pass ``my_list1`` as the list to be analyzed.
.. The parameters being sent to the function, sometimes referred to as the **actual parameters** or **arguments**,
.. represent the specific data items that the function will use when it is executing.
@@ -142,67 +131,24 @@ and 50 as the size of the square we want.
Once we've defined a function, we can call it as often as we like and its
statements will be executed each time we call it. In this case, we could use it to get
-one of our turtles to draw a square and then we can move the turtle and have it draw a different square in a
-different location. Note that we lift the tail so that when ``alex`` moves there is no trace. We put the tail
-back down before drawing the next square. Make sure you can identify both invocations of the ``drawSquare`` function.
-
-.. activecode:: ch04_1a
- :nocodelens:
-
- import turtle
-
- def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
-
- for i in range(4):
- t.forward(sz)
- t.left(90)
+the size of the range of multiple lists. Make sure you can identify all three invocations of the ``printRange`` function.
-
- wn = turtle.Screen() # Set up the window and its attributes
- wn.bgcolor("lightgreen")
-
- alex = turtle.Turtle() # create alex
- drawSquare(alex, 50) # Call the function to draw the square
-
- alex.penup()
- alex.goto(100,100)
- alex.pendown()
-
- drawSquare(alex,75) # Draw another square
-
- wn.exitonclick()
-
-In the next example, we've changed the ``drawSquare``
-function a little and we get ``tess`` to draw 15 squares with some variations. Once the function has
-been defined, we can call it as many times as we like with whatever actual parameters we like.
-
-.. activecode:: ch04_2
+.. activecode:: ch04_1
:nocodelens:
- import turtle
-
- def drawMulticolorSquare(t, sz):
- """Make turtle t draw a multi-colour square of sz."""
- for i in ['red','purple','hotpink','blue']:
- t.color(i)
- t.forward(sz)
- t.left(90)
-
- wn = turtle.Screen() # Set up the window and its attributes
- wn.bgcolor("lightgreen")
+ def printRange(lst):
+ """Prints the size of the range of lst."""
+ smallest = min(lst)
+ largest = max(lst)
+ print(largest - smallest)
- tess = turtle.Turtle() # create tess and set some attributes
- tess.pensize(3)
- size = 20 # size of the smallest square
- for i in range(15):
- drawMulticolorSquare(tess, size)
- size = size + 10 # increase the size for next time
- tess.forward(10) # move tess along a little
- tess.right(18) # and give her some extra turn
+ my_list1 = [1, 2, 3, 4, 5, 6]
+ my_list2 = [2, 6, 9, 16, 42, 100, 2, 5]
+ printRange(my_list1)
+ printRange(my_list2)
+ printRange([5, 10, 1000, 2])
- wn.exitonclick()
.. warning::
@@ -210,8 +156,8 @@ been defined, we can call it as many times as we like with whatever actual param
the parentheses ``( )`` after the function name are *required*. This
can lead to a difficult bug: A function name without the
parenthesis is a legal expression *referring* to the function; for example,
- ``print`` and ``alex.penup``, but they do
- not *call* the associated functions.
+ ``print``, but it does
+ not *call* the associated function. Try it below if you want to see.
.. note::
@@ -267,10 +213,10 @@ been defined, we can call it as many times as we like with whatever actual param
.. mchoice:: test_question5_1_4
:practice: T
- :answer_a: def drawSquare(t, sz)
- :answer_b: drawSquare
- :answer_c: drawSquare(t, sz)
- :answer_d: Make turtle t draw a square with side sz.
+ :answer_a: def printSquare(size)
+ :answer_b: printSquare
+ :answer_c: printSquare(size)
+ :answer_d: Print a square of asterices with side size.
:correct: b
:feedback_a: This line is the complete function header (except for the semi-colon) which includes the name as well as several other components.
:feedback_b: Yes, the name of the function is given after the keyword def and before the list of parameters.
@@ -281,61 +227,58 @@ been defined, we can call it as many times as we like with whatever actual param
.. code-block:: python
- def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
- for i in range(4):
- t.forward(sz)
- t.left(90)
+ def printSquare(size):
+ """Print a square of asterices with side size."""
+ for i in range(size):
+ print("*"*size)
.. mchoice:: test_question5_1_5
:practice: T
:answer_a: i
- :answer_b: t
- :answer_c: t, sz
- :answer_d: t, sz, i
+ :answer_b: size, i
+ :answer_c: size
+ :answer_d: "*"*size
:correct: c
:feedback_a: i is a variable used inside of the function, but not a parameter, which is passed in to the function.
- :feedback_b: t is only one of the parameters to this function.
- :feedback_c: Yes, the function specifies two parameters: t and sz.
- :feedback_d: the parameters include only those variables whose values that the function expects to receive as input. They are specified in the header of the function.
+ :feedback_b: i is a variable used inside of the function, but not a parameter, which is passed in to the function.
+ :feedback_c: Yes, the function specifies one parameter: size.
+ :feedback_d: This is an argument provided to the call to print().
What are the parameters of the following function?
.. code-block:: python
- def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
- for i in range(4):
- t.forward(sz)
- t.left(90)
+ def printSquare(size):
+ """Print a square of asterices with side size."""
+ for i in range(size):
+ print("*"*size)
.. mchoice:: test_question5_1_6
:practice: T
- :answer_a: def drawSquare(t, sz)
- :answer_b: drawSquare
- :answer_c: drawSquare(10)
- :answer_d: drawSquare(alex, 10):
- :answer_e: drawSquare(alex, 10)
+ :answer_a: def printSquare(size)
+ :answer_b: printSquare
+ :answer_c: printSquare(10)
+ :answer_d: printSquare(my_size):
+ :answer_e: printSquare(size):
:correct: e
- :feedback_a: No, t and sz are the names of the formal parameters to this function. When the function is called, it requires actual values to be passed in.
+ :feedback_a: No, size is the name of the formal parameter to this function. When the function is called, it requires an actual value to be passed in.
:feedback_b: A function call always requires parentheses after the name of the function.
- :feedback_c: This function takes two parameters (arguments)
- :feedback_d: A colon is only required in a function definition. It will cause an error with a function call.
- :feedback_e: Since alex was already previously defined and 10 is a value, we have passed in two correct values for this function.
+ :feedback_c: Yes, this would work
+ :feedback_d: Yes, this would work since my_size is already defined.
+ :feedback_e: A colon is only required in a function definition. It will cause an error with a function call.
- Considering the function below, which of the following statements correctly invokes, or calls, this function (i.e., causes it to run)? Assume we already have a turtle named alex.
+ Considering the function below, which of the following statements correctly invokes, or calls, this function (i.e., causes it to run)? Assume we already have a variable named my_size.
.. code-block:: python
- def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
- for i in range(4):
- t.forward(sz)
- t.left(90)
+ def printSquare(size):
+ """Print a square of asterices with side size."""
+ for i in range(size):
+ print("*"*size)
diff --git a/_sources/Functions/mainfunction.rst b/_sources/Functions/mainfunction.rst
index addbdf8f0..9128bfabd 100644
--- a/_sources/Functions/mainfunction.rst
+++ b/_sources/Functions/mainfunction.rst
@@ -19,65 +19,54 @@ Using a Main Function
---------------------
Using functions is a good idea. It helps us to modularize our code by breaking a program
-into logical parts where each part is responsible for a specific task. For example, in one of our first programs there
-was a function called ``drawSquare`` that was responsible for having some turtle draw a square of some size.
-The actual turtle and the actual size of the square were defined to be provided as parameters. Here is that original program.
+into logical parts where each part is responsible for a specific task. For example, in one of our recent programs there
+was a function called ``square`` that was responsible for calculating the square of a number.
+After the function definition we defined a variable, called the function, and printed its results. Here is that original program.
.. code-block:: python
- import turtle
+ def square(x):
+ y = x * x
+ return y
- def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
+ toSquare = 10
+ squareResult = square(toSquare)
+ print("The result of", toSquare, "squared is", squareResult)
- for i in range(4):
- t.forward(sz)
- t.left(90)
+If you look closely at the structure of this program, we first define the function ``square``. At this point, we could have defined as many functions as were needed. Finally, there are five statements that set up the window, create the turtle, perform the function invocation, and wait for a user click to terminate the program.
- wn = turtle.Screen() # Set up the window and its attributes
- wn.bgcolor("lightgreen")
+The final three statements perform the main processing that the program will do. Notice that much of the detail has been pushed inside the ``square`` function.
+However, there are still these three lines of code that are needed to get things done.
- alex = turtle.Turtle() # create alex
- drawSquare(alex, 50) # Call the function to draw the square
-
- wn.exitonclick()
-
-
-If you look closely at the structure of this program, you will notice that we first perform all of our necessary ``import`` statements, in this case to be able to use the ``turtle`` module. Next, we define the function ``drawSquare``. At this point, we could have defined as many functions as were needed. Finally, there are five statements that set up the window, create the turtle, perform the function invocation, and wait for a user click to terminate the program.
-
-These final five statements perform the main processing that the program will do. Notice that much of the detail has been pushed inside the ``drawSquare`` function. However, there are still these five lines of code that are needed to get things done.
-
-In many programming languages (e.g. Java and C++), it is not possible to simply have statements sitting alone like this at the bottom of the program. They are required to be part of a special function that is automatically invoked by the operating system when the program is executed. This special function is called **main**. Although this is not required by the Python programming language, it is actually a good idea that we can incorporate into the logical structure of our program. In other words, these five lines are logically related to one another in that they provide the main tasks that the program will perform. Since functions are designed to allow us to break up a program into logical pieces, it makes sense to call this piece ``main``.
+In many programming languages (e.g. Java and C++), it is not possible to simply have statements sitting alone like this at the bottom of the program.
+They are required to be part of a special function that is automatically invoked by the operating system when the program is executed.
+This special function is called **main**. Although this is not required by the Python programming language, it is actually a good idea that we
+can incorporate into the logical structure of our program. In other words, these three lines are logically related to one another in that they provide the
+main tasks that the program will perform. Since functions are designed to allow us to break up a program into logical pieces, it makes sense to call this
+piece ``main``.
The following activecode shows this idea. In line 11 we have defined a new function called ``main`` that doesn't need any parameters. The five lines of main processing are now placed inside this function. Finally, in order to execute that main processing code, we need to invoke the ``main`` function (line 20). When you push run, you will see that the program works the same as it did before.
.. activecode:: ch04_1main
:nocodelens:
- import turtle
-
- def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
-
- for i in range(4):
- t.forward(sz)
- t.left(90)
+ def square(x):
+ y = x * x
+ return y
def main(): # Define the main function
- wn = turtle.Screen() # Set up the window and its attributes
- wn.bgcolor("lightgreen")
-
- alex = turtle.Turtle() # create alex
- drawSquare(alex, 50) # Call the function to draw the square
-
- wn.exitonclick()
+ toSquare = 10
+ squareResult = square(toSquare)
+ print("The result of", toSquare, "squared is", squareResult)
main() # Invoke the main function
-Now our program structure is as follows. First, import any modules that will be required. Second, define any functions that will be needed. Third, define a ``main`` function that will get the process started. And finally, invoke the main function (which will in turn call the other functions as needed).
+Now our program structure is as follows. First, import any modules that will be required (you'll read about those in the next chapter). Second, define any functions
+that will be needed. Third, define a ``main`` function that will get the process started. And finally, invoke the main function
+(which will in turn call the other functions as needed).
.. note::
@@ -110,6 +99,3 @@ The activecode below defines two simple functions and a main.
Line 12 uses an ``if`` statement to ask about the value of the ``__name__`` variable. If the value is ``"__main__"``, then the ``main`` function will be called. Otherwise, it can be assumed that the program is being imported into another program and we do not want to call ``main`` because that program will invoke the functions as needed. This ability to conditionally execute our main function can be extremely useful when we are writing code that will potentially be used by others. It allows us to include functionality that the user of the code will not need, most often as part of a testing process to be sure that the functions are working correctly.
-.. note::
-
- In order to conditionally execute the ``main`` function, we used a structure called an ``if`` statement to create what is known as selection. This topic will be studied in much more detail later.
diff --git a/_sources/Functions/toctree.rst b/_sources/Functions/toctree.rst
index 938d5bffc..d85f7f987 100644
--- a/_sources/Functions/toctree.rst
+++ b/_sources/Functions/toctree.rst
@@ -7,7 +7,6 @@ Functions
functions.rst
Functionsthatreturnvalues.rst
- UnitTesting.rst
Variablesandparametersarelocal.rst
TheAccumulatorPattern.rst
Functionscancallotherfunctions.rst
@@ -15,6 +14,6 @@ Functions
mainfunction.rst
ProgramDevelopment.rst
Composition.rst
- ATurtleBarChart.rst
+ UnitTesting.rst
Glossary.rst
Exercises.rst
diff --git a/_sources/GeneralIntro/ThePythonProgrammingLanguage.rst b/_sources/GeneralIntro/ThePythonProgrammingLanguage.rst
index c4e689c9d..512b934a4 100644
--- a/_sources/GeneralIntro/ThePythonProgrammingLanguage.rst
+++ b/_sources/GeneralIntro/ThePythonProgrammingLanguage.rst
@@ -58,11 +58,6 @@ without further translation.
.. image:: Figures/compile.png
:alt: Compile illustration
-Many modern languages use both processes. They are first compiled into a lower
-level language, called **byte code**, and then interpreted by a program called
-a **virtual machine**. Python uses both processes, but because of the way
-programmers interact with it, it is usually considered an interpreted language.
-
There are two ways to use the Python interpreter: *shell mode* and *program
mode*. In shell mode, you type Python expressions into the **Python shell**,
and the interpreter immediately shows the result. The example below shows the Python shell at work.
@@ -112,16 +107,6 @@ These examples show Python being run from a Unix command line. In other
development environments, the details of executing programs may differ. Also,
most programs are more interesting than this one.
-.. admonition:: Want to learn more about Python?
-
- If you would like to learn more about installing and using Python, here are some video links.
- `Installing Python for Windows `__ shows you how to install the Python environment under
- Windows Vista,
- `Installing Python for Mac `__ shows you how to install under Mac OS/X, and
- `Installing Python for Linux `__ shows you how to install from the Linux
- command line.
- `Using Python `__ shows you some details about the Python shell and source code.
-
**Check your understanding**
.. mchoice:: question1_2_1
diff --git a/_sources/GeneralIntro/toctree.rst b/_sources/GeneralIntro/toctree.rst
index 4a8ddbfbf..0f01d3ef9 100644
--- a/_sources/GeneralIntro/toctree.rst
+++ b/_sources/GeneralIntro/toctree.rst
@@ -15,9 +15,9 @@ General Introduction
RuntimeErrors.rst
SemanticErrors.rst
ExperimentalDebugging.rst
- FormalandNaturalLanguages.rst
ATypicalFirstProgram.rst
Comments.rst
+ FormalandNaturalLanguages.rst
Glossary.rst
Exercises.rst
\ No newline at end of file
diff --git a/_sources/IntroRecursion/toctree.rst b/_sources/IntroRecursion/toctree.rst
index 0f33af2b5..8da4ecbba 100644
--- a/_sources/IntroRecursion/toctree.rst
+++ b/_sources/IntroRecursion/toctree.rst
@@ -9,8 +9,6 @@ Recursion
CalculatingtheSumofaListofNumbers.rst
TheThreeLawsofRecursion.rst
ConvertinganIntegertoaStringinAnyBase.rst
- intro-VisualizingRecursion.rst
- SierpinskiTriangle.rst
Glossary.rst
ProgrammingExercises.rst
Exercises.rst
diff --git a/_sources/Lists/Aliasing.rst b/_sources/Lists/Aliasing.rst
index 8525b989d..560b4d9c5 100644
--- a/_sources/Lists/Aliasing.rst
+++ b/_sources/Lists/Aliasing.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-11-
+ :prefix: list-14-
:start: 1
.. index:: alias
diff --git a/_sources/Lists/AppendversusConcatenate.rst b/_sources/Lists/AppendversusConcatenate.rst
index 83d67bb3f..a169ff6c8 100644
--- a/_sources/Lists/AppendversusConcatenate.rst
+++ b/_sources/Lists/AppendversusConcatenate.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-16-
+ :prefix: list-11-
:start: 1
Append versus Concatenate
diff --git a/_sources/Lists/CloningLists.rst b/_sources/Lists/CloningLists.rst
index 3376aa8b1..9c7677363 100644
--- a/_sources/Lists/CloningLists.rst
+++ b/_sources/Lists/CloningLists.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-12-
+ :prefix: list-15-
:start: 1
.. index:: clone
diff --git a/_sources/Lists/ConcatenationandRepetition.rst b/_sources/Lists/ConcatenationandRepetition.rst
index 6114d799d..74aa97796 100644
--- a/_sources/Lists/ConcatenationandRepetition.rst
+++ b/_sources/Lists/ConcatenationandRepetition.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-6-
+ :prefix: list-5-
:start: 1
.. index::
diff --git a/_sources/Lists/ListDeletion.rst b/_sources/Lists/ListDeletion.rst
index e5dd5a6e5..0d6d3638a 100644
--- a/_sources/Lists/ListDeletion.rst
+++ b/_sources/Lists/ListDeletion.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-9-
+ :prefix: list-8-
:start: 1
.. index:: del; a list portion
diff --git a/_sources/Lists/ListMembership.rst b/_sources/Lists/ListMembership.rst
index b77dfe2b7..a47245a1c 100644
--- a/_sources/Lists/ListMembership.rst
+++ b/_sources/Lists/ListMembership.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-5-
+ :prefix: list-12-
:start: 1
.. index:: in; membership operator
diff --git a/_sources/Lists/ListMethods.rst b/_sources/Lists/ListMethods.rst
index 21e44e220..509025559 100644
--- a/_sources/Lists/ListMethods.rst
+++ b/_sources/Lists/ListMethods.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-14-
+ :prefix: list-9-
:start: 1
List Methods
diff --git a/_sources/Lists/ListSlices.rst b/_sources/Lists/ListSlices.rst
index edfe3147b..ec90110e5 100644
--- a/_sources/Lists/ListSlices.rst
+++ b/_sources/Lists/ListSlices.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-7-
+ :prefix: list-6-
:start: 1
.. index::
diff --git a/_sources/Lists/Listsandforloops.rst b/_sources/Lists/Listsandforloops.rst
index 9d7a87e58..36bd171fb 100644
--- a/_sources/Lists/Listsandforloops.rst
+++ b/_sources/Lists/Listsandforloops.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-17-
+ :prefix: list-18-
:start: 1
Lists and ``for`` loops
diff --git a/_sources/Lists/ListsareMutable.rst b/_sources/Lists/ListsareMutable.rst
index ef901545e..cfc3c6c30 100644
--- a/_sources/Lists/ListsareMutable.rst
+++ b/_sources/Lists/ListsareMutable.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-8-
+ :prefix: list-7-
:start: 1
Lists are Mutable
diff --git a/_sources/Lists/ObjectsandReferences.rst b/_sources/Lists/ObjectsandReferences.rst
index c39a2db5a..2efdfbf84 100644
--- a/_sources/Lists/ObjectsandReferences.rst
+++ b/_sources/Lists/ObjectsandReferences.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-10-
+ :prefix: list-13-
:start: 1
diff --git a/_sources/Lists/RepetitionandReferences.rst b/_sources/Lists/RepetitionandReferences.rst
index b353e0e18..ee8b4f302 100644
--- a/_sources/Lists/RepetitionandReferences.rst
+++ b/_sources/Lists/RepetitionandReferences.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-13-
+ :prefix: list-16-
:start: 1
Repetition and References
diff --git a/_sources/Lists/StringsandLists.rst b/_sources/Lists/StringsandLists.rst
index f2de1e085..b1c4fd3f2 100644
--- a/_sources/Lists/StringsandLists.rst
+++ b/_sources/Lists/StringsandLists.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-24-
+ :prefix: list-10-
:start: 1
Strings and Lists
diff --git a/_sources/Lists/TheAccumulatorPatternwithLists.rst b/_sources/Lists/TheAccumulatorPatternwithLists.rst
index 5e77a5b1a..a1f3cddf5 100644
--- a/_sources/Lists/TheAccumulatorPatternwithLists.rst
+++ b/_sources/Lists/TheAccumulatorPatternwithLists.rst
@@ -7,7 +7,7 @@
License".
.. qnum::
- :prefix: list-29-
+ :prefix: list-19-
:start: 1
.. _accumulator_lists:
diff --git a/_sources/Lists/TheReturnofLSystems.rst b/_sources/Lists/TheReturnofLSystems.rst
index 3bfb82339..c91622fc1 100644
--- a/_sources/Lists/TheReturnofLSystems.rst
+++ b/_sources/Lists/TheReturnofLSystems.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-15-
+ :prefix: list-17-
:start: 1
The Return of L-Systems
diff --git a/_sources/Lists/UsingListsasParameters.rst b/_sources/Lists/UsingListsasParameters.rst
index 8f6cbc43a..09398e42e 100644
--- a/_sources/Lists/UsingListsasParameters.rst
+++ b/_sources/Lists/UsingListsasParameters.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: list-18-
+ :prefix: list-20-
:start: 1
Using Lists as Parameters
diff --git a/_sources/Lists/toctree.rst b/_sources/Lists/toctree.rst
index 3b79795c2..f0bf30178 100644
--- a/_sources/Lists/toctree.rst
+++ b/_sources/Lists/toctree.rst
@@ -9,18 +9,19 @@ Lists
ListValues.rst
ListLength.rst
AccessingElements.rst
- ListMembership.rst
ConcatenationandRepetition.rst
ListSlices.rst
ListsareMutable.rst
ListDeletion.rst
+ ListMethods.rst
+ StringsandLists.rst
+ AppendversusConcatenate.rst
+ ListMembership.rst
+ NestedLists.rst
ObjectsandReferences.rst
Aliasing.rst
CloningLists.rst
RepetitionandReferences.rst
- ListMethods.rst
- TheReturnofLSystems.rst
- AppendversusConcatenate.rst
Listsandforloops.rst
TheAccumulatorPatternwithLists.rst
UsingListsasParameters.rst
@@ -28,8 +29,6 @@ Lists
WhichisBetter.rst
FunctionsthatProduceLists.rst
ListComprehensions.rst
- NestedLists.rst
- StringsandLists.rst
listTypeConversionFunction.rst
TuplesandMutability.rst
TupleAssignment.rst
diff --git a/_sources/MoreAboutIteration/FlowofExecutionofthewhileLoop.rst b/_sources/MoreAboutIteration/FlowofExecutionofthewhileLoop.rst
new file mode 100644
index 000000000..1a6f94ae5
--- /dev/null
+++ b/_sources/MoreAboutIteration/FlowofExecutionofthewhileLoop.rst
@@ -0,0 +1,43 @@
+.. Copyright (C) Brad Miller, David Ranum, Jeffrey Elkner, Peter Wentworth, Allen B. Downey, Chris
+ Meyers, and Dario Mitchell. Permission is granted to copy, distribute
+ and/or modify this document under the terms of the GNU Free Documentation
+ License, Version 1.3 or any later version published by the Free Software
+ Foundation; with Invariant Sections being Forward, Prefaces, and
+ Contributor List, no Front-Cover Texts, and no Back-Cover Texts. A copy of
+ the license is included in the section entitled "GNU Free Documentation
+ License".
+
+.. qnum::
+ :prefix: turtle-5-
+ :start: 1
+
+.. index:: control flow, flow of execution
+
+
+
+Flow of Execution of the while Loop
+-----------------------------------
+
+As before with ``if``, loops allow us as programmers to manipulate the control flow of a Python program.
+We can now possibly skip a portion of code, or choose to repeat it an indefinite number of times.
+
+The flowchart below provides the general sequence of steps that govern execution of a while loop.
+
+.. image:: Figures/while_flow.png
+ :width: 300px
+ :align: center
+
+
+A codelens demonstration is a good way to help you visualize exactly how the flow of control
+works with the while loop. Try stepping forward and backward through the program by pressing
+the buttons. You can see the value of ``count`` change as the loop iterates through the values from 10 to 0.
+
+.. codelens:: vtest
+
+ count = 10
+ while count > 0:
+ print(count)
+ count = count - 1
+ print("Blastoff!")
+
+
diff --git a/_sources/MoreAboutIteration/NewtonsMethod.rst b/_sources/MoreAboutIteration/NewtonsMethod.rst
index ef7c8b4e4..fb99ac735 100644
--- a/_sources/MoreAboutIteration/NewtonsMethod.rst
+++ b/_sources/MoreAboutIteration/NewtonsMethod.rst
@@ -38,22 +38,22 @@ value whose square root will be approximated. The second is the number of times
calculation yielding a better result.
.. activecode:: chp07_newtonsdef
-
- def newtonSqrt(n, howmany):
- approx = 0.5 * n
- for i in range(howmany):
- betterapprox = 0.5 * (approx + n/approx)
- approx = betterapprox
- return betterapprox
-
- print(newtonSqrt(100, 10))
- print(newtonSqrt(4, 10))
- print(newtonSqrt(1, 10))
+
+ n = 100
+ howmany = 10
+
+ approx = 0.5 * n
+ for i in range(howmany):
+ betterapprox = 0.5 * (approx + n/approx)
+ approx = betterapprox
+ prin(betterapprox)
.. admonition:: Modify the program ...
- All three of the calls to ``newtonSqrt`` in the previous example produce the correct square root for the first parameter. However, were 10 iterations required to get the correct answer? Experiment with different values for the number of repetitions (the 10 on lines 8, 9, and 10). For each of these calls, find the **smallest** value for the number of repetitions that will produce the **correct** result.
+ The values used in the previous example produce the correct square root for 100. However, were 10 iterations required to get the correct answer?
+ Experiment with different values for the number of repetitions (howmany on line 2). Find the **smallest** value for the number of
+ repetitions that will produce the **correct** result.
Repeating more than the required number of times is a waste of computing resources. So definite iteration is not a good solution to this problem.
@@ -66,15 +66,13 @@ uses a ``while`` condition to execute until the approximation is no longer chang
.. codelens:: chp07_newtonswhile
- def newtonSqrt(n):
- approx = 0.5 * n
- better = 0.5 * (approx + n/approx)
- while better != approx:
- approx = better
- better = 0.5 * (approx + n/approx)
- return approx
-
- print(newtonSqrt(10))
+ n = 10
+ approx = 0.5 * n
+ better = 0.5 * (approx + n/approx)
+ while better != approx:
+ approx = better
+ better = 0.5 * (approx + n/approx)
+ print(approx)
.. note::
diff --git a/_sources/MoreAboutIteration/SentinelValuesAndValidation.rst b/_sources/MoreAboutIteration/SentinelValuesAndValidation.rst
index a5f14f344..8e22d4713 100644
--- a/_sources/MoreAboutIteration/SentinelValuesAndValidation.rst
+++ b/_sources/MoreAboutIteration/SentinelValuesAndValidation.rst
@@ -21,7 +21,7 @@ Other uses of ``while``
Sentinel Values
~~~~~~~~~~~~~~~~~~~
-Indefinite loops are much more common in the real world than definite loops.
+The indefinite loops provided by the ``while`` statement are common in the real world.
* If you are selling tickets to an event, you don't know in advance how
many tickets you will sell. You keep selling tickets as long as people come
@@ -60,25 +60,22 @@ zero is a **sentinel value**, a value used to signal the end of the loop. Here's
.. activecode:: ch07_sentinel
:timelimit: 60000
-
- def checkout():
- total = 0
- count = 0
- moreItems = True
- while moreItems:
- price = float(input('Enter price of item (0 when done): '))
- if price != 0:
- count = count + 1
- total = total + price
- print('Subtotal: $', total)
- else:
- moreItems = False
- average = total / count
- print('Total items:', count)
- print('Total $', total)
- print('Average price per item: $', average)
-
- checkout()
+
+ total = 0
+ count = 0
+ moreItems = True
+ while moreItems:
+ price = float(input('Enter price of item (0 when done): '))
+ if price != 0:
+ count = count + 1
+ total = total + price
+ print('Subtotal: $', total)
+ else:
+ moreItems = False
+ average = total / count
+ print('Total items:', count)
+ print('Total $', total)
+ print('Average price per item: $', average)
There are still a few problems with this program.
@@ -122,20 +119,17 @@ When you run the following code, try typing something other than Y or N to see h
.. activecode:: ch07_validation
:timelimit: 60000
-
- def get_yes_or_no(message):
- valid_input = False
- answer = input(message)
- while not valid_input:
- answer = answer.upper() # convert to upper case
- if answer == 'Y' or answer == 'N':
- valid_input = True
- else:
- answer = input('Please enter Y for yes or N for no. \n' + message)
- return answer
-
- response = get_yes_or_no('Do you like lima beans? Y)es or N)o: ')
- if response == 'Y':
- print('Great! They are very healthy.')
- else:
- print('Too bad. If cooked right, they are quite tasty.')
+
+ valid_input = False
+ response = input('Do you like lima beans? Y)es or N)o: ')
+ while not valid_input:
+ response = response.upper() # convert to upper case
+ if response == 'Y' or response == 'N':
+ valid_input = True
+ else:
+ response = input('Please enter Y for yes or N for no. \n' + message)
+
+ if response == 'Y':
+ print('Great! They are very healthy.')
+ else:
+ print('Too bad. If cooked right, they are quite tasty.')
diff --git a/_sources/MoreAboutIteration/The3n1Sequence.rst b/_sources/MoreAboutIteration/The3n1Sequence.rst
index 25d0b377d..26ed77599 100644
--- a/_sources/MoreAboutIteration/The3n1Sequence.rst
+++ b/_sources/MoreAboutIteration/The3n1Sequence.rst
@@ -14,28 +14,27 @@
The 3n + 1 Sequence
-------------------
-As another example of indefinite iteration, let's look at a sequence that has fascinated mathematicians for many years.
+As another example of iteration with ``while``, let's look at a sequence that has fascinated mathematicians for many years.
The rule for creating the sequence is to start from
some positive integer, call it ``n``, and to generate
the next term of the sequence from ``n``, either by halving ``n``,
whenever ``n`` is even, or else by multiplying it by three and adding 1 when it is odd. The sequence
terminates when ``n`` reaches 1.
-This Python function captures that algorithm. Try running this program several times supplying different values for n.
+This Python code captures that algorithm. Try running this program several times supplying different values for n.
.. activecode:: ch07_indef1
- def seq3np1(n):
- """ Print the 3n+1 sequence from n, terminating when it reaches 1."""
- while n != 1:
- print(n)
- if n % 2 == 0: # n is even
- n = n // 2
- else: # n is odd
- n = n * 3 + 1
- print(n) # the last print is 1
-
- seq3np1(3)
+ n = 3
+
+ """ Print the 3n+1 sequence from n, terminating when it reaches 1."""
+ while n != 1:
+ print(n)
+ if n % 2 == 0: # n is even
+ n = n // 2
+ else: # n is odd
+ n = n * 3 + 1
+ print(n) # the last print is 1
@@ -57,12 +56,6 @@ time through the loop until it reaches 1.
You might like to have some fun and see if you can find a small starting
number that needs more than a hundred steps before it terminates.
-
-.. admonition:: Lab
-
- * `Experimenting with the 3n+1 Sequence <../Labs/sequencelab.html>`_ In this guided lab exercise we will try to learn more about this sequence.
-
-
Particular values aside, the interesting question is whether we can prove that
this sequence terminates for *all* positive values of ``n``. So far, no one has been able
to prove it *or* disprove it!
@@ -77,24 +70,6 @@ You'll notice that if you don't stop when you reach one, the sequence gets into
its own loop: 1, 4, 2, 1, 4, 2, 1, 4, and so on. One possibility is that there might
be other cycles that we just haven't found.
-.. admonition:: Choosing between ``for`` and ``while``
-
- Use a ``for`` loop if you know the maximum number of times that you'll
- need to execute the body. For example, if you're traversing a list of elements,
- or can formulate a suitable call to ``range``, then choose the ``for`` loop.
-
- So any problem like "iterate this weather model run for 1000 cycles", or "search this
- list of words", "check all integers up to 10000 to see which are prime" suggest that a ``for`` loop is best.
-
- By contrast, if you are required to repeat some computation until some condition is
- met, as we did in this 3n + 1 problem, you'll need a ``while`` loop.
-
- As we noted before, the first case is called **definite iteration** --- we have some definite bounds for
- what is needed. The latter case is called **indefinite iteration** --- we are not sure
- how many iterations we'll need --- we cannot even establish an upper bound!
-
-
-
.. There are also some great visualization tools becoming available to help you
.. trace and understand small fragments of Python code. The one we recommend is at
.. http://netserv.ict.ru.ac.za/python3_viz
diff --git a/_sources/MoreAboutIteration/TheforLoop.rst b/_sources/MoreAboutIteration/TheforLoop.rst
new file mode 100644
index 000000000..45366ce09
--- /dev/null
+++ b/_sources/MoreAboutIteration/TheforLoop.rst
@@ -0,0 +1,94 @@
+.. Copyright (C) Brad Miller, David Ranum, Jeffrey Elkner, Peter Wentworth, Allen B. Downey, Chris
+ Meyers, and Dario Mitchell. Permission is granted to copy, distribute
+ and/or modify this document under the terms of the GNU Free Documentation
+ License, Version 1.3 or any later version published by the Free Software
+ Foundation; with Invariant Sections being Forward, Prefaces, and
+ Contributor List, no Front-Cover Texts, and no Back-Cover Texts. A copy of
+ the license is included in the section entitled "GNU Free Documentation
+ License".
+
+.. qnum::
+ :prefix: turtle-3-
+ :start: 1
+
+.. index:: for loop, iteration, body
+ loop; for
+
+The ``for`` Loop
+----------------
+
+
+The ``while`` statement is a general-purpose tool for iteration, and is necessary for any instance of iteration where we don't know how many repetitions will be needed.
+However, if we do know how many are needed, there is a more efficient method: the ``for`` statement.
+
+As a simple example, let's say we have some friends, and
+we'd like to send them each an email inviting them to our party. We
+don't quite know how to send email yet, so for the moment we'll just print a
+message for each friend.
+
+.. activecode:: ch03_4
+ :nocanvas:
+ :tour_1: "Overall Tour"; 1-2: Example04_Tour01_Line01; 2: Example04_Tour01_Line02; 1: Example04_Tour01_Line03;
+
+ for name in ["Joe", "Amy", "Brad", "Angelina", "Zuki", "Thandi", "Paris"]:
+ print(f"Hi {name}! Please come to my party on Saturday!")
+
+
+Take a look at the output produced when you press the ``run`` button. There is one line printed for each friend. Here's how it works:
+
+
+* **name** in this ``for`` statement is the **loop variable**.
+* The list of names in the square brackets is a regular list. Later we'll see that other types besides lists can be put in this spot.
+* Line 2 is the **loop body**. Like with while, the loop body is always
+ indented. The loop body is performed one time for each name in the list.
+* On each *iteration* or *pass* of the loop, a check is done to see if
+ there are still more items to be processed. If there are none left (this is
+ called the **terminating condition** of the loop), the loop has finished.
+ Program execution continues at the next statement after the loop body.
+* If there are items still to be processed, the loop variable is updated to
+ refer to the next item in the list. This means, in this case, that the loop
+ body is executed here 7 times, and each time ``name`` will refer to a different
+ friend.
+* At the end of each execution of the body of the loop, Python returns
+ to the ``for`` statement, to see if there are more items to be handled.
+
+.. note::
+
+ Introduction of the for statement causes us to think about the types of iteration we have seen. The ``for`` statement will always iterate through a sequence of
+ values like the list of names for the party.
+ Since we know that it will iterate once for each value in the collection, it is often said that a ``for`` loop creates a
+ **definite iteration** because we definitely know how many times we are going to iterate. On the other
+ hand, the ``while`` statement is dependent on a condition that needs to evaluate to ``False`` in order
+ for the loop to terminate. Since we do not necessarily know when this will happen, it creates what we
+ call **indefinite iteration**. Indefinite iteration simply means that we don't know how many times we will repeat but eventually the condition
+ controlling the iteration will fail and the iteration will stop. (Unless we have an infinite loop which is of course a problem.)
+
+.. admonition:: Choosing between ``for`` and ``while``
+
+ Use a ``for`` loop if you know the maximum number of times that you'll
+ need to execute the body. For example, if you're traversing a list of elements,
+ or can formulate a suitable call to ``range``, then choose the ``for`` loop.
+
+ So any problem like "iterate this weather model run for 1000 cycles", or "search this
+ list of words", "check all integers up to 10000 to see which are prime" suggest that a ``for`` loop is best.
+
+ By contrast, if you are required to repeat some computation until some condition is
+ met, as we did in this 3n + 1 problem, you'll need a ``while`` loop.
+
+What you will notice here is that the ``while`` loop is more work for
+you --- the programmer --- than the equivalent ``for`` loop. When using a ``while``
+loop you have to control the loop variable yourself. You give it an initial value, test
+for completion, and then make sure you change something in the body so that the loop
+terminates.
+
+**Check your understanding**
+
+.. mchoice:: test_question7_6_1
+ :practice: T
+ :answer_a: True
+ :answer_b: False
+ :correct: a
+ :feedback_a: The syntax for a for-loop can make it easier and more appealing, but a while loop is just as powerful as a for-loop and often more flexible.
+ :feedback_b: Often a for-loop is more natural and convenient for a task, but that same task can always be expressed using a while loop.
+
+ True or False: You can rewrite any for-loop as a while-loop.
diff --git a/_sources/MoreAboutIteration/TherangeFunction.rst b/_sources/MoreAboutIteration/TherangeFunction.rst
new file mode 100644
index 000000000..fcafc68c3
--- /dev/null
+++ b/_sources/MoreAboutIteration/TherangeFunction.rst
@@ -0,0 +1,193 @@
+.. Copyright (C) Brad Miller, David Ranum, Jeffrey Elkner, Peter Wentworth, Allen B. Downey, Chris
+ Meyers, and Dario Mitchell. Permission is granted to copy, distribute
+ and/or modify this document under the terms of the GNU Free Documentation
+ License, Version 1.3 or any later version published by the Free Software
+ Foundation; with Invariant Sections being Forward, Prefaces, and
+ Contributor List, no Front-Cover Texts, and no Back-Cover Texts. A copy of
+ the license is included in the section entitled "GNU Free Documentation
+ License".
+
+.. qnum::
+ :prefix: turtle-8-
+ :start: 1
+
+The range Function
+------------------
+
+.. youtube:: YK8QlIT3__M
+ :divid: advrange
+ :height: 315
+ :width: 560
+ :align: left
+
+In our first example of a while loop, we counted down from 10 to 0. If we were to consider doing this with a for loop, we would need to construct our own series of numbers
+to loop through them.
+
+It turns out that generating lists with a specific number of integers is a very common thing to do, especially when you
+want to write simple ``for loop`` controlled iteration. The conventional thing to do is to use a list of integers starting with 0.
+In fact, these lists are so popular that Python gives us special built-in ``range`` objects that can deliver a sequence of values to
+the ``for`` loop. When called with one parameter, the sequence provided by ``range`` always starts with 0. If you ask for ``range(4)``, then you will get 4 values starting with 0. In other words, 0, 1, 2, and finally 3. Notice that 4 is not included since we started with 0. Likewise, ``range(10)`` provides 10 values, 0 through 9.
+
+.. sourcecode:: python
+
+ for i in range(4):
+ # Executes the body with i = 0, then 1, then 2, then 3
+ for x in range(10):
+ # sets x to each of ... [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+.. note::
+
+ Computer scientists like to count from 0!
+
+
+So to count something ten times, a good Python programmer would do this:
+
+.. sourcecode:: python
+
+ for i in range(10):
+ #do something
+
+
+The `range `_ function is actually a very powerful function
+when it comes to
+creating sequences of integers. It can take one, two, or three parameters. We have seen
+the simplest case of one parameter such as ``range(4)`` which creates ``[0, 1, 2, 3]``.
+But what if we really want to have the sequence ``[1, 2, 3, 4]``?
+We can do this by using a two parameter version of ``range`` where the first parameter is the starting point and the second parameter is the ending point. The evaluation of ``range(1,5)`` produces the desired sequence. What happened to the 5?
+In this case we interpret the parameters of the range function to mean
+range(start,beyondLast), where beyondLast means an index past the last index we want. In the 2-parameter version
+of range, that is the last index included + 1.
+
+
+.. note::
+
+ Why in the world would range not just work like range(start,
+ stop)? Think about it like this. Because computer scientists like to
+ start counting at 0 instead of 1, ``range(N)`` produces a sequence of
+ things that is N long, but the consequence of this is that the final
+ number of the sequence is N-1. In the case of start,
+ stop it helps to simply think that the sequence begins with start and
+ continues as long as the number is less than stop.
+
+.. note::
+ The range function is *lazy*: It produces the next element only when needed.
+ With a regular Python 3 interpreter, printing a range does *not* calculate all the elements.
+ To immediately calculate all the elements in a range,
+ wrap the range in a list, like ``list(range(4))``.
+ Activecode is not designed to work on very long sequences, and it may allow you to be
+ sloppy, avoiding the list function, and *see* the elements in the range with ``print(range(4))``.
+
+Here are two examples for you to run. Try them and then add another line below to create a sequence starting
+at 10 and going up to 20 (including 20).
+
+.. activecode:: ch03_5
+ :nocanvas:
+
+ print(list(range(4)))
+ print(list(range(1, 5)))
+
+
+Codelens will help us to further understand the way range works. In this case, the variable ``i`` will take on values
+produced by the ``range`` function.
+
+.. codelens:: rangeme
+
+ for i in range(10):
+ print(i)
+
+
+
+Finally, suppose we want to actually count down from 10 to 1.
+How would we do that? Easy, we add another parameter, a step,
+that tells range what to count by. For our purposes, we want to start at 10
+and count down by 1 each time. So if we wanted 10 numbers counting down we would use
+``range(10,0,-1)``. The most general form of the range is
+``range(start, beyondLast, step)``. You can also create a sequence of numbers that
+skips some using a step size larger than 1 or smaller than -1.
+
+.. activecode:: ch03_6
+ :nocanvas:
+
+ print(list(range(0, 19, 2)))
+ print(list(range(0, 20, 2)))
+ print(list(range(10, 0, -1)))
+
+Try it in codelens. Do you see why the first two statements produce the same result?
+
+
+.. codelens:: rangeme2
+
+ for i in range(0, 20, 2):
+ print(i)
+
+**Check your understanding**
+
+.. mchoice:: test_question3_5_1
+ :practice: T
+ :answer_a: Range should generate a sequence that stops before 10 (including 9).
+ :answer_b: Range should generate a sequence that starts at 10 (including 10).
+ :answer_c: Range should generate a sequence starting at 3 that stops at 10 (including 10).
+ :answer_d: Range should generate a sequence using every 10th number between the start and the stopping number.
+ :correct: a
+ :feedback_a: Range will generate the sequence 3, 5, 7, 9.
+ :feedback_b: The first argument (3) tells range what number to start at.
+ :feedback_c: Range will always stop at the number in the sequence before (not including) the specified limit for the sequence.
+ :feedback_d: The third argument (2) tells range how many numbers to skip between each element in the sequence.
+
+ In the command range(3, 10, 2), what does the second argument (10) specify?
+
+.. mchoice:: test_question3_5_2
+ :practice: T
+ :answer_a: range(2, 5, 8)
+ :answer_b: range(2, 8, 3)
+ :answer_c: range(2, 10, 3)
+ :answer_d: range(8, 1, -3)
+ :correct: c
+ :feedback_a: This command generates the sequence with just the number 2 because the first parameter (2) tells range where to start, the second number tells range where to end (before 5) and the third number tells range how many numbers to skip between elements (8). Since 10 >= 5, there is only one number in this sequence.
+ :feedback_b: This command generates the sequence 2, 5 because 8 is not less than 8 (the specified number past the end).
+ :feedback_c: The first number is the starting point, the second is past the last allowed, and the third is the amount to increment by.
+ :feedback_d: This command generates the sequence 8, 5, 2 because it starts at 8, ends before 1, and skips to every third number going down.
+
+ What command correctly generates the sequence 2, 5, 8?
+
+.. mchoice:: test_question3_5_3
+ :practice: T
+ :answer_a: It will generate a sequence starting at 0, with every number included up to but not including the argument it was passed.
+ :answer_b: It will generate a sequence starting at 1, with every number up to but not including the argument it was passed.
+ :answer_c: It will generate a sequence starting at 1, with every number including the argument it was passed.
+ :answer_d: It will cause an error: range always takes exactly 3 arguments.
+ :correct: a
+ :feedback_a: Yes, if you only give one number to range it starts with 0 and ends before the number specified incrementing by 1.
+ :feedback_b: Range with one parameter starts at 0.
+ :feedback_c: Range with one parameter starts at 0, and never includes the argument it was passed.
+ :feedback_d: If range is passed only one argument, it interprets that argument as one past the end of the list.
+
+ What happens if you give range only one argument? For example: range(4)
+
+.. mchoice:: test_question3_5_4
+ :practice: T
+ :answer_a: range(5, 25, 5)
+ :answer_b: range(20, 3, -5)
+ :answer_c: range(20, 5, 4)
+ :answer_d: range(20, 5, -5)
+ :correct: b
+ :feedback_a: The step 5 is positive, while the given sequence is decreasing. This answer creates the reversed, increasing sequence.
+ :feedback_b: Yes: If we take steps of -5, not worrying about the ending, we get 20, 15, 10, 5, 0, .... The limit 3 is past the 5, so the range sequence stops with the 5.
+ :feedback_c: The step 5 is positive so the sequence would need to increase from 20 toward 4. That does not make sense and the sequence would be empty.
+ :feedback_d: the sequence can never include the second parameter (5). The second parameter must always be past the end of the range sequence.
+
+ Which range function call will produce the sequence 20, 15, 10, 5?
+
+
+.. mchoice:: test_question3_5_5
+ :practice: T
+ :answer_a: No other value would give the same sequence.
+ :answer_b: The only other choice is 14.
+ :answer_c: 11, 13, or 14
+ :correct: c
+ :feedback_a: The sequence produced has steps of 4: 2, 6, 10. The next would be 14, but it is not before the limit 12. There are other limit choices past 10, but not past 14.
+ :feedback_b: 14 would work: It is also past 10, and not past 14, but there are other integers with the same properties.
+ :feedback_c: Yes, any integer past 10, and not past the next step at 14 would work.
+
+ What could the second parameter (12) in range(2, 12, 4) be replaced with and generate exactly the same sequence?
diff --git a/_sources/MoreAboutIteration/ThewhileStatement.rst b/_sources/MoreAboutIteration/ThewhileStatement.rst
index 201fdfc99..8d08fa036 100644
--- a/_sources/MoreAboutIteration/ThewhileStatement.rst
+++ b/_sources/MoreAboutIteration/ThewhileStatement.rst
@@ -20,75 +20,39 @@ The ``while`` Statement
:width: 560
:align: left
-There is another Python statement that can also be used to build an iteration. It is called the ``while`` statement.
-The ``while`` statement provides a much more general mechanism for iterating. Similar to the ``if`` statement, it uses
-a boolean expression to control the flow of execution. The body of while will be repeated as long as the controlling boolean expression evaluates to ``True``.
+A basic building block of all programs is to be able to repeat some code
+over and over again. In computer science, we refer to this repetitive idea as **iteration**. In this section, we will explore some mechanisms for basic iteration.
-The following figure shows the flow of control.
+Let's look at our first Python statement that can be used to build an iteration. It is called the ``while`` statement. When used with other code it can be used to
+repeat code in a **while loop**. Similar to the ``if`` statement, it uses
+a boolean expression to control the flow of execution. The body of while (code indented one space in) will be repeated as long as the controlling boolean
+expression evaluates to ``True``.
-.. image:: Figures/while_flow.png
-
-We can use the ``while`` loop to create any type of iteration we wish, including anything that we have previously done with a ``for`` loop. For example, the program in the previous section could be rewritten using ``while``.
-Instead of relying on the ``range`` function to produce the numbers for our summation, we will need to produce them ourselves. To to this, we will create a variable called ``aNumber`` and initialize it to 1, the first number in the summation. Every iteration will add ``aNumber`` to the running total until all the values have been used.
-In order to control the iteration, we must create a boolean expression that evaluates to ``True`` as long as we want to keep adding values to our running total. In this case, as long as ``aNumber`` is less than or equal to the bound, we should keep going.
-
-
-
-Here is a new version of the summation program that uses a while statement.
+Here is a simple example that counts down from 10 to 0.
.. activecode:: ch07_while1
- def sumTo(aBound):
- """ Return the sum of 1+2+3 ... n """
-
- theSum = 0
- aNumber = 1
- while aNumber <= aBound:
- theSum = theSum + aNumber
- aNumber = aNumber + 1
- return theSum
-
- print(sumTo(4))
-
- print(sumTo(1000))
-
-
-
-You can almost read the ``while`` statement as if it were in natural language. It means,
-while ``aNumber`` is less than or equal to ``aBound``, continue executing the body of the loop. Within
-the body, each time, update ``theSum`` using the accumulator pattern and increment ``aNumber``. After the body of the loop, we go back up to the condition of the ``while`` and reevaluate it. When ``aNumber`` becomes greater than ``aBound``, the condition fails and flow of control continues to the ``return`` statement.
-
-The same program in codelens will allow you to observe the flow of execution.
-
-.. codelens:: ch07_while2
-
- def sumTo(aBound):
- """ Return the sum of 1+2+3 ... n """
-
- theSum = 0
- aNumber = 1
- while aNumber <= aBound:
- theSum = theSum + aNumber
- aNumber = aNumber + 1
- return theSum
-
- print(sumTo(4))
-
-
-
-More formally, here is the flow of execution for a ``while`` statement:
-
-#. Evaluate the condition, yielding ``False`` or ``True``.
-#. If the condition is ``False``, exit the ``while`` statement and continue
- execution at the next statement.
-#. If the condition is ``True``, execute each of the statements in the body and
- then go back to step 1.
-
-The body consists of all of the statements below the header with the same
-indentation.
-
-This type of flow is called a **loop** because the third step loops back around
-to the top. Notice that if the condition is ``False`` the first time through the
+ count = 10
+ while count > 0:
+ print(count)
+ count = count - 1
+ print("Blastoff!")
+
+
+* **count** is a normal variable here, but since it is governing the ``while`` loop it is also called the **loop variable**.
+* Line 2 here is the **loop condition**. It must always be a boolean expression that will evaluate to ``False`` or ``True``.
+* Lines 3 and 4 are the **loop body**. The loop body is always
+ indented. The indentation determines exactly what statements are "in the
+ loop". The loop body is run each time the loop is repeated.
+* On each *iteration* or *pass* of the loop, a check is done to see if
+ the loop condition is True (if ``count`` is greater than zero). If it is not (this is
+ called the **terminating condition** of the loop), the loop has finished.
+ Program execution continues at the next statement after the loop body.
+* If ``count`` is greater than zero, the loop body is executed again.
+* At the end of each execution of the body of the loop, Python returns
+ to the ``while`` statement, to see if the loop should repeat.
+
+Notice that if the condition is ``False`` the first time through the
loop, the statements inside the loop are never executed.
.. warning::
@@ -102,51 +66,61 @@ loop, the statements inside the loop are never executed.
The body of the loop should change the value of one or more variables so that
eventually the condition becomes ``False`` and the loop terminates. Otherwise the
loop will repeat forever. This is called an **infinite loop**.
-An endless
-source of amusement for computer scientists is the observation that the
+An endless source of amusement for computer scientists is the observation that the
directions written on the back of the shampoo bottle (lather, rinse, repeat) create an infinite loop.
-In the case shown above, we can prove that the loop terminates because we
-know that the value of ``aBound`` is finite, and we can see that the value of ``aNumber``
-increments each time through the loop, so eventually it will have to exceed ``aBound``. In
-other cases, it is not so easy to tell.
+We can use the ``while`` loop to create any type of iteration we wish, making more general-purpose than the ``for`` loop we'll learn next week.
+For example, let us consider a program that adds all numbers from ``1`` to ``n``. To do this, we will create a variable called ``aNumber`` and initialize it to
+1, the first number in the summation. Every iteration will add ``aNumber`` to the running total until all the values have been used.
+In order to control the iteration, we must create a boolean expression that evaluates to ``True`` as long as we want to keep adding values to our
+running total. In this case, as long as ``aNumber`` is less than or equal to the bound, we should keep going.
-.. note::
+Here is the summation program that uses a while statement.
- Introduction of the while statement causes us to think about the types of iteration we have seen. The ``for`` statement will always iterate through a sequence of values like the list of names for the party or the list of numbers created by ``range``. Since we know that it will iterate once for each value in the collection, it is often said that a ``for`` loop creates a
- **definite iteration** because we definitely know how many times we are going to iterate. On the other
- hand, the ``while`` statement is dependent on a condition that needs to evaluate to ``False`` in order
- for the loop to terminate. Since we do not necessarily know when this will happen, it creates what we
- call **indefinite iteration**. Indefinite iteration simply means that we don't know how many times we will repeat but eventually the condition controlling the iteration will fail and the iteration will stop. (Unless we have an infinite loop which is of course a problem.)
+.. activecode:: ch07_while2
-What you will notice here is that the ``while`` loop is more work for
-you --- the programmer --- than the equivalent ``for`` loop. When using a ``while``
-loop you have to control the loop variable yourself. You give it an initial value, test
-for completion, and then make sure you change something in the body so that the loop
-terminates.
+ """ Return the sum of 1+2+3 ... n """
+ aBound = int(input("Please give a number n: "))
+ theSum = 0
+ aNumber = 1
+ while aNumber <= aBound:
+ theSum = theSum + aNumber
+ aNumber = aNumber + 1
+ print(theSum)
-So why have two kinds of loop if ``for`` looks easier? The next section, :ref:`randomly-walking-turtles`, shows an indefinite iteration where
-we need the extra power that we get from the ``while`` loop.
-.. note::
+You can almost read the ``while`` statement as if it were in natural language. It means,
+while ``aNumber`` is less than or equal to ``aBound``, continue executing the body of the loop. Within
+the body, each time, update ``theSum`` and increment ``aNumber``. After the body of the loop, we go
+back up to the condition of the ``while`` and reevaluate it. When ``aNumber`` becomes greater
+than ``aBound``, the condition fails and flow of control continues to the ``print`` statement.
- This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
+The same program in codelens will allow you to observe the flow of execution.
- .. activecode:: scratch_07_01
+.. codelens:: ch07_while3
+ """ Return the sum of 1+2+3 ... n """
+ aBound = 10
+ theSum = 0
+ aNumber = 1
+ while aNumber <= aBound:
+ theSum = theSum + aNumber
+ aNumber = aNumber + 1
+ print(theSum)
-**Check your understanding**
-.. mchoice:: test_question7_2_1
- :practice: T
- :answer_a: True
- :answer_b: False
- :correct: a
- :feedback_a: Although the while loop uses a different syntax, it is just as powerful as a for-loop and often more flexible.
- :feedback_b: Often a for-loop is more natural and convenient for a task, but that same task can always be expressed using a while loop.
- True or False: You can rewrite any for-loop as a while-loop.
+In the case shown above, we can prove that the loop terminates because we
+know that the value of ``aBound`` is finite, and we can see that the value of ``aNumber``
+increments each time through the loop, so eventually it will have to exceed ``aBound``. In
+other cases, it is not so easy to tell.
+
+.. note::
+
+ This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
+
+ .. activecode:: scratch_07_01
.. mchoice:: test_question7_2_2
:practice: T
diff --git a/_sources/MoreAboutIteration/intro-IterationRevisited.rst b/_sources/MoreAboutIteration/intro-IterationRevisited.rst
index fac46c62c..e1e91716a 100644
--- a/_sources/MoreAboutIteration/intro-IterationRevisited.rst
+++ b/_sources/MoreAboutIteration/intro-IterationRevisited.rst
@@ -11,7 +11,7 @@
:prefix: iter-1-
:start: 1
-Iteration Revisited
+Iteration
===================
.. index:: iteration, assignment, assignment statement, reassignment
@@ -26,10 +26,8 @@ people do poorly.
Repeated execution of a sequence of statements is called **iteration**. Because
iteration is so common, Python provides several language features to make it
-easier. We've already seen the ``for`` statement in a previous chapter. This is a very common
-form of iteration in Python. In this chapter
-we are going to look at the ``while`` statement --- another way to have your
-program do iteration.
+easier. In this chapter we are going to look at two common forms of iteration: the ``while`` statement
+and the ``for`` statement.
.. index:: for loop
diff --git a/_sources/MoreAboutIteration/toctree.rst b/_sources/MoreAboutIteration/toctree.rst
index 6b944d8ff..1a492e782 100644
--- a/_sources/MoreAboutIteration/toctree.rst
+++ b/_sources/MoreAboutIteration/toctree.rst
@@ -1,21 +1,19 @@
-More About Iteration
+Iteration
::::::::::::::::::::
.. toctree::
- :caption: More About Iteration
+ :caption: Iteration
:maxdepth: 2
- intro-IterationRevisited.rst
- Theforlooprevisited.rst
+ intro-Iteration.rst
ThewhileStatement.rst
- RandomlyWalkingTurtles.rst
+ FlowofExecutionofthewhileLoop.rst
The3n1Sequence.rst
+ SentinelValuesAndValidation.rst
+ TheforLoop.rst
+ TherangeFunction.rst
NewtonsMethod.rst
accumulatorRevisited.rst
- SentinelValuesAndValidation.rst
AlgorithmsRevisited.rst
- SimpleTables.rst
- 2DimensionalIterationImageProcessing.rst
- ImageProcessingonYourOwn.rst
Glossary.rst
Exercises.rst
diff --git a/_sources/PythonModules/CreatingModules.rst b/_sources/PythonModules/CreatingModules.rst
index c704b5971..d425cf397 100644
--- a/_sources/PythonModules/CreatingModules.rst
+++ b/_sources/PythonModules/CreatingModules.rst
@@ -7,7 +7,7 @@
Creating Modules
----------------
-You've seen how to *use* modules like ``random``, ``math``, and ``turtle``, but how would you *create* a module?
+You've seen how to *use* modules like ``random`` and ``math``, but how would you *create* a module?
Every time you've written a Python script you've created a module!
@@ -120,10 +120,6 @@ Also - look at all the awesome comments in there!
It is important to include header comments in your module that explain what the module does.
-.. admonition:: Function Comments
-
- Functions are the next chapter, but the comments used here demonstrate a common Python documentation style.
-
Ok - so we've got a function in our module now, let's use it.
*coffee_customer.py*
diff --git a/_sources/PythonModules/MoreAboutUsingModules.rst b/_sources/PythonModules/MoreAboutUsingModules.rst
index 4e3076a14..5ea3269ff 100644
--- a/_sources/PythonModules/MoreAboutUsingModules.rst
+++ b/_sources/PythonModules/MoreAboutUsingModules.rst
@@ -20,18 +20,8 @@ like any other data in Python. Module objects simply contain other Python eleme
The first thing we need to do when we wish to use a module is perform an ``import``. In the example above, the statement
-``import turtle`` creates a new name, ``turtle``, and makes it refer to a `module object`. This looks very much like
+``import math`` creates a new name, ``math``, and makes it refer to a `module object`. This looks very much like
the reference diagrams we saw earlier for simple variables.
-
-.. image:: Figures/modreference.png
-
-In order to use something contained in a module, we use the `dot` notation, providing the module name and the specific item joined together with a "dot". For example, to use the ``Turtle`` class, we say ``turtle.Turtle``. You should read
-this as: "In the module turtle, access the Python element called Turtle".
-
-We will now turn our attention to a few other modules that you might find useful.
-
-.. youtube:: SGVgAV0v-Ww
- :height: 315
- :width: 560
- :align: left
+In order to use something contained in a module, we use the `dot` notation, providing the module name and the specific item joined together with a "dot". For example, to use the ``sqrt`` function, we say ``math.sqrt``. You should read
+this as: "In the module math, access the Python element called sqrt".
diff --git a/_sources/PythonModules/modules.rst b/_sources/PythonModules/modules.rst
index f17176f66..bbd090ff9 100644
--- a/_sources/PythonModules/modules.rst
+++ b/_sources/PythonModules/modules.rst
@@ -25,28 +25,26 @@ Modules and Getting Help
A **module** is a file containing Python definitions and statements intended
for use in other Python programs. There are many Python modules that come with
-Python as part of the **standard library**. We have already used one of these quite extensively,
-the ``turtle`` module. Recall that once we import the module, we can use things
+Python as part of the **standard library**. We have already used one of these briefly,
+the ``math`` module. Recall that once we import the module, we can use things
that are defined inside.
.. activecode:: chmod_01
:nocodelens:
- import turtle # allows us to use the turtles library
+ import math # allows us to use the math library
- wn = turtle.Screen() # creates a graphics window
- alex = turtle.Turtle() # create a turtle named alex
+ print(math.factorial(10)) # prints 10!
+ print(math.exp(4)) # prints e^4
- alex.forward(150) # tell alex to move forward by 150 units
- alex.left(90) # turn by 90 degrees
- alex.forward(75) # complete the second side of a rectangle
- wn.exitonclick()
+ print(math.log2(1024)) # prints log2(1024)
+ print(math.sqrt(100)) # prints the square root of 100
-Here we are using ``Screen`` and ``Turtle``, both of which are defined inside the turtle module.
+Here we are using ``factorial``, ``exp``, ``log2``, and ``sqrt``, all of which are defined inside the math module.
-But what if no one had told us about turtle? How would we know
+But what if no one had told us about math? How would we know
that it exists. How would we know what it can do for us? The answer is to ask for help and the best place to get
help about the Python programming environment is to consult with the Python Documentation.
@@ -66,13 +64,13 @@ and to use it often.
.. image:: Figures/pythondocmedium.png
If you have not done so already, take a look at the Global Module Index. Here you will see an alphabetical listing of all
-the modules that are available as part of the standard library. Find the turtle module.
+the modules that are available as part of the standard library. Find the math module.
.. image:: Figures/moduleindexmedium.png
-.. image:: Figures/turtlemodmedium.png
-You can see that all the turtle functionality that we have talked about is there. However, there is so much more. Take some time to read through and familiarize yourself with some of the other things that turtles can do.
+You can see that all the math functionality that we have talked about is there. However, there is so much more.
+Take some time to read through and familiarize yourself with some of the other things that math can do.
@@ -84,7 +82,7 @@ You can see that all the turtle functionality that we have talked about is there
activecode used here was strictly to help us learn. It is not the way we write production programs.
To that end, it is necessary to mention that many of the modules available in standard Python
- will **not** work in the activecode environment. In fact, only turtle, math, and random have been
+ will **not** work in the activecode environment. In fact, only math and random have been
completely ported at this point. If you wish to explore any
additional modules, you will need to also explore using a more robust development environment.
diff --git a/_sources/PythonModules/toctree.rst b/_sources/PythonModules/toctree.rst
index 246062f60..fc17267f9 100644
--- a/_sources/PythonModules/toctree.rst
+++ b/_sources/PythonModules/toctree.rst
@@ -7,7 +7,6 @@ Python Modules
modules.rst
MoreAboutUsingModules.rst
- Themathmodule.rst
Therandommodule.rst
CreatingModules.rst
Glossary.rst
diff --git a/_sources/Selection/Chainedconditionals.rst b/_sources/Selection/Chainedconditionals.rst
index ec543f191..96b3a669b 100644
--- a/_sources/Selection/Chainedconditionals.rst
+++ b/_sources/Selection/Chainedconditionals.rst
@@ -135,26 +135,4 @@ Here is the same program using ``elif``.
print(x, " is 0")
-.. mchoice:: test_question6_7_2
- :practice: T
- :answer_a: a
- :answer_b: b
- :answer_c: c
- :correct: c
- :feedback_a: While the value in x is less than the value in y (3 is less than 5) it is not less than the value in z (3 is not less than 2).
- :feedback_b: The value in y is not less than the value in x (5 is not less than 3).
- :feedback_c: Since the first two Boolean expressions are false the else will be executed.
-
- What will the following code print if x = 3, y = 5, and z = 2?
-
- .. code-block:: python
-
- if x < y and x < z:
- print("a")
- elif y < x and y < z:
- print("b")
- else:
- print("c")
-
-
diff --git a/_sources/Selection/ConditionalExecutionBinarySelection.rst b/_sources/Selection/ConditionalExecutionBinarySelection.rst
index 76ab28dcc..20ac98a18 100644
--- a/_sources/Selection/ConditionalExecutionBinarySelection.rst
+++ b/_sources/Selection/ConditionalExecutionBinarySelection.rst
@@ -56,14 +56,22 @@ indented under the ``else`` clause get executed.
.. image:: Figures/flowchart_if_else.png
-
-
-As with the function definition from the last chapter and other compound
-statements like ``for``, the ``if`` statement consists of a header line and a body. The header
+As a program executes, the interpreter always keeps track of which statement is
+about to be executed. We call this the **control flow**, or the **flow of
+execution** of the program. When humans execute programs, they often use their
+finger to point to each statement in turn. So you could think of control flow
+as "Python's moving finger".
+
+Control flow until now has been strictly top to bottom, one statement at a
+time. We call this type of control **sequential**. In Python flow is sequential as long as
+successive statements are indented the *same* amount. The ``if`` statement
+introduces indented sub-statements after the if heading.
+
+Each ``if`` statement consists of a header line and a body. The header
line begins with the keyword ``if`` followed by a *boolean expression* and ends with
a colon (:).
-The more indented statements that follow are called a **block**.
+The more indented statements that follow are called a **block** or sometimes a **body**.
Each of the statements inside the first block of statements is executed in order if the boolean
expression evaluates to ``True``. The entire first block of statements
diff --git a/_sources/Selection/toctree.rst b/_sources/Selection/toctree.rst
index cd2eb1482..03604c8e8 100644
--- a/_sources/Selection/toctree.rst
+++ b/_sources/Selection/toctree.rst
@@ -6,12 +6,12 @@ Selection
:maxdepth: 2
BooleanValuesandBooleanExpressions.rst
- Logicaloperators.rst
- PrecedenceofOperators.rst
ConditionalExecutionBinarySelection.rst
OmittingtheelseClauseUnarySelection.rst
Nestedconditionals.rst
Chainedconditionals.rst
+ Logicaloperators.rst
+ PrecedenceofOperators.rst
BooleanFunctions.rst
Glossary.rst
Exercises.rst
diff --git a/_sources/Strings/ACollectionDataType.rst b/_sources/Strings/ACollectionDataType.rst
index 03c5e92c7..e8eda97bf 100644
--- a/_sources/Strings/ACollectionDataType.rst
+++ b/_sources/Strings/ACollectionDataType.rst
@@ -14,12 +14,10 @@
A Collection Data Type
----------------------
-So far we have seen built-in types like: ``int``, ``float``,
-``bool``, ``str`` and we've seen lists.
-``int``, ``float``, and
-``bool`` are considered to be simple or primitive data types because their values are not composed
+So far we have seen built-in types like: ``int``, ``float``, and ``str``.
+``int`` and ``float`` are considered to be simple or primitive data types because their values are not composed
of any smaller parts. They cannot be broken down.
-On the other hand, strings and lists are different from the others because they
+On the other hand, strings (and lists that we will talk about next chapter) are different from the others because they
are made up of smaller pieces. In the case of strings, they are made up of smaller
strings each containing one **character**.
@@ -30,7 +28,8 @@ single entity (the whole), or we may want to access its parts. This ambiguity is
Strings can be defined as sequential collections of characters. This means that the individual characters
that make up the string are assumed to be in a particular order from left to right.
-A string that contains no characters, often referred to as the **empty string**, is still considered to be a string. It is simply a sequence of zero characters and is represented by '' or "" (two single or two double quotes with nothing in between).
+A string that contains no characters, often referred to as the **empty string**, is still considered to be a string.
+It is simply a sequence of zero characters and is represented by '' or "" (two single or two double quotes with nothing in between).
.. index:: string operations, concatenation
diff --git a/_sources/Strings/StringComparison.rst b/_sources/Strings/StringComparison.rst
index e239e4b69..e566331e4 100644
--- a/_sources/Strings/StringComparison.rst
+++ b/_sources/Strings/StringComparison.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: strings-8-
+ :prefix: strings-9-
:start: 1
diff --git a/_sources/Strings/StringMethods.rst b/_sources/Strings/StringMethods.rst
index 307cfda0a..c08c30fe6 100644
--- a/_sources/Strings/StringMethods.rst
+++ b/_sources/Strings/StringMethods.rst
@@ -16,13 +16,11 @@
String Methods
--------------
-We previously saw that each turtle instance has its own attributes and
-a number of methods that can be applied to the instance. For example,
-we wrote ``tess.right(90)`` when we wanted the turtle object ``tess`` to perform the ``right`` method to turn
-to the right 90 degrees. The "dot notation" is the way we connect the name of an object to the name of a method
-it can perform.
+We previously used a few functions like ``print()`` and ``input()``. A **method** is a function that is attached to a specific Python object.
+To access this function, we write the object, then a dot ``.``, and then the name of the method. The "dot notation" is the way we connect the name of an object to the name of a method
+it can perform. For example, we can write ``ss.upper()`` when we wanted the string ``ss`` to perform the ``upper()`` method to create an upper-case version of itself.
-Strings are also objects. Each string instance has its own attributes and methods. The most important attribute of the string is the collection of characters. There are a wide variety of methods. Try the following program.
+Remember that Strings are objects. Each string instance has its own attributes and methods. The most important attribute of the string is the collection of characters. There are a wide variety of methods. Try the following program.
.. activecode:: chp08_upper
@@ -157,7 +155,7 @@ change the original. You can also consult the `Python documentation for strings
.. _Format-Strings:
-String Format Method
+F-Strings
~~~~~~~~~~~~~~~~~~~~~
In grade school quizzes a common convention is to use fill-in-the blanks. For instance,
@@ -168,26 +166,25 @@ In grade school quizzes a common convention is to use fill-in-the blanks. For in
and you can fill in the name of the person greeted, and combine
given text with a chosen insertion. *We use this as an analogy:*
Python has a similar
-construction, better called fill-in-the-braces. The string method ``format``, makes
+construction, called a formatted string or an **f-string**. An f-string makes
substitutions into places in a string
enclosed in braces. Run this code:
.. activecode:: ch08_methods3
person = input('Your name: ')
- greeting = 'Hello {}!'.format(person)
+ greeting = f'Hello {person}!'
print(greeting)
There are several new ideas here!
-The string for the ``format`` method has a special form, with braces embedded.
-Such a string is called a *format string*. Places where
-braces are embedded are replaced by the value of an expression
-taken from the parameter list for the ``format`` method. There are many
+The string has been formatted in a new way. We have included an ``f`` before the starting quotation mark.
+Such a string is called an *f-string*. Places where
+braces are embedded are replaced by the value of the expression inside the braces. There are many
variations on the syntax between the braces. In this case we use
the syntax where the first (and only) location in the string with
-braces has a substitution made from the first (and only) parameter.
+braces has the variable ``person``. When this code is evaluated, the value of the person variable is placed in the string in this location.
In the code above, this new string is assigned to the identifier
``greeting``, and then the string is printed.
@@ -201,7 +198,7 @@ version:
.. activecode:: ch08_methods4
person = input('Enter your name: ')
- print('Hello {}!'.format(person))
+ print(f'Hello {person}!')
There can be multiple substitutions, with data of any type.
Next we use floats. Try original price $2.50 with a 7% discount:
@@ -211,35 +208,29 @@ Next we use floats. Try original price $2.50 with a 7% discount:
origPrice = float(input('Enter the original price: $'))
discount = float(input('Enter discount percentage: '))
newPrice = (1 - discount/100)*origPrice
- calculation = '${} discounted by {}% is ${}.'.format(origPrice, discount, newPrice)
+ calculation = f'${origPrice} discounted by {discount}% is ${newPrice}.'
print(calculation)
-The parameters are inserted into the braces in order.
-
If you used the data suggested, this result is not satisfying.
Prices should appear with exactly two places beyond the decimal point,
but that is not the default way to display floats.
-Format strings can give further information inside the braces
+F-strings can give further information inside the braces
showing how to specially format data.
In particular floats can be shown with a specific number of decimal places.
-For two decimal places, put ``:.2f`` inside the braces for the monetary values:
+For two decimal places, put ``:.2f`` inside the braces but after the variable name for the monetary values:
.. activecode:: ch08_methods6
origPrice = float(input('Enter the original price: $'))
discount = float(input('Enter discount percentage: '))
newPrice = (1 - discount/100)*origPrice
- calculation = '${:.2f} discounted by {}% is ${:.2f}.'.format(origPrice, discount, newPrice)
+ calculation = f'${origPrice:.2f} discounted by {discount}% is ${newPrice:.2f}.'
print(calculation)
The 2 in the format modifier can be replaced by another integer to round to that
specified number of digits.
-This kind of format string depends directly on the order of the
-parameters to the format method. There are other approaches that we will
-skip here, explicitly numbering substitutions and taking substitutions from a dictionary.
-
A technical point: Since braces have special meaning in a format
string, there must be a special rule if you want braces to actually
be included in the final *formatted* string. The rule is to double
@@ -251,40 +242,22 @@ formatted string::
a = 5
b = 9
- setStr = 'The set is {{ {},{} }}.'.format(a, b)
+ setStr = f'The set is {{ {a},{b} }}.'
print(setStr)
Unfortunately, at the time of this writing, the ActiveCode format implementation has a bug,
printing doubled braces, but standard Python prints ``{5, 9}``.
-You can have multiple placeholders indexing the same argument, or perhaps even have extra
-arguments that are not referenced at all:
-
-.. activecode:: ch08_formatspecification
-
- letter = """
- Dear {0} {2}.
- {0}, I have an interesting money-making proposition for you!
- If you deposit $10 million into my bank account, I can
- double your money ...
- """
-
- print(letter.format("Paris", "Whitney", "Hilton"))
- print(letter.format("Bill", "Henry", "Gates"))
-
-
-
-
.. mchoice:: test_question8_3_3
:practice: T
:answer_a: Nothing - it causes an error
- :answer_b: sum of {} and {} is {}; product: {}. 2 6 8 12
+ :answer_b: sum of {} and {} is {}; product: {}.
:answer_c: sum of 2 and 6 is 8; product: 12.
:answer_d: sum of {2} and {6} is {8}; product: {12}.
:correct: c
- :feedback_a: It is legal format syntax: put the data in place of the braces.
- :feedback_b: Put the data into the format string; not after it.
- :feedback_c: Yes, correct substitutions!
+ :feedback_a: It is legal format syntax.
+ :feedback_b: Put the value of each expression in place of the braces.
+ :feedback_c: Yes, correct!
:feedback_d: Close: REPLACE the braces.
@@ -294,7 +267,7 @@ arguments that are not referenced at all:
x = 2
y = 6
- print('sum of {} and {} is {}; product: {}.'.format( x, y, x+y, x*y))
+ print(f'sum of {x} and {y} is {x+y}; product: {x*y}.')
.. mchoice:: test_question8_3_4
@@ -313,6 +286,6 @@ arguments that are not referenced at all:
.. code-block:: python
v = 2.34567
- print('{:.1f} {:.2f} {:.7f}'.format(v, v, v))
+ print(f'{v:.1f} {v:.2f} {v:.7f}')
diff --git a/_sources/Strings/StringsareImmutable.rst b/_sources/Strings/StringsareImmutable.rst
index 3e4bca44e..ad934011e 100644
--- a/_sources/Strings/StringsareImmutable.rst
+++ b/_sources/Strings/StringsareImmutable.rst
@@ -8,7 +8,7 @@
License".
.. qnum::
- :prefix: strings-9-
+ :prefix: strings-8-
:start: 1
.. index:: mutable, immutable
diff --git a/_sources/Strings/TheSliceOperator.rst b/_sources/Strings/TheSliceOperator.rst
index f8fb8082d..283f00dc3 100644
--- a/_sources/Strings/TheSliceOperator.rst
+++ b/_sources/Strings/TheSliceOperator.rst
@@ -32,9 +32,6 @@ selecting a character:
The `slice` operator ``[n:m]`` returns the part of the string from the n'th character
to the m'th character, including the first but excluding the last. In other words, start with the character at index n and
go up to but do not include the character at index m.
-This
-behavior may seem counter-intuitive but if you recall the ``range`` function, it did not include its end
-point either.
If you omit the first index (before the colon), the slice starts at the
beginning of the string. If you omit the second index, the slice goes to the
diff --git a/_sources/Strings/toctree.rst b/_sources/Strings/toctree.rst
index 86ae0ba68..b926c10ae 100644
--- a/_sources/Strings/toctree.rst
+++ b/_sources/Strings/toctree.rst
@@ -12,18 +12,17 @@ Strings
StringMethods.rst
Length.rst
TheSliceOperator.rst
- StringComparison.rst
StringsareImmutable.rst
+ StringComparison.rst
+ Theinandnotinoperators.rst
TraversalandtheforLoopByItem.rst
TraversalandtheforLoopByIndex.rst
TraversalandthewhileLoop.rst
- Theinandnotinoperators.rst
TheAccumulatorPatternwithStrings.rst
- TurtlesandStringsandLSystems.rst
+ Characterclassification.rst
Loopingandcounting.rst
Afindfunction.rst
Optionalparameters.rst
- Characterclassification.rst
Summary.rst
Glossary.rst
Exercises.rst
diff --git a/_sources/index.rst b/_sources/index.rst
index 05921b03d..bfd39a59b 100644
--- a/_sources/index.rst
+++ b/_sources/index.rst
@@ -54,24 +54,24 @@ Table of Contents
GeneralIntro/toctree.rst
SimplePythonData/toctree.rst
- Debugging/toctree.rst
- PythonTurtle/toctree.rst
- PythonModules/toctree.rst
- Functions/toctree.rst
- Selection/toctree.rst
- MoreAboutIteration/toctree.rst
Strings/toctree.rst
Lists/toctree.rst
+ Selection/toctree.rst
+ Debugging/toctree.rst
+ MoreAboutIteration/toctree.rst
+ Functions/toctree.rst
+ PythonModules/toctree.rst
Files/toctree.rst
- Dictionaries/toctree.rst
- Exceptions/toctree.rst
- WebApps/toctree.rst
- GUIandEventDrivenProgramming/toctree.rst
IntroRecursion/toctree.rst
ClassesBasics/toctree.rst
+ Exceptions/toctree.rst
ClassesDiggingDeeper/toctree.rst
Inheritance/toctree.rst
UnitTesting/toctree.rst
+ Dictionaries/toctree.rst
+ WebApps/toctree.rst
+ GUIandEventDrivenProgramming/toctree.rst
+ PythonTurtle/toctree.rst
Labs
::::
diff --git a/conf.py b/conf.py
index 1d700d086..30c670ad9 100644
--- a/conf.py
+++ b/conf.py
@@ -51,10 +51,10 @@
generate_component_labels = False
# General information about the project.
-project = u'How to Think Like a Computer Scientist'
-copyright = u'2014 Brad Miller, David Ranum, Created using Runestone Interactive'
+project = u'Computer Science for STEM'
+copyright = u'based on the book by 2014 Brad Miller, David Ranum, Created using Runestone Interactive'
course_description = """Based on the original open source book by Allan Downy and Jeff Elkner. Learn Python, this edition is expanded with additional topics and is fully interactive. Try examples, answer questions, interactively, right in the book!"""
-key_words = "intro google active learning fun data turtle graphics learn"
+key_words = "intro google active learning fun data learn"
shelf_section = "Intro to Computer Science"
@@ -63,9 +63,9 @@
# built documents.
#
# The short X.Y version.
-version = '3.0'
+version = '1.0'
# The full version, including alpha/beta/rc tags.
-release = '3.0'
+release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -130,7 +130,7 @@
#html_theme_options = {'nosidebar': 'true'}
html_theme_options = {
# Navigation bar title. (Default: ``project`` value)
- 'navbar_title': "How To Think Like a Computer Scientist",
+ 'navbar_title': "Computer Science for STEM",
# Tab name for entire site. (Default: "Site")
'navbar_site_name': "Chapters",
@@ -177,10 +177,10 @@
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
-html_title = 'How to Think like a Computer Scientist: Interactive Edition'
+html_title = 'Computer Science for STEM'
# A shorter title for the navigation bar. Default is the same as html_title.
-html_short_title = 'How to Think Like a Computer Scientist'
+html_short_title = 'Computer Science for STEM'
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
diff --git a/pavement.py b/pavement.py
index e48cbd584..f7af9f986 100644
--- a/pavement.py
+++ b/pavement.py
@@ -21,7 +21,7 @@
######## CHANGE THIS ##########
-project_name = "thinkcspy"
+project_name = "mines_csstem"
###############################
master_url = None
@@ -48,7 +48,7 @@
doctrees=doctrees,
template_args={
"course_id": project_name,
- "course_title": "How\\ to\\ Think\\ like\\ a\\ Computer\\ Scientist",
+ "course_title": "Computer\\ Science\\ for\\ STEM",
"login_required": "false",
"appname": master_app,
"loglevel": 10,
@@ -89,7 +89,7 @@
template_args = {
"course_id": project_name,
- "course_title": "How\\ to\\ Think\\ like\\ a\\ Computer\\ Scientist",
+ "course_title": "Computer\\ Science\\ for\\ STEM",
"login_required": "false",
"appname": master_app,
"loglevel": 10,
diff --git a/pretext/AdditionalTopics/Aliasingandcopying.ptx b/pretext/AdditionalTopics/Aliasingandcopying.ptx
new file mode 100644
index 000000000..97a0c7c0e
--- /dev/null
+++ b/pretext/AdditionalTopics/Aliasingandcopying.ptx
@@ -0,0 +1,78 @@
+
+
+ Aliasing and Copying
+
Because dictionaries are mutable, you need to be aware of aliasing (as we saw with lists). Whenever
+ two variables refer to the same dictionary object, changes to one affect the other.
+ For example, opposites is a dictionary that contains pairs
+ of opposites.
As you can see from the is operator, alias and opposites refer to the same object.
+
If you want to modify a dictionary and keep a copy of the original, use the dictionary
+ copy method. Since acopy is a copy of the dictionary, changes to it will not effect the original.
+
+
+acopy = opposites.copy()
+acopy['right'] = 'left' # does not change opposites
+
+
+
+
+
+ mydict and yourdict are both names for the same dictionary.
+
+
+
+
+
None
+
+
+ The dictionary is mutable so changes can be made to the keys and values.
+
+
+
+
+
999
+
+
+ Yes, since yourdict is an alias for mydict, the value for the key elephant has been changed.
+
+
+
+
+
Error, there are two different keys named elephant.
+
+
+ There is only one dictionary with only one key named elephant. The dictionary has two different names, mydict and yourdict.
+
+
+
+
+
diff --git a/pretext/AdditionalTopics/BigO.ptx b/pretext/AdditionalTopics/BigO.ptx
new file mode 100644
index 000000000..01735d235
--- /dev/null
+++ b/pretext/AdditionalTopics/BigO.ptx
@@ -0,0 +1,202 @@
+
+
+ Big O Analysis
+
+
A common question that comes up when programming is: "How long will my program take to run?". Even if a program provides the correct output, if it takes
+ too long to finish then it is unacceptable. There is a problem here though, it's impossible to reliably say exactly how long a program will take to run.
+ It depends on too many things. The capabilities of the computer running the code, what else is running on the computer, and the size of the input are just
+ some of the things that would need to be considered.
+
+
+
To simplify this issue, we'll give up trying to estimate exactly how long a program will run, and instead look at the biggest factor that affects
+ existing code: the size of the input. If we wrote a program that ran for 60 seconds on 100 megabytes of input data, how should we expect the program to
+ react to 200 megabytes of input data? Maybe it would run in 120 seconds (twice the data for twice the run time)? Maybe it would still run in 60 seconds,
+ assuming that extra data isn't used. Or maybe the program would run for far longer. The issue is that we don't know what the relationship is between the size
+ of the input data and the behavior of the program.
+
+
This is where Big O Analysis comes in. Big O is a notation computer scientists use to describe the relationship between the size
+ of the input data and the behavior of the program. These terms are written like a mathematical function using the variable n. n as a variable represents the
+ size of the input data provided to the program. The Big O function tells us how n affects the time the program will take to complete.
+
+
Consider the example we had before. We have a program that takes 60 seconds to run on 100 megabytes of input data, we'd like to know (roughly)
+ how long the program might take to run on 200 megabytes of input data. If we know the run time of the program is the function f(n) = n^2, with n being
+ the size of the data, now we have enough information to make a guess. If n is doubled, then the time the program runs for will quadruple! (2*n)^2 = 4 * n^2.
+
+
The formal mathematical notation for Big O is denoted with a capital O (a big o!) followed by parentheses.
+ Inside of the O() is most commonly some term of n. In our previous example, we would say the program has O(n^2) behavior.
+
+
Different functions of n have different magnitudes, which helps us to quantify how quick or slow an algorithm is relative to the input size n.
+ From left to right, left being the quickest time and right being the slowest time, we typically see these complexities:
Big O is like a limit in that only the most significant terms matter as n gets bigger and bigger. We typically expect n to be very, VERY large because
+ small inputs aren't as strongly affected by time limits. If a program takes 0.001 seconds to run with most normal data, is it really a big deal if it takes 0.004
+ seconds on occasion? What if we were dealing with a program that had to run for a month though? Now that factor of four starts to hurt a lot more.
+
+
There is another important aspect that we have ignored up to this point: programs can often have wildly different behavior depending on their input.
+ Consider a contrived example:
In this program, the size of the input doesn't matter as much as whether the input string contains a letter "a" or not. If it does, the program runs forever.
+ If it doesn't, the program ends almost immediately. How do we reconcile this with our Big O notation? The answer is to be a pessimist. We adopt the assumption that
+ everything that can happen to slow down our program will happen. In the code above, we assume that the input ALWAYS will contain an "a". This assumption is broadly
+ known as the "worst case". Big O notation uses this assumption by default in every instance you will see it (at least in this class). Any other case besides "worst" will be labeled.
+
+
Let's look at some more examples:
+
+
+sum = 1 + 1
+print(sum)
+
+
+
This code has a Big O of O(1), also referred to as constant time. This is because the program does nothing with its input. In fact, it doesn't
+ even take input! Constant time operations are typically things in code which do not loop. A constant time program suggests it will always finish in a
+ consistent amount of time, no matter what happens.
+
+
Now, let's check out an example with a loop:
+
+
+def example_func(n):
+ for i in range(n):
+ print(i)
+
+
+
As you can see, this function simply prints 0 to n. Each print takes a little time, so a larger n means a longer program run time.
+ We denote the complexity of example_func as O(n),
+ because whether n = 100 or n = 10000000, as the complexity trends to infinity, it remains O(n).
+
+
In the last code example, O(n) was the complexity for all cases, because the loop always goes to n.
+
+
+
+
This figure shows complexities as a graph and which ones are considered "desirable" or at least "acceptable". Context mostly determines if these are "good" terms or not,
+ but do strive to never write something worse than O(n^3)!
+
+
It may be difficult to appreciate the implications of these terms when first seeing them. Let's say we have a set of algorithms with the following complexities, but they
+ all run with the same time (1 milliseconds) for n = 10. This table shows what will happen if we increase the size of the input:
+
+
+
+
+
+ n
+
+
+ O(log(n))
+
+
+ O(n)
+
+
+ O(n^3)
+
+
+ O(2^n)
+
+
+
+
+ 10
+
+
+ 1 ms
+
+
+ 1 ms
+
+
+ 1 ms
+
+
+ 1 ms
+
+
+
+
+ 11
+
+
+ 1 ms
+
+
+ 1.1 ms
+
+
+ ~1.3 ms
+
+
+ 2 ms
+
+
+
+
+ 20
+
+
+ 1.3 ms
+
+
+ 2 ms
+
+
+ 8 ms
+
+
+ 1 s
+
+
+
+
+ 100
+
+
+ 2 ms
+
+
+ 10 ms
+
+
+ 1 s
+
+
+ 10^16 years
+
+
+
+
+ 100000
+
+
+ 5 ms
+
+
+ 10 s
+
+
+ 31 years
+
+
+ :)
+
+
+
+
+
+
As you can see, what started off as a negligible difference exploded into a totally unacceptable time for larger input sizes applied to larger Big O terms. Examples like these are precisely why
+ computer scientists are so fixated on Big O. 100000 data points is not a lot of data. Large tech companies are often running code on billions or
+ trillions of data points, and anything less the most efficient code won't be able to run at-scale.
+
+
We will end this section with a disclaimer. We have only covered the bare basic concepts of Big O here today. If you continue to study computer science,
+ you'll have more opportunities to explore it in much more detail, including seeing the formal definition of Big O as well as learning how to determine the Big O of your own code.
+ For this specific class, we only ask you to be familiar with the notation of Big O and have a basic intuition behind what it communicates.
Have you ever seen all of the "hacker" 01010110101010s in the movies? As you might
+ know, this is called binary. While it's not actually how hacking works, binary is still the base of all computing.
+ Every word that you are reading right now was transmitted to your computer as a series of 1's and 0's. Although you won't
+ be typing 0's and 1's at a keyboard all day, binary is still useful to know.
+
+
Quick background: binary is a numbering system, just like decimal (the numbering system we normally use).
+ Decimal uses the digits 0-9, but binary only uses the digits 0 and 1, which are called bits.
+ In other words, binary is just a different way of counting.
+
+
Believe it or not, this is indirectly how you've been counting your entire life. For instance, in decimal numbering (base 10):
There are even more numbering systems, like hexadecimal and octal, but you only need to understand binary for this course.
+
+
Binary deals with powers of two (hence the name), reading from right to left and starting at 0.
+ If the bit is 0, it is "off" and the position is multiplied by 0; if the bit is 1, it is "on" and its
+ position in the number is the exponent with 2 as the base. Binary numbering is also called base 2
+ because of that. For instance:
Converting decimal to binary: A quick way to convert decimal to binary is to find the largest
+ factor of 2 that will go into the number, and concatenate 1 if it goes into the number; concatenate 0 if not. Subtract
+ the number from the running total and repeat until we hit 0. For instance:
+
+
Example: Convert 78 to binary
+
1. If we think about all of our powers of 2, 2^7 = 128 is too large (128 > 78), so we know 2^6 is where we'll start our number, and we need a 1 in that position. We now have: 1xxxxxx.
+
2. 78 - 64 = 14, which is our remainder from the last digit. 2^5 = 32 > 14, so we know 2^5 is a 0. We now have: 10xxxxx.
+
3. 78 - 64 = 14, which is our remainder from the last digit. 2^4 = 16 > 14, so we know 2^4 is a 0. We now have: 100xxxx.
+
4. 78 - 64 = 14, which is our remainder from the last digit. 2^3 = 8 < 14, so we know 2^3 is a 1 because it fits in! We now have: 1001xxx.
+
5. 78 - 64 - 8 = 6, which is our remainder from the last digit. 2^2 = 4 < 6, so we know 2^2 is a 1 because it fits in! We now have: 10011xx.
+
6. 78 - 64 - 8 - 4 = 2, which is our remainder from the last digit. 2^1 = 2 < 4, so we know 2^1 is a 1 because it fits in! We now have: 100111x.
+
7. 78 - 64 - 8 - 4 - 2 = 0, so we are done and can fill any remainders with a 0 bit.
+
Our final answer is: 1001110 (base 2)
+
+
+
+ Typically when we write binary, we'll see our bits in groups of 4, because our binary sequences are normally
+ some multiple of 4, like 8, 16, or 32. Because of this, we would add a leading zero and
+ write our previous answer as: 01001110 (base 2).
+
+
+
+
Converting binary to decimal: As mentioned above, you can simply look at each bit,
+ and add 2 to the power of its position if the bit is 1.
+
+
Like usual in math, there are a few different ways to arrive at one conclusion. These are not
+ the only ways to do conversions. If these explanations don't make sense to you, ask your instructor
+ or Google for their explanation.
+
diff --git a/pretext/AdditionalTopics/DataScience.ptx b/pretext/AdditionalTopics/DataScience.ptx
new file mode 100644
index 000000000..79a7e19cb
--- /dev/null
+++ b/pretext/AdditionalTopics/DataScience.ptx
@@ -0,0 +1,53 @@
+
+
+ Data Science
+
+
Data science is a multidisciplinary field which combines computer science,
+ math, and other domains to answer questions using data.
+
+
As the world moves more and more towards storing and analyzing large amounts of data,
+ data science is a vital skill for you to be familiar with, whether you're a computer science major or not. It is also
+ a very common and useful application of programming, which is why we're discussing it in this class.
+
+
Data science is perhaps best defined by describing what data science looks like. The data science process consists of four steps:
+
+
+
Obtaining data
+
Cleaning the data
+
Exploring the data
+
Predicting unknowns
+
+
+
Obtaining the data: We live in a time where data is more abundant then ever before. Getting a hold of data can involve gathering it yourself,
+ purchasing it, or taking advantage of the many, many sites online now which have a plethora of data
+ available for free (and sometimes paid) use. If you are getting your data from some 3rd party, it will likely come in a .csv, .json, or SQL database format.
+
+
Cleaning the data: This can vary, but ultimately you need to prepare your data
+ in a way that makes it easily usable in the next steps. Often data starts out "noisy" or contains errors. In this step you may
+ fix things in the data, change missing data, or correct wrong data.
+
+
Cleaning is regularly considered the longest step in this process! Data can come in all sorts of different
+ formats now, with anomalies, with blanks, and so much more. It often depends on context and you own goals
+ what "fixing" data even means.
+
+
Exploring the data: Now that the data is prepared, we can do some analysis on it! As the term suggests, exploring the data is about coming to better
+ understand it. You often don't know what is interesting or useful about data when you first encounter it. You may need to do some sort of statistical
+ analysis to uncover the interesting aspects, or you may want to graph values and look for relationships and trends visually.
+
+
Predicting unknowns: Having come to understand the data better, you can now use it to create new knowledge. These days, this step typically involves
+ using machine learning models. These techniques can generally be split into three groups:
+
+
+
Supervised Learning: With supervised learning, we try to construct a model that describes the relationship between inputs and outputs (regularly
+ referred to as "labels"). Knowing what labels we want in advance is what makes a method "supervised". For example, we could create a model to guess when an email
+ is spam or not based on its contents; the label here is "spam" or "not spam". Or we could try to guess what the stock price will be for our favorite company based
+ on how it has performed in the last few weeks. The label here would be the predicted stock price.
+
Unsupervised Learning: Contrasting with supervised learning, with unsupervised learning we don't know the labels in advance. An example here could be
+ using social media data to automatically identify friend groups. We don't know in advance how many groups we'll find or what their nature will be. Because of this, it
+ can be harder to guess what kind of results unsupervised learning will produce.
+
Semi-Supervised Learning: Semi-supervised learning is an attempt to capture the best aspects of both supervised and unsupervised learning. With these
+ approaches we start with some data that has labels and also some data that doesn't. To use a previous example, we could take a collection of emails, only some of
+ which have been labeled as spam or not, and still try to construct a reliable method for identifying new emails as spam. If it goes well, then we've saved ourselves
+ a lot of time that would have otherwise been spent labeling emails.
Like lists, dictionaries also support comprehensions as an alternative to dictionary generation with lengthier loops. The format for a dictionary comprehension is as follows
+
{<key-expression>:<value-expression> for <item> in <sequence> if <condition>}
+
Make careful note of the use of curly brackets instead of square brackets. These brackets are primarily how Python determines what kind of comprehension
+ you are making. Like list comprehensions, the if clause is optional.
+
Let's view an example,
+
+
+first_names = ["Radia", "Grace", "Katherine", "Jeannette"]
+last_names = ["Perlman", "Hopper", "Johnson", "Wing"]
+
+first_to_last = {first_names[i]:last_names[i] for i in range(len(first_names))}
+
+print(first_to_last)
+
+
+
This code takes two separate lists and associates their values in a new dictionary. More specifically, first names are mapped to last names.
+
Another more complicated example:
+
+
+def percentage(n):
+ """ Return a percentage value from a provided raw score, rounded to two decimal places. """
+
+ return round((n / 1000) * 100, 2)
+
+names = ["Sansa", "Jamie", "Cersei", "Jon", "Arya"]
+percentage_scores = {name:percentage(int(input(f"Please enter a score for {name}"))) for name in names}
+print(percentage_scores)
+
+
+
+
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
+
+
+
+
+
+
+
+
+ Check your understanding
+
+
+
+
What is printed by the following statements?
+
+
+alist = [4,2,8,6,5]
+dic = {num:num**2 for num in alist if num < 6}
+print(dic)
+
+
+
+
+
+
+
[4,2,5]
+
+
+ This is the list of keys that will be generated, but it is missing the associated values.
+
+
+
+
+
{4:16,2:4,8:64,6:36,5:25}
+
+
+ This is nearly correct, but has too many values. Look at the if clause.
+
+
+
+
+
{4:16,2:4,5:25}
+
+
+ Yes, this is correct.
+
+
+
+
+
{4:8,2:4,5:10}
+
+
+ These are the correct keys, but pay close attention to the value expression in the code.
+
+
+
+
+
diff --git a/pretext/AdditionalTopics/Dictionarymethods.ptx b/pretext/AdditionalTopics/Dictionarymethods.ptx
new file mode 100644
index 000000000..c1455c0bf
--- /dev/null
+++ b/pretext/AdditionalTopics/Dictionarymethods.ptx
@@ -0,0 +1,365 @@
+
+
+ Dictionary Methods
+
Dictionaries have a number of useful built-in methods.
+ The following table provides a summary and more details can be found in the
+ Python Documentation.
+
+
+
+
+ Method
+
+
+ Parameters
+
+
+ Description
+
+
+
+
+ keys
+
+
+ none
+
+
+ Returns a view of the keys in the dictionary
+
+
+
+
+ values
+
+
+ none
+
+
+ Returns a view of the values in the dictionary
+
+
+
+
+ items
+
+
+ none
+
+
+ Returns a view of the key-value pairs in the dictionary
+
+
+
+
+ get
+
+
+ key
+
+
+ Returns the value associated with key; None otherwise
+
+
+
+
+ get
+
+
+ key,alt
+
+
+ Returns the value associated with key; alt otherwise
+
+
+
+
+
The keys method returns what Python 3 calls a view of its underlying keys.
+ We can iterate over the view or turn the view into a
+ list by using the list conversion function.
+
+
+inventory = {'apples': 430, 'bananas': 312, 'oranges': 525, 'pears': 217}
+
+for akey in inventory.keys(): # the order in which we get the keys is not defined
+ print("Got key", akey, "which maps to value", inventory[akey])
+
+ks = list(inventory.keys())
+print(ks)
+
+
+
It is so common to iterate over the keys in a dictionary that you can
+ omit the keys method call in the for loop — iterating over
+ a dictionary implicitly iterates over its keys.
As we saw earlier with strings and lists, dictionary methods use dot notation,
+ which specifies the name of the method to the right of the dot and the name of
+ the object on which to apply the method immediately to the left of the dot. The empty
+ parentheses in the case of keys indicate that this method takes no parameters.
+
The values and items methods are similar to keys. They return view objects which can be turned
+ into lists or iterated over directly. Note that the items are shown as tuples containing the key and the associated value.
Note that tuples are often useful for getting both the key and the value at the same
+ time while you are looping. The two loops do the same thing.
+
The in and not in operators can test if a key is in the dictionary:
+
+
+inventory = {'apples': 430, 'bananas': 312, 'oranges': 525, 'pears': 217}
+print('apples' in inventory)
+print('cherries' in inventory)
+
+if 'bananas' in inventory:
+ print(inventory['bananas'])
+else:
+ print("We have no bananas")
+
+
+
This operator can be very useful since looking up a non-existent key in a
+ dictionary causes a runtime error.
+
The get method allows us to access the value associated with a key, similar to the [ ] operator.
+ The important difference is that get will not cause a runtime error if the key is not present. It
+ will instead return None. There exists a variation of get that allows a second parameter that serves as an alternative return value
+ in the case where the key is not present. This can be seen in the final example below. In this case, since cherries is not a key, return 0 (instead of None).
+
+
+ 23 is a value in the dictionary, not a key.
+
+
+
+
+
False
+
+
+ Yes, the in operator returns True if a key is in the dictionary, False otherwise.
+
+
+
+
+
+
+
What is printed by the following statements?
+
+
+total = 0
+mydict = {"cat":12, "dog":6, "elephant":23, "bear":20}
+for akey in mydict:
+ if len(akey) > 3:
+ total = total + mydict[akey]
+print(total)
+
+
+
+
+
+
+
18
+
+
+ Add the values that have keys greater than 3, not equal to 3.
+
+
+
+
+
43
+
+
+ Yes, the for statement iterates over the keys. It adds the values of the keys that have length greater than 3.
+
+
+
+
+
0
+
+
+ This is the accumulator pattern. total starts at 0 but then changes as the iteration proceeds.
+
+
+
+
+
61
+
+
+ Not all the values are added together. The if statement only chooses some of them.
+
+
+
+
+
diff --git a/pretext/AdditionalTopics/Dictionaryoperations.ptx b/pretext/AdditionalTopics/Dictionaryoperations.ptx
new file mode 100644
index 000000000..c0c5ca2db
--- /dev/null
+++ b/pretext/AdditionalTopics/Dictionaryoperations.ptx
@@ -0,0 +1,88 @@
+
+
+ Dictionary Operations
+
The del statement removes a key-value pair from a dictionary. For example,
+ the following dictionary contains the names of various fruits and the number of
+ each fruit in stock. If someone buys all of the pears, we can remove the entry from the dictionary.
Dictionaries are also mutable. As we've seen before with lists, this means that the dictionary can
+ be modified by referencing an association on the left hand side of the assignment statement. In the previous
+ example, instead of deleting the entry for pears, we could have set the inventory to 0.
+
Notice that there are now 512 bananas—the dictionary has been modified. Note also that the len function also works on dictionaries. It returns the number
+ of key-value pairs:
+
+
+ 12 is associated with the key cat.
+
+
+
+
+
0
+
+
+ The key mouse will be associated with the sum of the two values.
+
+
+
+
+
18
+
+
+ Yes, add the value for cat and the value for dog (12 + 6) and create a new entry for mouse.
+
+
+
+
+
Error, there is no entry with mouse as the key.
+
+
+ Since the new key is introduced on the left hand side of the assignment statement, a new key-value pair is added to the dictionary.
+
+
+
+
+
diff --git a/pretext/AdditionalTopics/Exercises.ptx b/pretext/AdditionalTopics/Exercises.ptx
new file mode 100644
index 000000000..4806889e7
--- /dev/null
+++ b/pretext/AdditionalTopics/Exercises.ptx
@@ -0,0 +1,532 @@
+
+
+ Exercises
+
+
+
Write a program that allows the user to enter a string. It then prints a
+ table of the letters of the alphabet in alphabetical order which occur in
+ the string together with the number of times each letter occurs. Case should
+ be ignored. A sample run of the program might look this this:
+
Please enter a sentence: ThiS is String with Upper and lower case Letters.
+a 2
+c 1
+d 1
+e 5
+g 1
+h 2
+i 4
+l 2
+n 2
+o 1
+p 2
+r 4
+s 5
+t 5
+u 1
+w 2
+$
+
+
+
+
+
+
+
+
+
+x = input("Enter a sentence")
+
+x = x.lower() # convert to all lowercase
+
+alphabet = 'abcdefghijklmnopqrstuvwxyz'
+
+letter_count = {} # empty dictionary
+for char in x:
+ if char in alphabet: # ignore any punctuation, numbers, etc
+ if char in letter_count:
+ letter_count[char] = letter_count[char] + 1
+ else:
+ letter_count[char] = 1
+
+keys = letter_count.keys()
+for char in sorted(keys):
+ print(char, letter_count[char])
+
+
+
+
+
+
Give the Python interpreter's response to each of the following from a
+ continuous interpreter session:
Be sure you understand why you get each result. Then apply what you
+ have learned to fill in the body of the function below, and add code for
+ the tests indicated:
+
+
+def add_fruit(inventory, fruit, quantity=0):
+ pass
+
+# make these tests work...
+new_inventory = {}
+add_fruit(new_inventory, 'strawberries', 10)
+# test that 'strawberries' in new_inventory
+# test that new_inventory['strawberries'] is 10
+add_fruit(new_inventory, 'strawberries', 25)
+# test that new_inventory['strawberries'] is now 35)
+
+
+
+
+
Write a program called alice_words.py that creates a text file named
+ alice_words.txt containing an alphabetical listing of all the words, and the
+ number of times each occurs, in the text version of Alice's Adventures in Wonderland.
+ (You can obtain a free plain text version of the book, along with many others, from
+ http://www.gutenberg.org.) The first 10 lines of your output file should look
+ something like this
How many times does the word, alice, occur in the book? If you are writing this
+ in the activecode window simply print out the results rather than write them to a file.
+
+
+
+
+
+
+
+ f = open('alice.txt', 'r')
+
+count = {}
+
+for line in f:
+ for word in line.split():
+
+ # remove punctuation
+ word = word.replace('_', '').replace('"', '').replace(',', '').replace('.', '')
+ word = word.replace('-', '').replace('?', '').replace('!', '').replace("'", "")
+ word = word.replace('(', '').replace(')', '').replace(':', '').replace('[', '')
+ word = word.replace(']', '').replace(';', '')
+
+ # ignore case
+ word = word.lower()
+
+ # ignore numbers
+ if word.isalpha():
+ if word in count:
+ count[word] = count[word] + 1
+ else:
+ count[word] = 1
+
+keys = count.keys()
+keys.sort()
+
+# save the word count analysis to a file
+out = open('alice_words.txt', 'w')
+
+for word in keys:
+ out.write(word + " " + str(count[word]))
+ out.write('\n')
+
+print("The word 'alice' appears " + str(count['alice']) + " times in the book.")
+
+
+f = open('alice.txt', 'r')
+
+count = {}
+
+for line in f:
+ for word in line.split():
+
+ # remove punctuation
+ word = word.replace('_', '').replace('"', '').replace(',', '').replace('.', '')
+ word = word.replace('-', '').replace('?', '').replace('!', '').replace("'", "")
+ word = word.replace('(', '').replace(')', '').replace(':', '').replace('[', '')
+ word = word.replace(']', '').replace(';', '')
+
+ # ignore case
+ word = word.lower()
+
+ # ignore numbers
+ if word.isalpha():
+ if word in count:
+ count[word] = count[word] + 1
+ else:
+ count[word] = 1
+
+keys = count.keys()
+keys.sort()
+
+# save the word count analysis to a file
+out = open('alice_words.txt', 'w')
+
+for word in keys:
+ out.write(word + " " + str(count[word]))
+ out.write('\n')
+
+print("The word 'alice' appears " + str(count['alice']) + " times in the book.")
+
+
+
+
+
+
What is the longest word in Alice in Wonderland? How many characters does it have?
Write a function named translator that takes a parameter containing a sentence in English
+ (no punctuation and all words in lowercase) and returns that sentence translated to Pirate.
+
For example, the sentence hello there students should be translated to avast there swabbies.
+
+
+
+def translator(english):
+
+ pirate = {}
+ pirate['sir'] = 'matey'
+ pirate['hotel'] = 'fleabag inn'
+ pirate['student'] = 'swabbie'
+ pirate['boy'] = 'matey'
+ pirate['restaurant'] = 'galley'
+ pirate['hello'] = 'avast'
+ pirate['students'] = 'swabbies'
+
+ # Complete the function
+
+====
+from unittest.gui import TestCaseGui
+
+class myTests(TestCaseGui):
+
+ def testOne(self):
+ self.assertEqual(translator("hello there students"),'avast there swabbies','translator("hello there students") yields "avast there swabbies"')
+ self.assertEqual(translator("the boy stayed in the hotel"),'the matey stayed in the fleabag inn','translator("the boy stayed in the hotel") yields "the matey stayed in the fleabag inn"')
+
+myTests().main()
+
+
+
+
+
+def translator(sentence):
+
+ pirate = {}
+ pirate['sir'] = 'matey'
+ pirate['hotel'] = 'fleabag inn'
+ pirate['student'] = 'swabbie'
+ pirate['boy'] = 'matey'
+ pirate['restaurant'] = 'galley'
+ pirate['hello'] = 'avast'
+ pirate['students'] = 'swabbies'
+
+ psentence = []
+ words = sentence.split()
+ for aword in words:
+ if aword in pirate:
+ psentence.append(pirate[aword])
+ else:
+ psentence.append(aword)
+
+ return " ".join(psentence)
+
+
+
+
+
diff --git a/pretext/AdditionalTopics/Glossary.ptx b/pretext/AdditionalTopics/Glossary.ptx
new file mode 100644
index 000000000..a0e7daa8a
--- /dev/null
+++ b/pretext/AdditionalTopics/Glossary.ptx
@@ -0,0 +1,50 @@
+
+
+ Glossary
+
+
+ Binary search
+
A searching algorithm where you look through a sorted list in halves; an improvement upon linear search.
+
+
+ Big O Notation
+
A notation computer scientists use to describe the relationship between the size
+ of the input data and the behavior of the program, denoted with O() and some factor inside of the parenthesis.
+
+
+ constant time
+
A Big O time complexity of O(1).
+
+
+ comprehension
+
A specific Python construction that allows collection types to be created and filled with a single line of code.
+
+
+ dictionary
+
A collection of key-value pairs that maps from keys to values. The keys
+ can be any immutable type, and the values can be any type.
+
+
+ key
+
A data item that is mapped to a value in a dictionary. Keys are used
+ to look up values in a dictionary.
+
+
+ key-value pair
+
One of the pairs of items in a dictionary. Values are looked up in a
+ dictionary by key.
+
+
+ Linear search
+
A searching algorithm where you look through in a linear order (directly from start to end).
+
+
+ mapping type
+
A mapping type is a data type comprised of a collection of keys and
+ associated values. Python's only built-in mapping type is the
+ dictionary. Dictionaries implement the
+ associative array
+ abstract data type.
+
+
+
diff --git a/pretext/Lists/ListComprehensions.ptx b/pretext/AdditionalTopics/ListComprehensions.ptx
similarity index 66%
rename from pretext/Lists/ListComprehensions.ptx
rename to pretext/AdditionalTopics/ListComprehensions.ptx
index f2ac50d45..b5a4eaf74 100644
--- a/pretext/Lists/ListComprehensions.ptx
+++ b/pretext/AdditionalTopics/ListComprehensions.ptx
@@ -1,10 +1,16 @@
-
+List Comprehensions
-
The previous example creates a list from a sequence of values based on some selection criteria. An easy way to do this type of processing in Python is to use a list comprehension. List comprehensions are concise ways to create lists. The general syntax is:
-
[<expression> for <item> in <sequence> if <condition>]
+
Generating or modifying a list of values based on some consistent rule is a very common operation done in Python. Take, for example,
+ generating a list of values according to a math function, or performing the same string operation on a list of words. This is common
+ enough that Python has built-in syntax to construct these smaller, collection-producing loops succinctly. These are known as comprehensions,
+ and can be done with several different collection types.
+
+
A comprehension that generates a list is, naturally, known as a list comprehension.
+ List comprehensions are concise ways to create lists. The general syntax is:
+
[<expression> for <item> in <sequence> if <condition>]
The expression describes each element of the list that is being built. The for clause iterates through each item in a sequence. The items are filtered by the if clause if there is one. In the example above, the for statement lets item take on all the values in the list mylist. Each item is then squared before it is added to the list that is being built. The result is a list of squares of the values in mylist.
-
To write the primes_upto function we will use the is_prime function to filter the sequence of integers coming from the range function. In other words, for every integer from 2 up to but not including n, if the integer is prime, keep it in the list.
+
To write a primes_upto function we can use the previously-made is_prime function to filter the sequence of integers coming from a range function. In other words, for every integer from 2 up to but not including n, if the integer is prime, keep it in the list.
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
-
+
@@ -36,7 +42,7 @@ def primes_upto(n):
Check your understanding
-
+
What is printed by the following statements?
diff --git a/pretext/AdditionalTopics/More-BigO.ptx b/pretext/AdditionalTopics/More-BigO.ptx
new file mode 100644
index 000000000..e8b108fb7
--- /dev/null
+++ b/pretext/AdditionalTopics/More-BigO.ptx
@@ -0,0 +1,161 @@
+
+
+ Big O Simplification and Practice
+
+
One more important topic in Big O Analysis is simplification. We won't get too deep into the math, but here are a few general rules:
+
+
Constant time operations always simplify to O(1). For instance, O(3) and O(1000000) both simplify to O(1).
+
+
Added constants are ignored when a larger factor is around. For instance, O(n + 1) is just O(n).
+
+
Multiplication by a constant factor simplifies to the factor, such as O(3n) becoming O(n).
+
+
Added polynomials are ignored when a larger factor is around. For instance, O(n! + n) is just O(n!), or O(n^2 + n) is just O(n^2).
+
+
With nested loops, any inner loop factors are multiplied by the outer loop factor.
+
+
+
+
Example 1: Find the time complexity of this program. Be careful of the nested loop.
+
+
+ def example_func(n):
+ for i in range(n):
+ for j in range(n):
+ print(i * j)
+
+
+
+
+
+
+
O(1)
+
+
+ Incorrect; we have two nested loops here.
+
+
+
+
+
O(logn)
+
+
+ Not quite. You typically see O(logn) more often in search/sort algorithms.
+
+
+
+
+
O(n)
+
+
+ Incorrect; both loops (one of which is nested) depend on n.
+
+
+
+
+
O(n^2)
+
+
+ Correct! Both loops depend on n, and one loop is nested, which multiplies it by the parent factor.
+
+
+
+
+
+
+
+
Example 2: Find the time complexity of this program.
+
+
+def example_func(n):
+ for i in range(n):
+ for j in range(10000):
+ print(j)
+
+
+
+
+
+
+
O(1)
+
+
+ Not quite; we one loop going to n and one loop going to a constant time.
+
+
+
+
+
O(logn)
+
+
+ Not quite. You typically see O(logn) more often in search/sort algorithms.
+
+
+
+
+
+
+
+ Not quite, since n is an arbitrary user inputted value.
+
+
+
+
+
O(logn)
+
+
+ Not quite. You typically see O(logn) more often in search/sort algorithms.
+
+
+
+
+
O(n)
+
+
+ Correct! We're going to n in this loop.
+
+
+
+
+
O(n^2)
+
+
+ Incorrect. We only have one loop going to n.
+
+
+
+
+
diff --git a/pretext/AdditionalTopics/SearchSortAlgorithms.ptx b/pretext/AdditionalTopics/SearchSortAlgorithms.ptx
new file mode 100644
index 000000000..6b1f8f10b
--- /dev/null
+++ b/pretext/AdditionalTopics/SearchSortAlgorithms.ptx
@@ -0,0 +1,50 @@
+
+
+ Search and Sort Algorithms
+
+
A major part of computer science is studying algorithms. There are two types of algorithms
+ that are spoken about very often: search and sort. Not only are they great
+ for learning about Big O and algorithms, but they're very applicable in the real world.
+
+
As the internet grows and the data we store grows, companies have to wrestle with the large amounts of data
+ they have. Imagine if you're Google and you're looking for one user out of one billion.
+ Now imagine you need to do that a thousand times a minute, with people doing it at the same time.
+ The code you write and the algorithms you use become massively important to how quickly
+ these operations can be done.
+
+
Linear search is the most basic searching algorithm, and the most intuitive.
+ Quite simply, you look through whatever you're considering in a linear order; from first to last.
+ This could be a stack of papers, or it could be a list in Python.
+
+
+
+# a program which finds 10 in my list, linearly
+my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+for element in my_list:
+ if element == 10:
+ print('found 10!')
+ break
+
+
+
+
Linear search has a best case complexity of O(1), average case of O(n), and worst case of O(n).
+ In the best case, the element we're looking for is the first element. But in the
+ average and worst cases, we will have to look through some n elements.
+
+
Binary search is an improvement upon linear search. Binary search splits the searched list in half and looks at the middle value.
+ If the number we're searching for is less than that value, we know it must be in the left half of the list;
+ if it's greater, we know it must be in the right half of the list, and we can repeat this process on smaller portions of the list until we find the number.
+
+
Binary search has a best case complexity of O(1), average case of O(logn), and worst case of O(logn).
+
+
However, there's a catch: for binary search to work, the list must be sorted! This is where sorting algorithms can come in. Sorting will not be covered in
+ this class, but we will describe one sorting algorithm for those that are curious.
+
+
Selection sort is a simple sorting algorithm. The idea is that we take the smallest element and swap it with the leftmost element,
+ and then the leftmost element becomes the sorted list. We repeat this process, and the sorted portion of the list grows in size each time, so we're only
+ adding elements from the nonsorted portion of the list to the end of the sorted part of the list.
+
+
The time complexity of selection sort is O(n^2) in every case.
+
+
Some other common sorting algorithms include Bubble Sort and Insertion Sort, but we will leave those for another class.
All of the compound data types we have studied in detail so far — strings,
+ lists, and tuples — are sequential collections. This means that the items in the collection are
+ ordered from left to right and they use integers as indices to access
+ the values they contain.
+
+ Dictionaries are a different kind of collection. They are Python's
+ built-in mapping type. A map is an unordered, associative collection. The association, or mapping,
+ is from a key, which can be any immutable type,
+ to a value, which can be any Python data object.
+
As an example, we will create a dictionary to translate English words into
+ Spanish. For this dictionary, the keys are strings and the values will also be strings.
+
One way to create a dictionary is to start with the empty dictionary and add
+ key-value pairs. The empty dictionary is denoted {}
+
The first assignment creates an empty dictionary named eng2sp. The other
+ assignments add new key-value pairs to the dictionary. The left hand side gives the dictionary and the key being associated. The right hand side gives the value being associated with that key.
+ We can print the current
+ value of the dictionary in the usual way.
+ The key-value pairs of the dictionary are separated by commas. Each pair
+ contains a key and a value separated by a colon.
+
The order of the pairs may not be what you expected. Python uses complex
+ algorithms, designed for very fast access, to determine where the
+ key-value pairs are stored in a dictionary.
+ For our purposes we can think of this ordering as unpredictable.
+
Another way to create a dictionary is to provide a list of key-value pairs
+ using the same syntax as the previous output.
It doesn't matter what order we write the pairs. The values in a dictionary are
+ accessed with keys, not with indices, so there is no need to care about
+ ordering.
+
Here is how we use a key to look up the corresponding value.
+
+
+ 12 is associated with the key cat.
+
+
+
+
+
6
+
+
+ Yes, 6 is associated with the key dog.
+
+
+
+
+
23
+
+
+ 23 is associated with the key elephant.
+
+
+
+
+
Error, you cannot use the index operator with a dictionary.
+
+
+ The [ ] operator, when used with a dictionary, will look up a value based on its key.
+
+
+
+
+
diff --git a/pretext/AdditionalTopics/pygame/Introduction.ptx b/pretext/AdditionalTopics/pygame/Introduction.ptx
new file mode 100644
index 000000000..ebb158449
--- /dev/null
+++ b/pretext/AdditionalTopics/pygame/Introduction.ptx
@@ -0,0 +1,105 @@
+
+
+ Pygame Introduction
+
+
Another aspect of python that is not specifically covered in this course is Pygame. This section will cover an introduction and key features of pygame so that you could get started programming your own game.
+ Pygame is a free open-source library for programming games using Python. Pygame is considered a simple library in the world of game development, its capabilities include: graphics and animation, user input handling,
+ collision detection, event handling, and sprite management.
+
+
+
To first use pygame you must install it on your computer. For both Mac and Windows, open vscode and a new terminal (Terminal -> New Terminal). In the terminal type : pip install pygame. If you already have pygame installed
+ on your computer make sure that it is up to date with the latest version. Once pygame is installed and updated you are ready to get started!
+
+
Key Aspects of Game Development:
+
Game loop: The game loop is a continuous cycle that begins when game play starts and ends based upon certain events happening. The game loop listens for user input such as: a mouse click, key events, the window closing, etc.
+ based upon these inputs the loop will update the game. This creates the illusion of the user interacting with the game. For example, programming that once a user lost a certain amount of points the game would end, the game
+ loop would continuously check the amount of points the user had and once it reached a certain threshold the game would quit.
+
+
Event handling: In game development event handling is a way to control responses to an event. When an event occurs such as user input or a collision, the event is directed to an event handler. This is a block of code that runs in
+ response to the event. For example, if the user collides with an obstacle the game will end.
+
+
Sprites: Sprites are two dimensional animations or objects that often represent characters within the game. In pygame, sprites are typically created as classes and different sprite objects are created from that class.
+ This could be as the user, as an enemy(ies) etc.
+
+
Collisions: Collisions are an often used concept in game development, many basic games such as car racing, pong, etc. Collision detection is also a type of event handling, where when two objects share the same coordinates
+ the collision event occurs.
+
+
Game speed: Game speed is an aspect of the game that controls how quickly the game is played. For example, if you are playing an obstacle course, how quickly or not the objects appear is considered the game speed.
+ Typically this is a variable that can be adjusted by the players depending on the difficulty that they choose to play the game at.
+
+
+
When beginning writing any pygame file the first two lines should always be: import pygame and pygame.init().
+ These two commands import and initialize the pygame module so that you may use it in your code. You will then want
+ to create and name the window that your game will appear in outside of your coding environment. To do this:
+
+
+window = pygame.display.set_mode((500,500)) #this will create and set the size of your window
+pygame.display.set_caption("Name") #this will set the name of your window
+exit = False
+while !exit: #game loop
+ for event in pygame.event.get() #listens for events
+ if event.type == pygame.QUIT:
+ exit = True
+ pygame.display.update()
+
+
+
When the above code is run. it should create a blank black window on your computer. All further creative ideas can extend from this central code.
Pygame can only have a single display active at a time, if set_mode() is called while another window is open, the previous window will be closed.
+Using pygame.display.quit() will also shut down the window.
+
pygame.draw.rect- draws a rectangle
+
pygame.draw.polygon- draws a polygon
+
pygame.draw.circle- draws a circle
+
pygame.draw.ellipse- draws an ellipse
+
pygame.draw.arc- draws an elliptical arc
+
pygame.draw.line- draws a straight line
+
pygame.draw.lines- draws multiple contiguous straight line segments
+
+
Events in Pygame:
+
pygame.event.get()-gets events from the queue
+
pygame.event.wait()- waits for single event from the queue
+
pygame.event.clear()- removes all events from the queue
+
To get the state of various input devices, you can forego the event queue and access the input
+devices directly with their appropriate modules. For example: pyagme.mouse, pygame.key, pygame.joystick, etc.
+If this method is used, pygame requires some from of communication with the system window manager and other parts
+of the platform. To keep pygame in sync with the system you will need to call: pygame.event.pump(), to keep everything current.
+Usually, this should be called once per game loop.
+
+
The event queue itself contains event objects that can be accessed from the queue by checking for existence or grabbing them
+directly off of the stack.
+
+
Mouse Event in Pygame:
+
pygame.mouse.get_pressed()- get the state of the mouse buttons
+
pygame.mouse.get_pos()- get the mouse cursor position
+
pygame.mouse.set_pos()- set the mouse cursor position
+
pygame.mouse.set_visible()- hide or show the mouse cursor
+
pygame.mouse.get_visible()- check if the display is receiving mouse input
+
+
When the display mode is set, the queue will start receiving mouse evets. The mouse buttons themselves will generate: pygameMOUSEBUTTONDOWN/UP events.
+Similarly, a pygame.MOUSEMOTION event whenever the mouse is moved. All of these events can be directed to an event handler within the game loop.
+
+
Time in Pygame:
+
pygame.time.get_ticks()- gets the time in milliseconds
+
pygame.time.wait()- pauses the program for a specified amount of time
+
pygame.time.delay()- same^
+
pygame.time.set_timer()- repeatedly create an event on the event queue
+
pygame.time.Clock- creates an object to track the time.
+
Use of time in pygame can add an additional layer of complexity to your game. Whether that is making sure that the user completes a game level within a certain
+amount of time, or times the user and records the best time.
+
+
Here is an example of code that moves a box around the screen using the arrow keys.
+
+
+
+
+
+
+
+
diff --git a/pretext/AdditionalTopics/pygame/image.png b/pretext/AdditionalTopics/pygame/image.png
new file mode 100644
index 000000000..5b67d93fa
Binary files /dev/null and b/pretext/AdditionalTopics/pygame/image.png differ
diff --git a/pretext/AdditionalTopics/toctree.ptx b/pretext/AdditionalTopics/toctree.ptx
new file mode 100644
index 000000000..5f1a746a0
--- /dev/null
+++ b/pretext/AdditionalTopics/toctree.ptx
@@ -0,0 +1,18 @@
+
+
+4Additional Topics
+4
+4
+4
+4
+4
+4
+4
+4
+4
+4
+4
+4
+4
+4
+
diff --git a/pretext/AdditionalTopics/video-more-python.ptx b/pretext/AdditionalTopics/video-more-python.ptx
new file mode 100644
index 000000000..485b0ef9f
--- /dev/null
+++ b/pretext/AdditionalTopics/video-more-python.ptx
@@ -0,0 +1,7 @@
+
+
+ Practice Video Lecture
+
Week 15 Video Lecture:
+
+
+
diff --git a/pretext/ClassesBasics/Achangeofperspective.ptx b/pretext/ClassesBasics/Achangeofperspective.ptx
index 71c3bec0d..d928a8e9e 100644
--- a/pretext/ClassesBasics/Achangeofperspective.ptx
+++ b/pretext/ClassesBasics/Achangeofperspective.ptx
@@ -1,17 +1,11 @@
A change of perspective
-
Throughout the earlier chapters, we wrote functions and called them using a syntax such as drawCircle(tess). This suggests that the
- function is the active agent. It says something like, Hey, drawCircle!
- Here's a turtle object for you to use to draw with.
-
In object-oriented programming, the objects are considered the active agents.
- For example, in our early introduction to turtles, we used
- an object-oriented style. We said tess.forward(100), which
- asks the turtle to move itself forward by the given number of steps.
- An
- invocation like tess.circle() says Hey tess!
- Please use your circle method!
-
This change in perspective is sometimes considered to be a more polite way to write programming instructions. However, it may not initially
+
Throughout the earlier chapters, we wrote functions and called them using a syntax such as printRange(lst). This suggests that the
+ function is the active agent. It says something like, "Hey, printRange!
+ Here's a list for you to use to print with."
+
In object-oriented programming, the objects are considered the active agents. This change in perspective is sometimes considered to be a more "polite" way
+ to write programming instructions. However, it may not initially
be obvious that it is useful. It turns out that often times shifting responsibility from
the functions onto the objects makes it possible to write more versatile
functions and makes it easier to maintain and reuse code.
diff --git a/pretext/ClassesBasics/AddingOtherMethodstoourClass.ptx b/pretext/ClassesBasics/AddingOtherMethodstoourClass.ptx
index 8365cd680..c4d897295 100644
--- a/pretext/ClassesBasics/AddingOtherMethodstoourClass.ptx
+++ b/pretext/ClassesBasics/AddingOtherMethodstoourClass.ptx
@@ -10,11 +10,11 @@
We can group together the sensible operations, and the kinds of data
they apply to, and each instance of the class can have its own state.
A method behaves like a function but it is invoked on a specific
- instance. For example, with a turtle named tess, tess.right(90) asks the tess object to perform its
- right method and turn 90 degrees. Methods are accessed using dot notation.
+ instance. For example, with a list named lst, lst.append(90) asks the lst object to perform its
+ append method and add the integer 90 to the end of the list. Methods are accessed using dot notation.
Let's add two simple methods to allow a point to give us information about its state. The getX method, when invoked, will return the value of the x coordinate. The implementation of this method is straight forward since we already know how
to write functions that return values. One thing to notice is that even though the getX method does not need any other parameter information to do its work, there is still one formal parameter, self. As we stated earlier, all methods defined in a class that operate on objects of that class will have self as their first parameter. Again, this serves as reference to the object itself which in turn gives access to the state data inside the object.
-
+
class Point:
""" Point class for representing and manipulating x,y coordinates. """
@@ -40,7 +40,7 @@ print(p.getY())
Let's add another method, distanceFromOrigin, to see better how methods
work. This method will again not need any additional information to do its work.
It will perform a more complex task.
-
+
class Point:
""" Point class for representing and manipulating x,y coordinates. """
diff --git a/pretext/ClassesBasics/ConvertinganObjecttoaString.ptx b/pretext/ClassesBasics/ConvertinganObjecttoaString.ptx
index d46f2cc7a..c213d5d0d 100644
--- a/pretext/ClassesBasics/ConvertinganObjecttoaString.ptx
+++ b/pretext/ClassesBasics/ConvertinganObjecttoaString.ptx
@@ -3,7 +3,7 @@
Converting an Object to a String
When we're working with classes and objects, it is often necessary to print an object (that is to print the state of an object).
Consider the example below.
-
+
class Point:
""" Point class for representing and manipulating x,y coordinates. """
@@ -35,7 +35,7 @@ print(p)
The __str__ method is responsible for returning a string representation as defined by the class creator. In other words, you as the programmer, get to choose what a Point should look like when it gets printed. In this case, we
have decided that the string representation will include the values of x and y as well as some identifying text. It
is required that the __str__ method create and return a string.
-
+
class Point:
""" Point class for representing and manipulating x,y coordinates. """
diff --git a/pretext/ClassesBasics/ImprovingourConstructor.ptx b/pretext/ClassesBasics/ImprovingourConstructor.ptx
index e4fc90bde..a85f45fb7 100644
--- a/pretext/ClassesBasics/ImprovingourConstructor.ptx
+++ b/pretext/ClassesBasics/ImprovingourConstructor.ptx
@@ -5,7 +5,7 @@
provide some additional capability for the user to pass information to the constructor. Since constructors are simply specially named functions, we can use parameters (as we've seen before) to provide the specific information.
We can make our class constructor more general by putting extra parameters into
the __init__ method, as shown in this codelens example.
-
+
class Point:
""" Point class for representing and manipulating x,y coordinates. """
diff --git a/pretext/ClassesBasics/InstancesasReturnValues.ptx b/pretext/ClassesBasics/InstancesasReturnValues.ptx
index c246aeadf..71ca70edf 100644
--- a/pretext/ClassesBasics/InstancesasReturnValues.ptx
+++ b/pretext/ClassesBasics/InstancesasReturnValues.ptx
@@ -8,7 +8,7 @@
and wish to find the midpoint halfway between it and some other target point. We would like to write a method, call
it halfway that takes another Point as a parameter and returns the Point that is halfway between the point and
the target.
-
+
class Point:
@@ -50,7 +50,7 @@ print(mid.getY())
We can always see whether the coordinates of Point self or target are being referred to.
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
In Python, every value is actually an object. Whether it be a turtle, a list, or even an integer, they are all objects. Programs manipulate those objects either by performing
- computation with them or by asking them to perform methods. To be more specific, we say that an object has
- a state and a collection of methods that it can perform. The state of an object represents those things
- that the object knows about itself. For example, as we have seen with turtle objects, each turtle has a state consisting
- of the turtle's position, its color, its heading and so on. Each turtle also has the ability to go forward, backward, or turn right or left. Individual turtles are different in that even though they are
- all turtles, they differ in the specific values of the individual state attributes (maybe they are in a different location or have a different heading).
-
+
In Python, every value is actually an object. Whether it be a string, a list, or even an integer, they are all objects. Programs manipulate those objects either by performing
+ computation with them or by asking them to perform methods. To be more specific, we say that an object has
+ a state and a collection of methods that it can perform. The state of an object represents those things
+ that the object knows about itself. For example, each list has a state consisting
+ of the items it contains, a length and so on. Each list also has the ability to add, delete, and sort the items inside of it. Individual lists are different in
+ that even though they are all lists, they differ in the specific values of the individual state attributes (maybe they have different items inside them).
+
diff --git a/pretext/ClassesBasics/ObjectsasArgumentsandParameters.ptx b/pretext/ClassesBasics/ObjectsasArgumentsandParameters.ptx
index 93a00188f..7be61958f 100644
--- a/pretext/ClassesBasics/ObjectsasArgumentsandParameters.ptx
+++ b/pretext/ClassesBasics/ObjectsasArgumentsandParameters.ptx
@@ -1,13 +1,9 @@
Objects as Arguments and Parameters
-
You can pass an object as an argument in the usual way. We've already seen
- this in some of the turtle examples where we passed the turtle to
- some function like drawRectangle so that the function could
- control and use whatever turtle instance we passed to it.
-
Here is a simple function called distance involving our new Point objects. The job of this function is to figure out the
- distance between two points.
-
+
You can pass an object as an argument in the usual way. Here is a simple function called distance involving our new Point objects.
+ The job of this function is to figure out the distance between two points.
+
import math
diff --git a/pretext/ClassesBasics/UserDefinedClasses.ptx b/pretext/ClassesBasics/UserDefinedClasses.ptx
index 7a7a52a72..cabf4271a 100644
--- a/pretext/ClassesBasics/UserDefinedClasses.ptx
+++ b/pretext/ClassesBasics/UserDefinedClasses.ptx
@@ -1,7 +1,7 @@
User Defined Classes
-
We've already seen classes like str, int, float and Turtle. These were defined by Python and
+
We've already seen classes like str, int, and float. These were defined by Python and
made available for us to use. However, in many cases when we are solving problems we need to create data objects
that are related to the problem we are trying to solve. We need to create our own classes.
As an example, consider the concept of a mathematical point. In two dimensions, a point is two
@@ -49,7 +49,7 @@ class Point:
other name, but nobody ever does!) is automatically set to reference
the newly-created object that needs to be initialized.
So let's use our new Point class now.
-
+
class Point:
""" Point class for representing and manipulating x,y coordinates. """
@@ -68,7 +68,7 @@ print("Nothing seems to have happened with the points")
During the initialization of the objects, we created two
attributes called x and y for each, and gave them both the value 0.
-
The asignments are not to x and y, but to self.x and self.y.
+
The assignments are not to x and y, but to self.x and self.y.
The attributes x and y are always attached to a particular instance.
The instance is always explicitly referenced with dot notation.
@@ -77,7 +77,7 @@ print("Nothing seems to have happened with the points")
having an x and y coordinate with value 0. However, because we have not asked the point to do anything, we don't see any other result.
You can see this for yourself, via codelens:
-
+
class Point:
""" Point class for representing and manipulating x,y coordinates. """
@@ -95,7 +95,7 @@ print("Nothing seems to have happened with the points")
The following program adds a few print statements. You can see that the output suggests that each one is a Point object.
However, notice that the is operator returns False meaning that they are different objects (we will have more to say about this in a later chapter).
-
+
class Point:
""" Point class for representing and manipulating x,y coordinates. """
@@ -114,7 +114,7 @@ print(q)
print(p is q)
-
This should look familiar — we've used classes before to create
+
The variables p and q are assigned references to two new Point objects.
A function like Turtle or Point that creates a new object instance
is called a constructor. Every class automatically uses the name of the class as the name of the constructor function.
@@ -141,7 +141,7 @@ alex = Turtle()
Check Your Understanding
-
+
What is the the output of the following print code?
To design our class, we simply need to use the analysis above to realize that the state of a fraction object can be
completely described by representing two integers. We can begin by implementing the Fraction class and the __init__
method which will allow the user to provide a numerator and a denominator for the fraction being created.
-
+
class Fraction:
diff --git a/pretext/ClassesDiggingDeeper/ObjectsareMutable.ptx b/pretext/ClassesDiggingDeeper/ObjectsareMutable.ptx
index 21fd86124..7b170476b 100644
--- a/pretext/ClassesDiggingDeeper/ObjectsareMutable.ptx
+++ b/pretext/ClassesDiggingDeeper/ObjectsareMutable.ptx
@@ -12,7 +12,7 @@
representation would be 3/4.
There is a very nice iterative method for computing the greatest common divisor of two integers. Try to run the
function on a number of different examples.
-
+
def gcd(m, n):
while m % n != 0:
@@ -31,7 +31,7 @@ print(gcd(12, 16))
a fraction method called simplify. We will ask the fraction to put itself in lowest terms.
The simplify method will pass the numerator and the denominator to the gcd function to find the
greatest common divisor. It will then modify itself by dividing its num and its den by that value.
-
+
def gcd(m, n):
while m % n != 0:
diff --git a/pretext/ClassesDiggingDeeper/Sameness.ptx b/pretext/ClassesDiggingDeeper/Sameness.ptx
index a6768f6d8..1dd7ac238 100644
--- a/pretext/ClassesDiggingDeeper/Sameness.ptx
+++ b/pretext/ClassesDiggingDeeper/Sameness.ptx
@@ -13,7 +13,7 @@
We've already seen the is operator in the chapter on lists, where we
talked about aliases.
It allows us to find out if two references refer to the same object.
+
+
+
diff --git a/pretext/Strings/Afindfunction.ptx b/pretext/ComplexLogic/Afindfunction.ptx
similarity index 95%
rename from pretext/Strings/Afindfunction.ptx
rename to pretext/ComplexLogic/Afindfunction.ptx
index c531bb891..723b13c40 100644
--- a/pretext/Strings/Afindfunction.ptx
+++ b/pretext/ComplexLogic/Afindfunction.ptx
@@ -1,8 +1,8 @@
-
+A find function
Here is an implementation for a restricted find method, where the target is a single character.
-
+
def find(astring, achar):
"""
diff --git a/pretext/Lists/Aliasing.ptx b/pretext/ComplexLogic/Aliasing.ptx
similarity index 98%
rename from pretext/Lists/Aliasing.ptx
rename to pretext/ComplexLogic/Aliasing.ptx
index 415797a7e..e450d82b0 100644
--- a/pretext/Lists/Aliasing.ptx
+++ b/pretext/ComplexLogic/Aliasing.ptx
@@ -16,7 +16,7 @@ print(a is b)
is aliased. Changes made with one alias affect the other. In the codelens example below, you can see that a and b refer
to the same list after executing the assignment statement b = a.
-
+
a = [81, 82, 83]
b = [81, 82, 83]
diff --git a/pretext/Lists/FunctionsthatProduceLists.ptx b/pretext/ComplexLogic/FunctionsthatProduceLists.ptx
similarity index 100%
rename from pretext/Lists/FunctionsthatProduceLists.ptx
rename to pretext/ComplexLogic/FunctionsthatProduceLists.ptx
diff --git a/pretext/Strings/Loopingandcounting.ptx b/pretext/ComplexLogic/Loopingandcounting.ptx
similarity index 100%
rename from pretext/Strings/Loopingandcounting.ptx
rename to pretext/ComplexLogic/Loopingandcounting.ptx
diff --git a/pretext/ComplexLogic/NestedList_Navigation.ptx b/pretext/ComplexLogic/NestedList_Navigation.ptx
new file mode 100644
index 000000000..f0965f52b
--- /dev/null
+++ b/pretext/ComplexLogic/NestedList_Navigation.ptx
@@ -0,0 +1,107 @@
+
+
+ Nested List Traversal
+
Nested lists can be traversed the say way as other lists. However, the code to do so can easily get complicated and confusing. In this section let us
+ examine several example programs that perform this task.
+
+
The following program concerns a list of lists of names. In some cases, we may want to take nested list data and "un-nest" it. To do this, we need to
+ iterate through the outer list, and then construct another loop to iterate through each name in each sublist. In this program's case, we are simply printing each
+ name as we encounter it.
+
+
+names = [["Thomas", "Abraham", "George"], ["Theodore", "Grover", "William"], ["Franklin", "Dwight", "John", "Harry"], ["George", "Bill"]]
+for sublist in names:
+ for name in sublist:
+ print(name)
+
+
+
Nested lists can also be navigated by index rather than by value. This complicates the code somewhat, but gives us more flexibility for what can be done to each item.
+ In this example program, we visit each name and turn it lowercase.
Note that in the above program it is very important that we use len(names[sublist_index]) in the second range call. Because the nested lists in this example
+ do not have the same length, we have to check the length of each sublist when setting up our nested for loop bounds. If we do not do this carefully, then we can easily
+ miss data or get an out of bounds exception. Consider a different, erroneous example:
Nested lists can be used in many different contexts, but one more common use is to model 2D grids of data. Here is one last example that treats nested lists as a 2D coordinate plane
+ and finds the location of a single value in that plane. Note this example reverses the y axis, so y values increase as you travel downward. This is to match the indexing on the lists,
+ though we could model this as a more familiar coordinate system with some small changes.
+
+
+coord = [['_', '_', '_', '_'],
+ ['_', '_', 'p', '_'],
+ ['_', '_', '_', '_'],
+ ['_', '_', '_', '_']]
+for y in range(len(coord)):
+ for x in range(len(coord[y])):
+ if coord[y][x] == 'p':
+ print(f'p is as coordinates (x={x}, y={y})')
+
+
+
+ Check your understanding
+
+
+
+
What is printed by the following statements?
+
+
+alist = [ [4, [True, False], 6, 8], [888, 999] ]
+for a in alist:
+ for b in range(1, len(a)):
+ if type(a[b]) == type(a[b-1]):
+ print(a[b], end=" ")
+
+
+
+
+
+
+
8 999
+
+
+ Yes, you are correct.
+
+
+
+
+
4 6 8 888 999
+
+
+ You are correct that the code will treat the list with boolean value differently, but you are missing other aspects. Look again at the bounds of the inner loop.
+
+
+
+
+
4 True False 6 8 888 999
+
+
+ This would be the output for a full traversal of the data. However, this code cannot fully traverse the data since it has three levels of nesting and the code only reaches two levels.
+
+
+
+
+
4 [True, False] 6 8 888 999
+
+
+ This would be the correct output if the code traversed two levels of nesting and printed everything. However, the if statement is also doing something here.
+
+
+
+
+
diff --git a/pretext/Lists/NestedLists.ptx b/pretext/ComplexLogic/NestedLists.ptx
similarity index 91%
rename from pretext/Lists/NestedLists.ptx
rename to pretext/ComplexLogic/NestedLists.ptx
index 04ea9df74..0e5b5cf9e 100644
--- a/pretext/Lists/NestedLists.ptx
+++ b/pretext/ComplexLogic/NestedLists.ptx
@@ -1,5 +1,5 @@
-
+Nested Lists
A nested list is a list that appears as an element in another list. In this
list, the element with index 3 is a nested list.
@@ -7,7 +7,7 @@
nested list, we can proceed in two steps. First, extract the nested list, then extract the item
of interest. It is also possible to combine those steps using bracket operators that evaluate from
left to right.
diff --git a/pretext/Lists/ObjectsandReferences.ptx b/pretext/ComplexLogic/ObjectsandReferences.ptx
similarity index 91%
rename from pretext/Lists/ObjectsandReferences.ptx
rename to pretext/ComplexLogic/ObjectsandReferences.ptx
index bf8bd24d2..8582f42f1 100644
--- a/pretext/Lists/ObjectsandReferences.ptx
+++ b/pretext/ComplexLogic/ObjectsandReferences.ptx
@@ -1,5 +1,5 @@
-
+Objects and References
If we execute these assignment statements,
@@ -19,7 +19,7 @@ b = "banana"
refer to.
We already know that objects can be identified using their unique identifier. We can also test whether two names refer to the same object using the is
operator. The is operator will return true if the two references are to the same object. In other words, the references are the same. Try our example from above.
-
+
a = "banana"
b = "banana"
@@ -32,7 +32,7 @@ print(a is b)
Since strings are immutable, Python can optimize resources by making two names
that refer to the same string literal value refer to the same object.
This is not the case with lists. Consider the following example. Here, a and b refer to two different lists, each of which happens to have the same element values.
-
+
a = [81, 82, 83]
b = [81, 82, 83]
@@ -48,7 +48,7 @@ print(a == b)
a and b have the same value but do not refer to the same object.
There is one other important thing to notice about this reference diagram. The variable a is a reference to a collection of references. Those references actually refer to the integer values in the list. In other words, a list is a collection of references to objects. Interestingly, even though a and b are two different lists (two different collections of references), the integer object 81 is shared by both. Like strings, integers are also immutable so Python optimizes and lets everyone share the same object for some commonly used small integers.
Here is the example in codelens. Pay particular attention to the id values.
-
+
a = [81, 82, 83]
b = [81, 82, 83]
diff --git a/pretext/Strings/Optionalparameters.ptx b/pretext/ComplexLogic/Optionalparameters.ptx
similarity index 100%
rename from pretext/Strings/Optionalparameters.ptx
rename to pretext/ComplexLogic/Optionalparameters.ptx
diff --git a/pretext/Lists/PureFunctions.ptx b/pretext/ComplexLogic/PureFunctions.ptx
similarity index 86%
rename from pretext/Lists/PureFunctions.ptx
rename to pretext/ComplexLogic/PureFunctions.ptx
index 453bf9383..05c7c04c0 100644
--- a/pretext/Lists/PureFunctions.ptx
+++ b/pretext/ComplexLogic/PureFunctions.ptx
@@ -1,5 +1,5 @@
-
+Pure Functions
A pure function does not produce side effects. It communicates with the
calling program only through parameters (which it does not modify) and a return
@@ -7,7 +7,7 @@
To use the pure function version of double_stuff to modify things,
you would assign the return value back to things.
-
+
def doubleStuff(a_list):
""" Return a new list in which contains doubles of the elements in a_list. """
@@ -24,7 +24,7 @@ print(things)
Once again, codelens helps us to see the actual references and objects as they are passed and returned.
-
+
def doubleStuff(a_list):
""" Return a new list in which contains doubles of the elements in a_list. """
diff --git a/pretext/Lists/RepetitionandReferences.ptx b/pretext/ComplexLogic/RepetitionandReferences.ptx
similarity index 98%
rename from pretext/Lists/RepetitionandReferences.ptx
rename to pretext/ComplexLogic/RepetitionandReferences.ptx
index 7e5bdaf90..b99bba568 100644
--- a/pretext/Lists/RepetitionandReferences.ptx
+++ b/pretext/ComplexLogic/RepetitionandReferences.ptx
@@ -44,7 +44,7 @@ print(newlist)
Here is the same example in codelens. Step through the code paying particular attention to the result of executing the assignment statement origlist[1] = 99.
-
+
origlist = [45, 76, 34, 55]
diff --git a/pretext/Lists/TheAccumulatorPatternwithLists.ptx b/pretext/ComplexLogic/TheAccumulatorPatternwithLists.ptx
similarity index 90%
rename from pretext/Lists/TheAccumulatorPatternwithLists.ptx
rename to pretext/ComplexLogic/TheAccumulatorPatternwithLists.ptx
index 17462b8a3..f4dd36055 100644
--- a/pretext/Lists/TheAccumulatorPatternwithLists.ptx
+++ b/pretext/ComplexLogic/TheAccumulatorPatternwithLists.ptx
@@ -1,5 +1,5 @@
-
+The Accumulator Pattern with Lists
Remember the ? Many algorithms involving lists make use of
@@ -7,23 +7,23 @@
explore the use of the accumulator pattern with lists.
Let's take the problem of adding up all of the items in a list. The following program
computes the sum of a list of numbers.
-
+
-sum = 0
+total = 0
for num in [1, 3, 5, 7, 9]:
- sum = sum + num
-print(sum)
+ total = total + num
+print(total)
-
The program begins by defining an accumulator variable, sum, and initializing it to 0 (line 1).
+
The program begins by defining an accumulator variable, total, and initializing it to 0 (line 1).
Next, the program iterates over the list (lines 2-3), and updates the sum on each
- iteration by adding an item from the list (line 3). When the loop is finished, sum
+ iteration by adding an item from the list (line 3). When the loop is finished, total
has accumulated the sum of all of the items in the list.
Take a moment to step through this program using CodeLens to see how it works. It's important to
grasp the basic techniques.
Sometimes when we're accumulating, we don't want to add to our accumulator every time we iterate.
Consider, for example, the following program which counts the number of names with more than 3 letters.
-
+
long_names = 0
for name in ["Joe", "Sally", "Amy", "Brad"]:
@@ -39,7 +39,7 @@ print(long_names)
it.
At the end, we have accumulated the total number of long names.
We can use conditionals to also count if particular items are in a string or list. The following code finds all occurrences of vowels in a string.
-
+
s = "what if we went to the zoo"
num_vowels = 0
@@ -53,13 +53,13 @@ print(num_vowels)
an o. If it is an o then we will update our counter.
-
+ Accumulating the Max Value
We can also use the accumulation pattern with conditionals to find the maximum or minimum value. Instead of
continuing to build up the accumulator value like we have when counting or finding a sum, we can reassign the
accumulator variable to a different value.
The following example shows how we can get the maximum value from a list of integers.
-
+
nums = [9, 3, 8, 11, 5, 29, 2]
best_num = 0
@@ -77,7 +77,7 @@ print(best_num)
happen to our code? What if we were looking for the smallest number but we initialized best_num with
zero? To get around this issue, we can initialize the accumulator variable using one of the numbers in the
list.
-
+
nums = [9, 3, 8, 11, 5, 29, 2]
best_num = nums[0]
@@ -90,11 +90,11 @@ print(best_num)
The only thing we changed was the value of best_num on line 2 so that the value of best_num is the
first element in nums, but the result is still the same!
-
+ Accumulating a String Result
The accumulator pattern can be used to convert a list of items to a string.
Consider the following program:
-
+
scores = [85, 95, 70]
result = ''
@@ -110,13 +110,13 @@ print("The scores are " + result)
The output of the program has some undesirable formatting problems: there is a trailing comma instead
of a period, and there are no spaces between the items. The next activity lets you work to
correct those problems.
-
+
Let's work to improve the formatting of the sentence produced by the program above.
Revise the following code so that it outputs the sentence:
The scores are 85, 95, and 70.
-
+
scores = [85, 95, 70]
result = ''
@@ -145,7 +145,7 @@ myTests().main()
This solution works by iterating over all of the scores in the list
except the last, and dealing with that one separately.
-
+
scores = [85, 95, 70]
result = ''
for score in scores[:-1]:
@@ -166,7 +166,7 @@ print("The scores are " + result)
Check your understanding
-
+
What is printed by the following statements?
@@ -215,7 +215,7 @@ print(x)
-
+
What is printed by the following statements?
@@ -264,11 +264,11 @@ print(min_value)
-
+
diff --git a/pretext/Strings/TheAccumulatorPatternwithStrings.ptx b/pretext/ComplexLogic/TheAccumulatorPatternwithStrings.ptx
similarity index 92%
rename from pretext/Strings/TheAccumulatorPatternwithStrings.ptx
rename to pretext/ComplexLogic/TheAccumulatorPatternwithStrings.ptx
index 9ef9bc2ee..9212b4778 100644
--- a/pretext/Strings/TheAccumulatorPatternwithStrings.ptx
+++ b/pretext/ComplexLogic/TheAccumulatorPatternwithStrings.ptx
@@ -1,10 +1,10 @@
-
+The Accumulator Pattern with Strings
Combining the in operator with string concatenation using + and the accumulator pattern, we can
write a function that removes all the vowels from a string. The idea is to start with a string and iterate over each character, checking to see if the character is a vowel. As we process the characters, we will build up a new string consisting of only the nonvowel characters. To do this, we use the accumulator pattern.
Remember that the accumulator pattern allows us to keep a running total. With strings, we are not accumulating a numeric total. Instead we are accumulating characters onto a string.
-
+
def removeVowels(s):
vowels = "aeiouAEIOU"
@@ -36,7 +36,7 @@ if eachChar != 'a' and eachChar != 'e' and eachChar != 'i' and
Take a close look also at the initialization of sWithoutVowels. We start with an empty string and then begin adding
new characters to the end.
Step through the function using codelens to see the accumulator variable grow.
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
-
+
diff --git a/pretext/Lists/UsingListsasParameters.ptx b/pretext/ComplexLogic/UsingListsasParameters.ptx
similarity index 90%
rename from pretext/Lists/UsingListsasParameters.ptx
rename to pretext/ComplexLogic/UsingListsasParameters.ptx
index c774a2aa8..52b7b5853 100644
--- a/pretext/Lists/UsingListsasParameters.ptx
+++ b/pretext/ComplexLogic/UsingListsasParameters.ptx
@@ -1,5 +1,5 @@
-
+Using Lists as Parameters
Functions which take lists as arguments and change them during execution are
called modifiers and the changes they make are called side effects.
@@ -9,7 +9,7 @@
the same list that the argument is referencing.
For example, the function below takes a list as an
argument and multiplies each element in the list by 2:
-
+
def doubleStuff(aList):
""" Overwrite each element in aList with double its value. """
@@ -29,7 +29,7 @@ print(things)
If a function modifies the elements of a list parameter, the caller sees the change since the change
is occurring to the original.
This can be easily seen in codelens. Note that after the call to doubleStuff, the formal parameter aList refers to the same object as the actual parameter things. There is only one copy of the list object itself.
-
+
def doubleStuff(aList):
""" Overwrite each element in aList with double its value. """
diff --git a/pretext/Lists/WhichisBetter.ptx b/pretext/ComplexLogic/WhichisBetter.ptx
similarity index 100%
rename from pretext/Lists/WhichisBetter.ptx
rename to pretext/ComplexLogic/WhichisBetter.ptx
diff --git a/pretext/ComplexLogic/intro_ComplexLogic.ptx b/pretext/ComplexLogic/intro_ComplexLogic.ptx
new file mode 100644
index 000000000..31d30702c
--- /dev/null
+++ b/pretext/ComplexLogic/intro_ComplexLogic.ptx
@@ -0,0 +1,8 @@
+
+
+ Complex Logic Introduction
+
Believe it or not, in the past seven weeks we've covered nearly all of the fundamental constructs within programming.
+ While there is certainly much more to learn and discover, virtually any programming language you will see in the future offers some form
+ of branching, looping, and function definition. That is not to say we have mastered these topics yet. This week of class and this chapter
+ focuses on revisiting these fundamental topics and deepening our mastery of them.
+
diff --git a/pretext/ComplexLogic/toctree.ptx b/pretext/ComplexLogic/toctree.ptx
new file mode 100644
index 000000000..1f9b76ea8
--- /dev/null
+++ b/pretext/ComplexLogic/toctree.ptx
@@ -0,0 +1,13 @@
+
+
+4Complex Logic
+4
+4
+4
+4
+4
+4
+4
+4
+4
+
diff --git a/pretext/ComplexLogic/video-complex.ptx b/pretext/ComplexLogic/video-complex.ptx
new file mode 100644
index 000000000..6d785a21b
--- /dev/null
+++ b/pretext/ComplexLogic/video-complex.ptx
@@ -0,0 +1,7 @@
+
+
+ Practice Video Lecture
+
Ok, let's look at an example. Let's solve the problem posed in question 3 at the end of the Simple Python Data chapter. Ask the user for the time now (in hours 0 - 23), and ask for the number of hours to wait. Your program should output what the time will be on the clock when the alarm goes off. For example, if current_time is 8 and wait_time is 5, final_time should be 13 (1 pm).
So, where to start? The problem requires two pieces of input from the user, so let's start there and make sure we can get the data we need.
-
+
current_time = input("what is the current time (in hours)?")
wait_time = input("How many hours do you want to wait")
@@ -53,7 +53,7 @@ print(wait_time)
So far so good. Now let's take the next step. We need to figure out what the time will be after waiting wait_time number of hours. A reasonable solution is to simply add wait_time to current_time and print out the result. So lets try that.
-
+
current_time = input("What is the current time (in hours 0 - 23)?")
wait_time = input("How many hours do you want to wait")
@@ -66,7 +66,7 @@ print(final_time)
Hmm, when you run this example you see that something unexpected has happened. You would not realize this was an error unless you first knew what the program was supposed to do.
-
+
Which of the following best describes what is wrong with the previous example?
@@ -99,7 +99,7 @@ print(final_time)
This error was probably pretty simple to spot, because we printed out the value of final_time and it is easy to see that the numbers were just concatenated together rather than added.
So what do we do about the problem? We will need to convert both current_time and wait_time to int. At this stage of your programming development, it can be a good idea to include the type of the variable in the variable name itself. So let's look at another iteration of the program that does that, and the conversion to integer.
-
+
current_time_str = input("What is the current time (in hours 0-23)?")
wait_time_str = input("How many hours do you want to wait")
@@ -114,7 +114,7 @@ print(final_time_int)
Now, that's a lot better, and in fact depending on the hours you chose, it may be exactly right. If you entered 8 for current_time and 5 for wait_time then 13 is correct. But if you entered 17 (5 pm) for current_time and 9 for wait_time then the result of 26 is not correct.
This illustrates an important aspect of testing: it is important to test your code on a range of inputs. It is especially important to test your code on boundary conditions. For this particular problem, you should test your program with current_time of 0, 23, and some values in between. You should test your wait_time for 0, and some larger values. What about negative numbers? Negative numbers don't make sense, and since we don't really have the tools to deal with telling the user when something is wrong we will not worry about that just yet.
So to account for those numbers that are bigger than 23, we need one final step: using the modulus operator.
-
+
current_time_str = input("What is the current time (in hours 0-23)?")
wait_time_str = input("How many hours do you want to wait")
diff --git a/pretext/Debugging/KnowyourerrorMessages.ptx b/pretext/Debugging/KnowyourerrorMessages.ptx
index 9e83f8d55..4bf31b6ec 100644
--- a/pretext/Debugging/KnowyourerrorMessages.ptx
+++ b/pretext/Debugging/KnowyourerrorMessages.ptx
@@ -2,8 +2,11 @@
Know Your Error Messages
+
Many problems in your program will lead to an error message. For example as I was writing and testing this chapter of the book I wrote the following version of the example program in the previous section.
+
+
current_time_str = input("What is the current time (in hours 0-23)?")
wait_time_str = input("How many hours do you want to wait")
@@ -11,13 +14,17 @@ wait_time_str = input("How many hours do you want to wait")
current_time_int = int(current_time_str)
wait_time_int = int(wait_time_int)
+
final_time_int = current_time_int + wait_time_int
print(final_time_int)
+
+
Can you see what is wrong, just by looking at the code? Maybe, maybe not. Our brain tends to see what we think is there, so sometimes it is very hard to find the problem just by looking at the code. Especially when it is our own code and we are sure that we have done everything right!
Let's try the program again, but this time in an activecode:
-
+
+
current_time_str = input("What is the current time (in hours 0-23)?")
wait_time_str = input("How many hours do you want to wait")
@@ -29,13 +36,16 @@ final_time_int = current_time_int + wait_time_int
print(final_time_int)
+
Aha! Now we have an error message that might be useful. The name error tells us that wait_time_int is not defined. It also tells us that the error is on line 5. That's really useful information. Now look at line five and you will see that wait_time_int is used on both the left and the right hand side of the assignment statement.
+
The error descriptions you see in activecode may be different (and more understandable!) than in a regular
Python interpreter. The interpreter in activecode is limited in many ways, but it is intended for beginners,
including the wording chosen to describe errors.
-
+
+
In writing and using this book over the last few years we have collected a lot of statistics about the programs in this book. Here are some statistics about error messages for the exercise we have been looking at.
@@ -214,6 +225,7 @@ print(final_time_int)
+
Nearly 90% of the error messages encountered for this problem are ParseError, TypeError, NameError, or ValueError. We will look at these errors in three stages:
@@ -228,27 +240,20 @@ print(final_time_int)
+
+
ParseError
Parse errors happen when you make an error in the syntax of your program. Syntax errors are like making grammatical errors in writing. If you don't use periods and commas in your writing then you are making it hard for other readers to figure out what you are trying to say. Similarly Python has certain grammatical rules that must be followed or else Python can't figure out what you are trying to say.
-
Usually ParseErrors can be traced back to missing punctuation characters, such as parentheses, quotation marks, or commas. Remember that in Python commas are used to separate parameters to functions. Parentheses must be balanced, or else Python thinks that you are trying to include everything that follows as a parameter to some function.
+
+
Usually ParseErrors can be traced back to missing punctuation characters, such as parentheses, quotation marks, or commas. Remember that in Python commas are used to separate values, such as when defining a list or giving multiple values to a function call. Parentheses must be balanced, or else Python thinks that you are trying to include everything that follows as a parameter to some function.
Here are a couple examples of Parse errors in the example program we have been using. See if you can figure out what caused them.
-
-
-
-
- current_time_str = input("What is the current time (in hours 0-23)?")
-wait_time_str = input("How many hours do you want to wait"
-current_time_int = int(current_time_str)
-wait_time_int = int(wait_time_str)
+
-final_time_int = current_time_int + wait_time_int
-print(final_time_int)
- Since the error message points us to line 4 this might be a bit confusing. If you look at line four carefully you will see that there is no problem with the syntax. So, in this case the next step should be to back up and look at the previous line. In this case if you look at line 2 carefully you will see that there is a missing right parenthesis at the end of the line. Remember that parenthses must be balanced. Since Python allows statements to continue over multiple lines inside parentheses Python will continue to scan subsequent lines looking for the balancing right parenthesis. However in this case it finds the name current_time_int and it will want to interpret that as another parameter to the input function. But, there is not a comma to separate the previous string from the variable so as far as Python is concerned the error here is a missing comma. From your perspective its a missing parenthesis.
-
-
+
+
current_time_str = input("What is the current time (in hours 0-23)?")
wait_time_str = input("How many hours do you want to wait"
@@ -258,25 +263,23 @@ wait_time_int = int(wait_time_str)
final_time_int = current_time_int + wait_time_int
print(final_time_int)
-
Since the error message points us to line 4 this might be a bit confusing. If you look at line four carefully you will see that there is no problem with the syntax. So, in this case the next step should be to back up and look at the previous line. In this case if you look at line 2 carefully you will see that there is a missing right parenthesis at the end of the line. Remember that parenthses must be balanced. Since Python allows statements to continue over multiple lines inside parentheses Python will continue to scan subsequent lines looking for the balancing right parenthesis. However in this case it finds the name current_time_int and it will want to interpret that as another parameter to the input function. But, there is not a comma to separate the previous string from the variable so as far as Python is concerned the error here is a missing comma. From your perspective its a missing parenthesis.
-
-
-
Finding Clues How can you help yourself find these problems? One trick that can be very valuable in this situation is to simply start by commenting out the line number that is flagged as having the error. If you comment out line four, the error message now changes to point to line 5. Now you ask yourself, am I really that bad that I have two lines in a row that have errors on them? Maybe, so taken to the extreme, you could comment out all of the remaining lines in the program. Now the error message changes to TokenError: EOF in multi-line statement This is a very technical way of saying that Python got to the end of file (EOF) while it was still looking for something. In this case a right parenthesis.
-
-
-
-
- current_time_str = input("What is the "current time" (in hours 0-23)?")
-wait_time_str = input("How many hours do you want to wait")
-current_time_int = int(current_time_str)
-wait_time_int = int(wait_time_str)
-final_time_int = current_time_int + wait_time_int
-print(final_time_int)
- The error message points you to line 1 and in this case that is exactly where the error occurs. In this case your biggest clue is to notice the difference in highlighting on the line. Notice that the words current time are a different color than those around them. Why is this? Because current time is in double quotes inside another pair of double quotes Python thinks that you are finishing off one string, then you have some other names and finally another string. But you haven't separated these names or strings by commas, and you haven't added them together with the concatenation operator (+). So, there are several corrections you could make. First you could make the argument to input be as follows: "What is the 'current time' (in hours 0-23)" Notice that here we have correctly used single quotes inside double quotes. Another option is to simply remove the extra double quotes. Why were you quoting current time anyway? "What is the current time (in hours 0-23)"
-
-
+
+
+ Since the error message points us to line 4 this might be a bit confusing. If you look at line four carefully you will see that there is no problem with the syntax. So, in this case the next step should be to back up and look at the previous line. In this case if you look at line 2 carefully you will see that there is a missing right parenthesis at the end of the line. Remember that parentheses must be balanced. Since Python allows statements to continue over multiple lines inside parentheses Python will continue to scan subsequent lines looking for the balancing right parenthesis. However in this case it finds the name current_time_int and it will want to interpret that as another parameter to the input function. But, there is not a comma to separate the previous string from the variable so as far as Python is concerned the error here is a missing comma. From your perspective its a missing parenthesis.
+
+
+
+
+
+
+
+
Finding Clues How can you help yourself find these problems? One trick that can be very valuable in this situation is to simply start by commenting out the line number that is flagged as having the error. If you comment out line four, the error message now changes to point to line 5. Now you ask yourself, am I really that bad that I have two lines in a row that have errors on them? Maybe, so taken to the extreme, you could comment out all of the remaining lines in the program. Now the error message changes to TokenError: EOF in multi-line statement This is a very technical way of saying that Python got to the end of file (EOF) while it was still looking for something. In this case a right parenthesis.
+
+
+
+
current_time_str = input("What is the "current time" (in hours 0-23)?")
wait_time_str = input("How many hours do you want to wait")
@@ -286,17 +289,26 @@ wait_time_int = int(wait_time_str)
final_time_int = current_time_int + wait_time_int
print(final_time_int)
-
The error message points you to line 1 and in this case that is exactly where the error occurs. In this case your biggest clue is to notice the difference in highlighting on the line. Notice that the words current time are a different color than those around them. Why is this? Because current time is in double quotes inside another pair of double quotes Python thinks that you are finishing off one string, then you have some other names and finally another string. But you haven't separated these names or strings by commas, and you haven't added them together with the concatenation operator (+). So, there are several corrections you could make. First you could make the argument to input be as follows: "What is the 'current time' (in hours 0-23)" Notice that here we have correctly used single quotes inside double quotes. Another option is to simply remove the extra double quotes. Why were you quoting current time anyway? "What is the current time (in hours 0-23)"
-
+
+
+
+ The error message points you to line 1 and in this case that is exactly where the error occurs. In this case your biggest clue is to notice the difference in highlighting on the line. Notice that the words current time are a different color than those around them. Why is this? Because current time is in double quotes inside another pair of double quotes Python thinks that you are finishing off one string, then you have some other names and finally another string. But you haven't separated these names or strings by commas, and you haven't added them together with the concatenation operator (+). So, there are several corrections you could make. First you could make the argument to input be as follows: "What is the 'current time' (in hours 0-23)" Notice that here we have correctly used single quotes inside double quotes. Another option is to simply remove the extra double quotes. Why were you quoting current time anyway? "What is the current time (in hours 0-23)"
+
+
+
+
+
Finding Clues If you follow the same advice as for the last problem, comment out line one, you will immediately get a different error message. Here's where you need to be very careful and not panic. The error message you get now is: NameError: name 'current_time_str' is not defined on line 4. You might be very tempted to think that this is somehow related to the earlier problem and immediately conclude that there is something wrong with the variable name current_time_str but if you reflect for a minute you will see that by commenting out line one you have caused a new and unrelated error. That is you have commented out the creation of the name current_time_str. So of course when you want to convert it to an int you will get the NameError. Yes, this can be confusing, but it will become much easier with experience. It's also important to keep calm, and evaluate each new clue carefully so you don't waste time chasing problems that are not really there.
Uncomment line 1 and you are back to the ParseError. Another track is to eliminate a possible source of error. Rather than commenting out the entire line you might just try to assign current_time_str to a constant value. For example you might make line one look like this: current_time_str = "10" #input("What is the "current time" (in hours 0-23)?"). Now you have assigned current_time_str to the string 10, and commented out the input statement. And now the program works! So you conclude that the problem must have something to do with the input function.
+
TypeError
TypeErrors occur when you you try to combine two objects that are not compatible. For example you try to add together an integer and a string. Usually type errors can be isolated to lines that are using mathematical operators, and usually the line number given by the error message is an accurate indication of the line.
Here's an example of a type error created by a Polish learner. See if you can find and fix the error.
-
+
+
a = input('wpisz godzine')
x = input('wpisz liczbe godzin')
@@ -310,8 +322,7 @@ print ('godzina teraz', a)
-
- Solution
+
In finding this error there are few lessons to think about. First, you may find it very disconcerting that you cannot understand the whole program. Unless you speak Polish then this won't be an issue. But, learning what you can ignore, and what you need to focus on is a very important part of the debugging process. Second, types and good variable names are important and can be very helpful. In this case a and x are not particularly helpful names, and in particular they do not help you think about the types of your variables, which as the error message implies is the root of the problem here. The rest of the lessons we will get back to in a minute.
The error message provided to you gives you a pretty big hint. TypeError: unsupported operand type(s) for FloorDiv: 'str' and 'number' on line: 5 On line five we are trying to use integer division on x and 24. The error message tells you that you are tyring to divide a string by a number. In this case you know that 24 is a number so x must be a string. But how? You can see the function call on line 3 where you are converting x to an integer. int(x) or so you think. This is lesson three and is one of the most common errors we see in introductory programming. What is the difference between int(x) and x = int(x)
@@ -325,14 +336,20 @@ print ('godzina teraz', a)
So, the solution to this problem is to change lines 3 and 4 so they are assignment statements.
-
+
+
Finding Clues One thing that can help you in this situation is to print out the values and the types of the variables involved in the statement that is causing the error. You might try adding a print statement after line 4 print(x, type(x)) You will see that at least we have confirmed that x is of type string. Now you need to start to work backward through the program. You need to ask yourself, where is x used in the program? x is used on lines 2, 3, and of course 5 and 6 (where we are getting an error). So maybe you move the print statement to be after line 2 and again after 3. Line 3 is where you expect the value of x to be changed to an integer. Could line 4 be mysteriously changing x back to a string? Not very likely. So the value and type of x is just what you would expect it to be after line 2, but not after line 3. This helps you isolate the problem to line 3. In fact if you employ one of our earlier techniques of commenting out line 3 you will see that this has no impact on the error, and is a big clue that line 3 as it is currently written is useless.
+
+
+
NameError
Name errors almost always mean that you have used a variable before it has a value. Often NameErrors are simply caused by typos in your code. They can be hard to spot if you don't have a good eye for catching spelling mistakes. Other times you may simply mis-remember the name of a variable or even a function you want to call. You have seen one example of a NameError at the beginning of this section. Here is another one. See if you can get this program to run successfully:
-
+
+
+
str_time = input("What time is it now?")
str_wait_time = input("What is the number of nours to wait?")
@@ -344,11 +361,15 @@ print(time_when_alarm_go_off)
-
- Solution
+
+
In this example, the student seems to be a fairly bad speller, as there are a number of typos to fix. The first one is identified as wait_time is not defined on line 6. Now in this example you can see that there is str_wait_time on line 2, and wai_time on line 4 and wait_time on line 6. If you do not have very sharp eyes its easy to miss that there is a typo on line 4.
-
+
+
+
+
+
Finding Clues With name errors one of the best things you can do is use the editor, or browser search function. Quite often if you search for the exact word in the error message one of two things will happen:
@@ -361,7 +382,8 @@ print(time_when_alarm_go_off)
Here is another one for you to try:
-
+
+
n = input("What time is it now (in hours)?")
n = imt(n)
@@ -371,25 +393,29 @@ q = m % 12
print("The time is now", q)
+
+
-
- Solution
+
This one is once again a typo, but the typo is not in a variable name, but rather, the name of a function. The search strategy would help you with this one easily, but there is another clue for you as well. The editor in the textbook, as well as almost all Python editors in the world provide you with color clues. Notice that on line 2 the function imt is not highlighted blue like the word int on line 4.
-
-
+
+
+
And one last bit of code to fix.
-
+
+
-present_time = input("Enter the present timein hours:")
+present_time = input("Enter the present time in hours:")
set_alarm = input("Set the hours for alarm:")
int (present_time, set_time, alarm_time)
alarm_time = present_time + set_alarm
print(alarm_time)
+
+
+
-
- Solution
In this example the error message is about set_time not defined on line 3. In this case the undefined name is not used in an assignment statement, but is used as a parameter (incorrectly) to a function call. A search on set_time reveals that in fact it is only used once in the program. Did the author mean set_alarm? If we make that assumption we immediately get another error NameError: name 'alarm_time' is not defined on line: 3. The variable alarm_time is defined on line 4, but that does not help us on line 3. Furthermore we now have to ask the question is this function call int(present_time, set_alarm, alarm_time) even the correct use of the int function? The answer to that is a resounding no. Let's list all of the things wrong with line 3:
Value errors occur when you pass a parameter to a function and the function is expecting a certain limitations on the values, and the value passed is not compatible. We can illustrate that with this particular program in two different ways.
-
+
+
current_time_str = input("What is the current time (in hours 0-23)?")
current_time_int = int(current_time_str)
diff --git a/pretext/Debugging/intro-HowtobeaSuccessfulProgrammer.ptx b/pretext/Debugging/intro-HowtobeaSuccessfulProgrammer.ptx
index 6f79d7f52..2d8fd2a2e 100644
--- a/pretext/Debugging/intro-HowtobeaSuccessfulProgrammer.ptx
+++ b/pretext/Debugging/intro-HowtobeaSuccessfulProgrammer.ptx
@@ -1,6 +1,6 @@
How to be a Successful Programmer
-
One of the most important skills you need to aquire to complete this book successfully is the ability to debug your programs. Debugging might be the most under-appreciated, and under-taught, skill in introductory computer science. For that reason we are introducing a series of debugging interludes. Debugging is a skill that you need to master over time, and some of the tips and tricks are specific to different aspects of Python programming. So look for additional debugging interludes throughout the rest of this book.
+
One of the most important skills you need to acquire to complete this book successfully is the ability to debug your programs. Debugging might be the most under-appreciated, and under-taught skill in introductory computer science. For that reason we are including this debugging interlude. Debugging is a skill that you need to master over time, and some of the tips and tricks are specific to different aspects of Python programming.
Programming is an odd thing in a way. Here is why. As programmers we spend 99% of our time trying to get our program to work. We struggle, we stress, we spend hours deep in frustration trying to get our program to execute correctly. Then when we do get it going we celebrate, hand it in, and move on to the next homework assignment or programming task. But here is the secret, when you are successful, you are happy, your brain releases a bit of chemical that makes you feel good. You need to organize your programming so that you have lots of little successess. It turns out your brain doesn't care all that much if you have successfully written hello world, or a fast fourier transform (trust me its hard) you still get that little release that makes you happy. When you are happy you want to go on and solve the next little problem. Essentially I'm telling you once again, start small, get something small working, and then add to it.
The del statement removes a key-value pair from a dictionary. For example,
the following dictionary contains the names of various fruits and the number of
each fruit in stock. If someone buys all of the pears, we can remove the entry from the dictionary.
-
+
inventory = {'apples': 430, 'bananas': 312, 'oranges': 525, 'pears': 217}
@@ -16,7 +16,7 @@
be modified by referencing an association on the left hand side of the assignment statement. In the previous
example, instead of deleting the entry for pears, we could have set the inventory to 0.
-
+
inventory = {'apples': 430, 'bananas': 312, 'oranges': 525, 'pears': 217}
@@ -25,7 +25,7 @@
Similarily,
a new shipment of 200 bananas arriving could be handled like this.
One way to create a dictionary is to start with the empty dictionary and add
key-value pairs. The empty dictionary is denoted {}
-
+
eng2sp = {}
eng2sp['one'] = 'uno'
@@ -35,7 +35,7 @@
For our purposes we can think of this ordering as unpredictable.
Another way to create a dictionary is to provide a list of key-value pairs
using the same syntax as the previous output.
-
+
eng2sp = {'three': 'tres', 'one': 'uno', 'two': 'dos'}
print(eng2sp)
@@ -46,7 +46,7 @@
accessed with keys, not with indices, so there is no need to care about
ordering.
Here is how we use a key to look up the corresponding value.
-
+
eng2sp = {'three': 'tres', 'one': 'uno', 'two': 'dos'}
diff --git a/pretext/Figures/ExtraTopics/Figures/complexity.png b/pretext/Figures/ExtraTopics/Figures/complexity.png
new file mode 100644
index 000000000..5914ca96d
Binary files /dev/null and b/pretext/Figures/ExtraTopics/Figures/complexity.png differ
diff --git a/pretext/Files/AlternativeFileReadingMethods.ptx b/pretext/Files/AlternativeFileReadingMethods.ptx
index 494965c5c..62d1c7908 100644
--- a/pretext/Files/AlternativeFileReadingMethods.ptx
+++ b/pretext/Files/AlternativeFileReadingMethods.ptx
@@ -20,26 +20,26 @@
of readline this moves the marker to the first character of the next line
in the file. In the case of read or readlines the marker is moved to
the end of the file.
-
Now let's look at another method of reading our file using a while loop. This is important because many other programming languages do not support the for loop style for reading files but they do support the pattern we'll show you here.
You can access files in sub-folders, also called directories, under your home directory
by adding a slash and the name of the folder. For example, if you had a file
- called hello.py in a folder called CS150 that is inside a folder called
- PyCharmProjects under your home directory, then the full name for the file
- hello.py is /Users/yourname/PyCharmProjects/CS150/hello.py.
+ called hello.py in a folder called CS128 that is inside a folder called
+ VSCodeProjects under your home directory, then the full name for the file
+ hello.py is /Users/yourname/VSCodeProjects/CS128/hello.py.
This is called an absolute file path. An absolute file path typically
only works on a specific computer. Think about it for a second. What other
computer in the world is going to have an absolute file path that starts with
diff --git a/pretext/Files/Glossary.ptx b/pretext/Files/Glossary.ptx
index a898e32ad..8cee89cbb 100644
--- a/pretext/Files/Glossary.ptx
+++ b/pretext/Files/Glossary.ptx
@@ -26,6 +26,26 @@
write
Will add characters to the end of a file that has been opened for writing.
+
+
+ csv
+
An optional Python module that provides useful functions for interacting with data in the Comma Separated Value format.
+
+
+ Comma Separated Value
+
A format that text files can have. Promises that the file contains alphanumeric values separate by single commas and organized into one row of data per line.
+
+
+ reader
+
A function part of the csv module that creates an object for traversing csv file data.
+
+
+ writerow
+
A function part of the csv module that takes a list of data, formats it in the appropriate csv format, and writes it to a data file.
+
+
+ writerows
+
A function part of the csv module. Similar to writerow, but can write multiple rows of data at once if given a list of lists.
absolute file path
diff --git a/pretext/Files/Iteratingoverlinesinafile.ptx b/pretext/Files/Iteratingoverlinesinafile.ptx
index da9ccf0f7..03d6492b9 100644
--- a/pretext/Files/Iteratingoverlinesinafile.ptx
+++ b/pretext/Files/Iteratingoverlinesinafile.ptx
@@ -1,8 +1,27 @@
Iterating over lines in a file
-
Recall the contents of the ccdata.txt file.
-
+
+
As an example, suppose we have a text file called ccdata.txt that contains
+ the following data representing statistics about climate change. Although it
+ would be possible to consider entering this data by hand each time it is used,
+ you can imagine that it would be time-consuming and error-prone to do this. In
+ addition, it is likely that there could be data from more sources and
+ other years. The format of the data file is as follows:
+
Year, Global Average Temperature, Global Emmision of CO2
+
+
+
To open this file, we would call the open function. The variable,
+ fileref, now holds a reference to the file object returned by
+ open. Again, after the file is closed any further attempts to
+ use fileref will result in an error.
+
with open("ccdata.txt", "r") as fileref:
+ # do things
+
+
+
+
+
We will now use this file as input in a program that will do some data
processing. In the program, we will read each line of the file and
print it with some additional text. Because text files are sequences of
@@ -44,16 +61,13 @@
the split method, we can break each line into a list containing all the fields of interest about climate
change. We can then take the values corresponding to year, global average temperature, and global emmisions to
construct a simple sentence.
-
+
-ccfile = open("ccdata.txt", "r")
-
-for aline in ccfile:
- values = aline.split()
- print('In', values[0], 'the average temp. was', values[1], '°C and CO2 emmisions were', values[2], 'gigatons.')
-
-ccfile.close()
-
+with open("ccdata.txt", "r") as ccfile:
+ for aline in ccfile:
+ values = aline.split()
+ print('In', values[0], 'the average temp. was', values[1], '°C and CO2 emmisions were', values[2], 'gigatons.')
+
You can obtain a line from the keyboard with the input function, and you can process lines of a file.
diff --git a/pretext/Files/ReadingCSV.ptx b/pretext/Files/ReadingCSV.ptx
new file mode 100644
index 000000000..c12bea915
--- /dev/null
+++ b/pretext/Files/ReadingCSV.ptx
@@ -0,0 +1,66 @@
+
+
+ Reading Files as csv
+
The climate change data file we have used as an example in this chapter has a more specific designation than just a .txt file. Because the file
+ consists of a series of values separated by commas, it can also be referred to as a Comma Separate Value file, or a .csv. Note that csv
+ files are still just text files, but knowing it is also a csv tells us something valuable about the structure of the data it contains. This makes it
+ easier to parse and interact with that data.
+
+
To interact with text files as csv's, we need to import the Python csv module and use it to create reader or writer objects.
+ This section focuses on reading csv, so we should use a reader. The reason we are interested in doing this is because the reader will automatically detect and remove
+ the commas separating values for us. Essentially, the reader will split the data up into lists for us. This makes it simpler to navigate and interact with the data in the file.
+
Let's see an example of this working.
+
+
+import csv
+with open("ccdata.csv", "r") as file:
+ csv_reader = csv.reader(file, delimiter=',')
+ for line in csv_reader:
+ print(line)
+ print(line[0]) # just years
+
+
+
+
Note that the value assigned to for loop line variable is a list rather than a single string like we would get with a standard file object. This allows us to acces column
+ data quickly with a single index value.
+
+
The following table describes the two csv functions you are most likely to want to use.
+
+
+
+
+ Method Name
+
+
+ Use
+
+
+ Explanation
+
+
+
+
+ reader
+
+
+ csv.reader(file_object)
+
+
+ Creates a csv reader object that automatically splits lines of data but can be looped through like a regular file object.
+
+
+
+
+ writer
+
+
+ csv.writer(file_object)
+
+
+ Creates a csv writer object that takes lists of strings and writes them to the provided file in the correct csv format.
+
+
+
+
+
diff --git a/pretext/Files/WithStatements.ptx b/pretext/Files/WithStatements.ptx
index d356755b3..b45707957 100644
--- a/pretext/Files/WithStatements.ptx
+++ b/pretext/Files/WithStatements.ptx
@@ -1,26 +1,79 @@
With Statements
-
-
This section is a bit of an advanced topic and can be easily skipped. But with statements are becoming very common and it doesn't hurt to know about them in case you run into one in the wild.
-
-
Now that you have seen and practiced a bit with opening and closing files, there is another mechanism that Python provides for us that cleans up the often forgotten close. Forgetting to close a file does not necessarily cause a runtime error in the kinds of programs you typically write in an introductory CS course. However if you are writing a program that may run for days or weeks at a time that does a lot of file reading and writing you may run into trouble.
-
In version 2.5 Python introduced the concept of a context manager. The context manager automates the process of doing common operations at the start of some task, as well as automating certain operations at the end of some task. In the context of reading and writing a file, the normal operation is to open the file and assign it to a variable. At the end of working with a file the common operation is to make sure that file is closed.
-
The Python with statement makes using context managers easy. The general form of a with statement is:
-
with <create some object that understands context> as <some name>:
- do some stuff with the object
+
+
+
+
In order to open files easily in Python, we can use the following form:
+
with <some open statement> as <variable name for the file>:
+ do some stuff with the file
...
-
When the program exits the with block, the context manager handles the common stuff that normally happens. For example closing a file. A simple example will clear up all of this abstract discussion of contexts.
+
When the program exits the with block, the file is automatically closed. Consider the following example:
-
-
+
+
-with open('mydata.txt') as md:
- print(md)
- for line in md:
+with open('mydata.txt') as myfile:
+ print(myfile)
+ for line in myfile:
print(line)
-print(md)
+print(myfile)
-
The first line of the with statement opens the file and assigns it to md then we can iterate over the file in any of the usual ways. and when we are done we simply stop indenting and let Python take care of closing the file and cleaning up.
+
The first line of the with statement opens the file and assigns it to myfile, then we can iterate over each line in the file. When we are done, we simply stop indenting and let Python take care of closing the file and cleaning up.
+
A word of caution: once you read all the lines from a file, it is "spent";
+ that is to say, if we tried to read from myfile again in the example above, it would not
+ work. We would have to open the file again to read again.
+
+
In this course, you likely will not see the following syntax, but it's still useful to know that it's out there:
+
In Python, we can call the open function to open files before we can use them and the close function to close them when we are done with them. As you might expect, once a file is opened it becomes a Python object just like all other data. shows the functions and methods that can be used to open and close files.
+
+
+
+
+ Method Name
+
+
+ Use
+
+
+ Explanation
+
+
+
+
+ open
+
+
+ open(filename,'r')
+
+
+ Open a file called filename and use it for reading. This will return a reference to a file object.
+
+
+
+
+ open
+
+
+ open(filename,'w')
+
+
+ Open a file called filename and use it for writing. This will also return a reference to a file object.
+
+
+
+
+ close
+
+
+ filevariable.close()
+
+
+ File use is complete.
+
+
+
+
+
diff --git a/pretext/Files/WritingCSV.ptx b/pretext/Files/WritingCSV.ptx
new file mode 100644
index 000000000..fdd8682d4
--- /dev/null
+++ b/pretext/Files/WritingCSV.ptx
@@ -0,0 +1,44 @@
+
+
+ Writing Files as csv
+
We already introduced the csv module in the previous section. Let's examine some examples using a csv.writer object.
+
Like the reader object, the csv.writer function takes a opened file object. Once set up, the csv file can be written to with writerow.
+ Make note that writerow does not need an explicit newline character \n to know when to end a line of text. This sets it apart for the the regular file.write() function.
+
+
+import csv
+data = [["Column_1_Name","Column_2_Name","Column_3_Name"],
+ [1,2,3],
+ [50,40,23]
+]
+
+with open("new_file.csv", "w", newline='') as file:
+ csv_writer = csv.writer(file, delimiter=',')
+ for line in data:
+ csv_writer.writerow(line)
+
+
+
This program will create a file called new_file.csv with the contents:
You may have noticed there is one new piece of code in our with open(... line. The newline='' parameter is needed here to avoid adding extra blank lines to our output file.
+ Try running this code locally without that part to see the difference.
+
+
There is one other writer method you may find useful, which is writerows. This allows you to write multiple rows of data at the same time. When applied to the previous
+ example, it saves us from having to set up a loop.
To construct this file, we will approach the problem using a similar algorithm as above. After opening the file, we will iterate through the
lines, break each line into its parts, choose the parts that we need, and then output them. Eventually, the output will be written to a file.
The program below solves part of the problem. Notice that it reads the data and creates a string consisting of the year of the climate change followed by the global emission. In this example, we simply print the lines as they are created.
When we run this program, we see the lines of output on the screen. Once we are satisfied that it is creating the appropriate output, the next step is to add the necessary pieces to produce an output file and write the data lines to it. To start, we need to open a new output file by adding another call to the open function, outfile = open("emissiondata.txt",'w'), using the 'w' flag. We can choose any file name we like. If the file does not exist, it will be created. However, if the file does exist, it will be reinitialized as empty and you will lose any previous contents.
Once the file has been created, we just need to call the write method passing the string that we wish to add to the file. In this case, the string is already being printed so we will just change the print into a call to the write method. However, there is one additional part of the data line that we need to include. The newline character needs to be concatenated to the end of the line. The entire line now becomes outfile.write(dataline + '\n'). We also need to close the file when we are done.
So far, the data we have used in this book have all been either coded right into the program, or have been entered by the user. In real life data reside in files. For example the images we worked with in the image processing unit ultimately live in files on your hard drive. Web pages, and word processing documents, and music are other examples of data that live in files. In this short chapter we will introduce the Python concepts necessary to use data from files in our programs.
+
So far, the data we have used in this book have all been either coded right into the program, or have been entered by the user. In real life, data reside in files.
+
For example, web pages, word processing documents, and all data that live in files. In this chapter we will introduce the Python concepts necessary to use data from files in our programs.
For our purposes, we will assume that our data files are text files–that is, files filled with characters. The Python programs that you write are stored as text files. We can create these files in any of a number of ways. For example, we could use a text editor to type in and save the data. We could also download the data from a website and then save it in a file. Regardless of how the file is created, Python will allow us to manipulate the contents.
-
In Python, we must open files before we can use them and close them when we are done with them. As you might expect, once a file is opened it becomes a Python object just like all other data. shows the functions and methods that can be used to open and close files.
-
-
-
-
- Method Name
-
-
- Use
-
-
- Explanation
-
-
-
-
- open
-
-
- open(filename,'r')
-
-
- Open a file called filename and use it for reading. This will return a reference to a file object.
-
-
-
-
- open
-
-
- open(filename,'w')
-
-
- Open a file called filename and use it for writing. This will also return a reference to a file object.
-
-
-
-
- close
-
-
- filevariable.close()
-
-
- File use is complete.
-
-
-
-
We have already seen that boolean values result from the evaluation of boolean expressions. Since the result of any
+ expression evaluation can be returned by a function (using the return statement),
+ functions can return boolean values. This turns out to be a very convenient way to hide the details of complicated tests. For example:
+
+
+
+def isDivisible(x, y):
+ if x % y == 0:
+ result = True
+ else:
+ result = False
+
+ return result
+
+print(isDivisible(10, 5))
+
+
+
The name of this function is isDivisible. It is common to give boolean
+ functions names that sound like yes/no questions. isDivisible returns
+ either True or False to indicate whether the x is or is not
+ divisible by y.
+
+
We can make the function more concise by taking advantage of the fact that the
+ condition of the if statement is itself a boolean expression. We can return
+ it directly, avoiding the if statement altogether:
+
+
+def isDivisible(x, y):
+ return x % y == 0
+
+
+
Boolean functions are often used in conditional statements:
It might be tempting to write something like
+ if isDivisible(x, y) == True:
+ but the extra comparison is redundant. You only need an == expression if you are comparing some other type than boolean. (isDivisible(x, y) == False can also be made more concise as
+ not isDivisible(x, y)). The following example shows the isDivisible function at work. Notice how
+ descriptive the code is when we move the testing details into a boolean function. Try it
+ with a few other actual parameters to see what is printed.
+
+
+def isDivisible(x, y):
+ return x % y == 0
+
+if isDivisible(10, 5):
+ print("That works")
+else:
+ print("Those values are no good")
+
+
+
Here is the same program in codelens. When we evaluate the if statement in the main part of the program, the evaluation of
+ the boolean expression causes a call to the isDivisible function. This is very easy to see in codelens.
+
+
+ def isDivisible(x, y):
+ return x % y == 0
+
+ if isDivisible(10, 5):
+ print("That works")
+ else:
+ print("Those values are no good")
+
+
+
+ Check your understanding
+
+
+
+
What is a Boolean function?
+
+
+
+
+
A function that returns True or False
+
+
+ A Boolean function is just like any other function, but it always returns True or False.
+
+
+
+
+
A function that takes True or False as an argument
+
+
+ A Boolean function may take any number of arguments (including 0, though that is rare), of any type.
+
+
+
+
+
The same as a Boolean expression
+
+
+ A Boolean expression is a statement that evaluates to True or False, e.g. 5+3==8. A function is a series of expressions grouped together with a name that are only executed when you call the function.
+
+
+
+
+
+
+
Is the following statement legal in a Python function (assuming x, y and z are defined to be numbers)?
+
+
+return x + y < z
+
+
+
+
+
+
+
Yes
+
+
+ It is perfectly valid to return the result of evaluating a Boolean expression.
+
+
+
+
+
No
+
+
+ x +y < z is a valid Boolean expression, which will evaluate to True or False. It is perfectly legal to return True or False from a function, and to have the statement to be evaluated in the same line as the return keyword.
+
+
+
+
+
+ More Unit Testing
+
When we write unit tests, we should also consider output equivalence classes that result in significantly different results.
+
The isDivisible function can return either True or False. These two different outputs give us two equivalence classes. We then choose inputs that should give each of the different results. It is important to have at least one test for each output equivalence class.
+
+
+
+def isDivisible(x, y):
+ '''is x evenly divisible by y?'''
+ return x % y == 0
+
+if __name__ == "__main__":
+ import test
+
+
+
+ Extend the program …
+
Starting on line 7, write two unit tests (that should pass), one for each output equivalence class.
+
+
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
Use the drawsquare function we wrote in this chapter in a program to draw
- the image shown below.
- Assume each side is 20 units.
- (Hint: notice that the turtle has already moved away from the ending point of the last
- square when the program ends.)
-
-
-
-
-
-import turtle
-
-def drawSquare(t, sz):
- """Get turtle t to draw a square of sz side"""
-
- for i in range(4):
- t.forward(sz)
- t.left(90)
-
-wn = turtle.Screen()
-wn.bgcolor("lightgreen")
-
-alex = turtle.Turtle()
-alex.color("pink")
-
-drawSquare(alex,20)
-
-wn.exitonclick()
-
-
-
-
-
-import turtle
-
-def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
- for i in range(4):
- t.forward(sz)
- t.left(90)
-
-wn = turtle.Screen() # Set up the window and its attributes
-wn.bgcolor("lightgreen")
-
-alex = turtle.Turtle() # create alex
-alex.color('hotpink')
-alex.pensize(3)
-
-for i in range(5):
- drawSquare(alex, 20) # Call the function to draw the square
- alex.penup()
- alex.forward(40) # move alex to the starting position for the next square
- alex.pendown()
-
-wn.exitonclick()
-
-
-
-
-
-
-
Write a program to draw this. Assume the innermost square is 20 units per side,
- and each successive square is 20 units bigger, per side, than the one inside it.
-
-
-
-
-
-
-
-
-
-
-
Write a non-fruitful function drawPoly(someturtle, somesides, somesize) which makes a turtle
- draw a regular polygon.
- When called with drawPoly(tess, 8, 50), it will draw a shape like this:
-
-
-
-
-
-
-
-
-
-
-import turtle
-
-def drawPoly(t, num_sides, side_length):
- for i in range(num_sides):
- t.forward(side_length)
- t.left(360/num_sides)
-
-wn = turtle.Screen() # Set up the window and its attributes
-wn.bgcolor("lightgreen")
-
-tess = turtle.Turtle()
-tess.color('hotpink')
-tess.pensize(3)
-
-drawPoly(tess, 8, 50)
-
-
-
-
-
-
-
Draw this pretty pattern.
-
-
-
-
-
-
-
-
-
-
-
The two spirals in this picture differ only by the turn angle. Draw both.
-
-
-
-
-
-
-
-
-
-
-import turtle
-
-def drawSpiral(t, angle):
- ''' takes a turtle, t, and an angle in degrees '''
- length = 1
- for i in range(84):
- t.forward(length)
- t.right(angle)
- length = length + 2
-
-
-wn = turtle.Screen() # Set up the window and its attributes
-wn.bgcolor("lightgreen")
-
-guido = turtle.Turtle() # create guido
-guido.color('blue')
-
-## draw the first spiral ##
-# position guido
-guido.penup()
-guido.backward(110)
-guido.pendown()
-
-# draw the spiral using a 90 degree turn angle
-drawSpiral(guido, 90)
-
-
-## draw the second spiral ##
-# position guido
-guido.home()
-guido.penup()
-guido.forward(90)
-guido.pendown()
-
-drawSpiral(guido, 89)
-
-
-
-
-
-
-
Write a non-fruitful function drawEquitriangle(someturtle, somesize) which calls drawPoly from the
- previous question to have its turtle draw a equilateral triangle.
-
-
-
-
-
-
-
-
Write a fruitful function sumTo(n) that returns the sum of all integer numbers up to and
including n. So sumTo(10) would be 1+2+3...+10 which would return the value 55. Use the
equation (n * (n + 1)) / 2.
-
+
def sumTo(n):
@@ -207,7 +26,7 @@ myTests().main()
-
+
from test import testEqual
@@ -226,11 +45,11 @@ print("The sum from 1 to 5 is",t)
-
+
Write a function areaOfCircle(r) which returns the area of a circle of radius r. Make sure you use the math module in your solution.
Extend your program above. Draw five stars, but between each, pick up the pen,
- move forward by 350 units, turn right by 144, put the pen down, and draw the next star.
- You'll get something like this (note that you will need to move to the left before drawing your first star in order to fit everything in the window):
-
-
What would it look like if you didn't pick up the pen?
-
-
-
-
-
-
-
-
-
-
Extend the star function to draw an n pointed star. (Hint: n must be an odd number greater or
- equal to 3).
Write a function called drawSprite that will draw a sprite. The function will need parameters for
- the turtle, the number of legs, and the length of the legs. Invoke the function to create a sprite
- with 15 legs of length 120.
-
-
-
-
-
-
-
-
+
Rewrite the function sumTo(n) that returns the sum of all integer numbers up to and
including n. This time use the accumulator pattern.
-
+
def sumTo(n):
@@ -351,7 +92,7 @@ myTests().main()
-
+
def sumTo(n):
sum = 0
@@ -370,37 +111,12 @@ print("The sum from 1 to 5 is",t)
-
-
-
Write a function called mySqrt that will approximate the square root of a number, call it n, by using
- Newton's algorithm.
- Newton's approach is an iterative guessing algorithm where the initial guess is n/2 and each subsequent guess
- is computed using the formula: newguess = (1/2) * (oldguess + (n/oldguess)).
-
-
-
-
-def mySqrt(n):
- # your code here ====
-from unittest.gui import TestCaseGui
-
-class myTests(TestCaseGui):
- def testOne(self):
- self.assertAlmostEqual(mySqrt(4.0),2.0,0,"Tested mySqrt on input 4.0")
- self.assertAlmostEqual(mySqrt(9.0),3.0,4,"Tested accuracy of mySqrt on input 3.0")
- self.assertAlmostEqual(mySqrt(36.0),6.0,5,"Tested accuracy of mySqrt on input 6.0")
- self.assertAlmostEqual(mySqrt(100.0),10.0,4,"Tested accuracy of mySqrt on input 10.0. Try iterating more times.")
-
-myTests().main()
-
-
-
-
+
Write a function called myPi that will return an approximation of PI (3.14159…). Use the Leibniz
approximation.
-
+
def myPi(iters):
@@ -411,7 +127,7 @@ myTests().main()
-
+
def myPi(iters):
''' Calculate an approximation of PI using the Leibniz
@@ -433,12 +149,12 @@ print(pi_approx)
-
+
Write a function called myPi that will return an approximation of PI (3.14159…). Use the Madhava
approximation.
Write a function called fancySquare that will draw a square with fancy corners (sprites on the corners). You should
- implement and use the drawSprite function from above. For an even more interesting look, how about adding small
- triangles to the ends of the sprite legs.
There was a whole program in to create a bar chart with specific data. Creating a bar chart is a useful idea in general. Write a non-fruitful function called barChart, that takes the numeric list of data as a parameter, and draws the bar chart. Write a full program calling this function.
- The current version of the drawBar function unfortuately draws the top of the bar through the bottom of the label. A nice elaboration is to make the label appear completely above the top line. To keep the spacing consistent you might pass an extra parameter to drawBar for the distance to move up. For the barChart function make that parameter be some small fraction of maxheight+border. The fill action makes this modification particularly tricky: You will want to move past the top of the bar and write before or after drawing and filling the bar.
-
-
-
-
-import turtle
-
-def drawBar(t, height):
- """ Get turtle t to draw one bar, of height. """
- t.begin_fill() # start filling this shape
- t.left(90)
- t.forward(height)
- t.write(str(height))
- t.right(90)
- t.forward(40)
- t.right(90)
- t.forward(height)
- t.left(90)
- t.end_fill() # stop filling this shape
-
-
-
-xs = [48, 117, 200, 240, 160, 260, 220] # here is the data
-maxheight = max(xs)
-numbars = len(xs)
-border = 10
-
-wn = turtle.Screen() # Set up the window and its attributes
-wn.setworldcoordinates(0-border, 0-border, 40*numbars+border, maxheight+border)
-wn.bgcolor("lightgreen")
-
-tess = turtle.Turtle() # create tess and set some attributes
-tess.color("blue")
-tess.fillcolor("red")
-tess.pensize(3)
-
-
-
-for a in xs:
- drawBar(tess, a)
-
-wn.exitonclick()
-
-
-
diff --git a/pretext/Functions/FlowofExecutionSummary.ptx b/pretext/Functions/FlowofExecutionSummary.ptx
index 2c27227b0..b728f41b7 100644
--- a/pretext/Functions/FlowofExecutionSummary.ptx
+++ b/pretext/Functions/FlowofExecutionSummary.ptx
@@ -28,22 +28,22 @@
Check your understanding
-
+
Consider the following Python code. Note that line numbers are included on the left.
-def pow(b, p):
- y = b ** p
- return y
-
-def square(x):
- a = pow(x, 2)
- return a
-
-n = 5
-result = square(n)
-print(result)
+def pow(b, p): #1
+ y = b ** p #2
+ return y #3
+#4
+def square(x): #5
+ a = pow(x, 2) #6
+ return a #7
+#8
+n = 5 #9
+result = square(n) #10
+print(result) #11
Which of the following best reflects the order in which these lines of code are processed in Python?
@@ -91,7 +91,7 @@ print(result)
-
+
Consider the following Python code. Note that line numbers are included on the left.
diff --git a/pretext/Functions/Functionscancallotherfunctions.ptx b/pretext/Functions/Functionscancallotherfunctions.ptx
index 47ae94418..d8d067edc 100644
--- a/pretext/Functions/Functionscancallotherfunctions.ptx
+++ b/pretext/Functions/Functionscancallotherfunctions.ptx
@@ -11,7 +11,7 @@
first function called square simply computes the square of a given number.
The second function called sum_of_squares makes use of square to compute
the sum of three numbers that have been squared.
-
+
def square(x):
y = x * x
@@ -41,100 +41,7 @@
for sum_of_squares. As you step through you will notice that x, and y are local variables in both functions and may even have
different values. This illustrates that even though they are named the same,
they are in fact, very different.
-
Now we will look at another example that uses two functions. This example illustrates an
- important computer science problem solving technique called
- generalization. Assume we want to write a
- function to draw a square. The generalization step is to realize that a
- square is just a special kind of rectangle.
-
To draw a rectangle we need to be able to call a function with different
- arguments for width and height. Unlike the case of the square,
- we cannot repeat the same thing 4 times, because the four sides are not equal.
- However, it is the case that drawing the bottom and right sides are the
- same sequence as drawing the top and left sides. So we eventually come up with
- this rather nice code that can draw a rectangle.
-
-
-def drawRectangle(t, w, h):
- """Get turtle t to draw a rectangle of width w and height h."""
- for i in range(2):
- t.forward(w)
- t.left(90)
- t.forward(h)
- t.left(90)
-
-
-
The parameter names are chosen as single letters for conciseness.
- In real programs, we will insist on better variable names than this.
- The point is that the program doesn't understand that you're drawing a rectangle or that the
- parameters represent the width and the height. Concepts like rectangle, width, and height are meaningful
- for humans. They are not concepts that the program or the computer understands.
-
- Thinking like a computer scientist involves looking for patterns and
- relationships. In the code above, we've done that to some extent. We did
- not just draw four sides. Instead, we spotted that we could draw the
- rectangle as two halves and used a loop to repeat that pattern twice.
-
But now we might spot that a square is a special kind of rectangle. A square
- simply uses the same value for both the height and the width.
- We already have a function that draws a rectangle, so we can use that to draw
- our square.
-
-
-def drawSquare(tx, sz): # a new version of drawSquare
- drawRectangle(tx, sz, sz)
-
-
-
Here is the entire example with the necessary set up code.
-
-
-import turtle
-
-def drawRectangle(t, w, h):
- """Get turtle t to draw a rectangle of width w and height h."""
- for i in range(2):
- t.forward(w)
- t.left(90)
- t.forward(h)
- t.left(90)
-
-def drawSquare(tx, sz): # a new version of drawSquare
- drawRectangle(tx, sz, sz)
-
-wn = turtle.Screen() # Set up the window
-wn.bgcolor("lightgreen")
-
-tess = turtle.Turtle() # create tess
-
-drawSquare(tess, 50)
-
-wn.exitonclick()
-
-
-
There are some points worth noting here:
-
-
-
-
Functions can call other functions.
-
-
-
Rewriting drawSquare like this captures the relationship
- that we've spotted.
-
-
-
A caller of this function might say drawSquare(tess, 50). The parameters
- of this function, tx and sz, are assigned the values of the tess object, and
- the integer 50 respectively.
-
-
-
In the body of the function, tz and sz are just like any other variable.
-
-
-
When the call is made to drawRectangle, the values in variables tx and sz
- are fetched first, then the call happens. So as we enter the top of
- function drawRectangle, its variable t is assigned the tess object, and w and
- h in that function are both given the value 50.
-
-
-
+
So far, it may not be clear why it is worth the trouble to create all of these
new functions. Actually, there are a lot of reasons, but this example
demonstrates two:
@@ -156,16 +63,4 @@ wn.exitonclick()
-
- Lab
-
-
-
-
- Drawing a Circle In this guided lab exercise we will work
- through a simple problem solving exercise related to drawing a circle with the turtle.
-
-
-
-
diff --git a/pretext/Functions/Functionsthatreturnvalues.ptx b/pretext/Functions/Functionsthatreturnvalues.ptx
index 9cda6247f..7f120fcf4 100644
--- a/pretext/Functions/Functionsthatreturnvalues.ptx
+++ b/pretext/Functions/Functionsthatreturnvalues.ptx
@@ -5,7 +5,7 @@
job. For example, if you want to find the absolute value of a number, you have
to indicate what the number is. Python has a built-in function for computing
the absolute value:
-
+
print(abs(5))
@@ -13,17 +13,11 @@ print(abs(-5))
In this example, the arguments to the abs function are 5 and -5.
-
Some functions take more than one argument. For example the math module contains a function
- called
- pow which takes two arguments, the base and the exponent.
-
-
-
+
Some functions take more than one argument. For example the range function that we saw with for loops.
Another built-in function that takes more than one argument is max.
-
+
print(max(7, 11))
print(max(4, 1, 17, 2, 12))
@@ -43,12 +37,12 @@ print(max(3 * 11, 5 ** 3, 512 - 9, 1024 ** 0))
return the maximum value sent. The arguments can be either simple values or
expressions. In the last example, 503 is returned, since it is larger than 33,
125, and 1. Note that max also works on lists of values.
-
Furthermore, functions like range, int, abs all return values that
+
Furthermore, functions like int and abs all return values that
can be used to build more complex expressions.
-
So an important difference between these functions and one like drawSquare is that
- drawSquare was not executed because we wanted it to compute a value — on the contrary,
- we wrote drawSquare because we wanted it to execute a sequence of steps that caused
- the turtle to draw a specific shape.
+
So an important difference between these functions and one like printRange is that
+ printRange was not executed because we wanted it to compute a value — on the contrary,
+ we wrote printRange because we wanted it to execute a sequence of steps that caused
+ the list's range to print.
Functions that return values are sometimes called fruitful functions.
In many other languages, a chunk that doesn't return a value is called a procedure,
but we will stick here with the Python way of also calling it a function, or if we want
@@ -61,7 +55,7 @@ print(max(3 * 11, 5 ** 3, 512 - 9, 1024 ** 0))
as a parameter and return the result of squaring that number. Here is the
black-box diagram with the Python code following.
-
+
def square(x):
y = x * x
@@ -99,7 +93,7 @@ print("The result of", toSquare, "squared is", result)
we will see later where it makes sense to have a return statement even when other statements
follow, and the further statements are not executed.
-
+
def square(x):
y = x * x
@@ -136,7 +130,7 @@ print("The result of", toSquare, "squared is", squareResult)
programmers. As you step through this example, pay very close attention to the return
value in the local variables listing. Then look at what is printed when the
function returns.
-
+
def square(x):
y = x * x
@@ -154,7 +148,7 @@ print("The result of", toSquare, "squared is", squareResult)
Check your understanding
-
+
What is wrong with the following function definition:
@@ -200,7 +194,7 @@ def addEm(x, y, z):
-
+
What will the following function return?
diff --git a/pretext/Functions/ProgramDevelopment.ptx b/pretext/Functions/ProgramDevelopment.ptx
index d86150a1f..c2cbbf371 100644
--- a/pretext/Functions/ProgramDevelopment.ptx
+++ b/pretext/Functions/ProgramDevelopment.ptx
@@ -29,7 +29,7 @@ def distance(x1, y1, x2, y2):
returns zero. But it is syntactically correct, and it will run, which means
that we can test it before we make it more complicated.
We import the test module to enable us to write a unit test for the function.
-
+
import test
def distance(x1, y1, x2, y2):
@@ -83,7 +83,7 @@ def distance(x1, y1, x2, y2):
should be 25).
Finally, using the fractional exponent 0.5 to find the square root,
we compute and return the result.
-
+
import test
def distance(x1, y1, x2, y2):
diff --git a/pretext/Functions/TheAccumulatorPattern.ptx b/pretext/Functions/TheAccumulatorPattern.ptx
index f875e2b51..7200d30ea 100644
--- a/pretext/Functions/TheAccumulatorPattern.ptx
+++ b/pretext/Functions/TheAccumulatorPattern.ptx
@@ -2,7 +2,7 @@
The Accumulator Pattern
-
+
In the previous example, we wrote a function that computes the square of a number. The algorithm we used
in the function was simple: multiply the number by itself.
In this section we will reimplement the square function and use a different algorithm, one that relies on addition instead
@@ -22,7 +22,7 @@
Here is the program in activecode. Note that the heading of the function definition is the same as it was before. All that has changed
is the details of how the squaring is done. This is a great example of black box design. We can change out the details inside of the box and still use the function exactly as we did before.
-
+
def square(x):
runningtotal = 0
@@ -47,7 +47,7 @@ print("The result of", toSquare, "squared is", squareResult)
the for statement? Not sure? Try it and find out.
Here is the same program in codelens. Step through the function and watch the running total accumulate the result.
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
-
+
@@ -85,7 +85,7 @@ repeat:
Check your understanding
-
+
Consider the following code:
@@ -136,7 +136,7 @@ def square(x):
-
+
A Variation on the Accumulator Pattern
-
+
def square(x):
'''raise x to the second power'''
diff --git a/pretext/Functions/UnitTesting.ptx b/pretext/Functions/UnitTesting.ptx
index e39b6a024..98d29da18 100644
--- a/pretext/Functions/UnitTesting.ptx
+++ b/pretext/Functions/UnitTesting.ptx
@@ -1,106 +1,106 @@
Unit Testing
-
-
A test case expresses requirements for a program, in a way that can be checked automatically. Specifically, a test
- asserts something about the state of the program at a particular point in its execution. A unit test is an automatic
- procedure used to validate that individual units of code are working properly. A function is one form of a unit.
- A collection of these unit tests is called a test suite.
+
A test case expresses requirements for a program, in a way that can be checked automatically. Specifically, a test
+ asserts something about the state of the program at a particular point in its execution. A unit test is an automatic
+ procedure used to validate that individual units of code are working properly. A function is one form of a unit.
+ A collection of these unit tests is called a test suite.
We have previously suggested that it's a good idea to first write down comments about what your code is supposed to do,
- before actually writing the code. It is an even better idea to write down some test cases before writing a program.
+ before actually writing the code. It is an even better idea to write down some test cases before writing a program.
There are several reasons why it's a good habit to write test cases.
-
-
-
Before we write code, we have in mind what it should do, but those thoughts may be a little vague. Writing down test cases forces us to be more concrete about what should happen.
-
-
-
As we write the code, the test cases can provide automated feedback. You've actually been the beneficiary of such automated feedback via test cases throughout this book in some of the activecode windows and almost all of the exercises. We wrote the code for those test cases but kept it hidden, so as not to confuse you and also to avoid giving away the answers. You can get some of the same benefit from writing your own test cases.
-
-
-
In larger software projects, the set of test cases can be run every time a change is made to the code base. Unit tests check that small bits of code are correctly implemented.
-
-
+
+
+
Before we write code, we have in mind what it should do, but those thoughts may be a little vague. Writing down test cases forces us to be more concrete about what should happen.
+
+
+
As we write the code, the test cases can provide automated feedback. You've actually been the beneficiary of such automated feedback via test cases throughout this book in some of the activecode windows and almost all of the exercises. We wrote the code for those test cases but kept it hidden, so as not to confuse you and also to avoid giving away the answers. You can get some of the same benefit from writing your own test cases.
+
+
+
In larger software projects, the set of test cases can be run every time a change is made to the code base. Unit tests check that small bits of code are correctly implemented.
+
+
-
One way to implement unit tests in Python is with assert.
+
You have been following this pattern in the class so far, even if it is unconsciously. The test cases we give for each assessment can be thought of as unit tests.
+ We give these to you when the assessment is assigned because it is so helpful to have while you are writing code.
+
One way to implement unit tests in Python, the same way our test cases do it, is with assert.
-
-
-
Following the word assert there will be a python expression.
-
-
-
If that expression evaluates to the Boolean False, then the interpreter will raise a runtime error.
-
-
-
If the expression evaluates to True, then nothing happens and the execution goes on to the next line of code.
-
-
+
+
+
Following the word assert there will be a python expression.
+
+
+
If that expression evaluates to the Boolean False, then the interpreter will raise a runtime error.
+
+
+
If the expression evaluates to True, then nothing happens and the execution goes on to the next line of code.
+
+
Take a look at the way assert is used in the following code.
-
-
+
+
assert type(9//5) == int
assert type(9.0//5) == int
-
+
In the code above, we explicitly state some natural assumptions about how truncated division might work in python.
- It turns out that the second asumption is wrong: 9.0//5 produces 2.0, a floating point value!
+ It turns out that the second asumption is wrong: 9.0//5 produces 2.0, a floating point value!
The python interpreter does not enforce restrictions about the data types of objects that can be bound to particular
- variables; however, type checking could alert us that something has gone wrong in our program execution. If we are
- assuming at that x is a list, but it's actually an integer, then at some point later in the program execution,
- there will probably be an error. We can add assert statements that will cause an error to be flagged sooner rather
- than later, which might make it a lot easier to debug.
+ variables; however, type checking could alert us that something has gone wrong in our program execution. If we are
+ assuming at that x is a list, but it's actually an integer, then at some point later in the program execution,
+ there will probably be an error. We can add assert statements that will cause an error to be flagged sooner rather
+ than later, which might make it a lot easier to debug.
- Check your understanding
+ Check your understanding
-
-
-
When assert x==y is executed and x and y have the same values, what will happen?
-
-
-
-
-
A runtime error will occur
-
-
- The expression ``x==y`` evaluates to ``True``
-
-
-
-
-
A message is printed out saying that the test failed.
-
-
- The expression ``x==y`` evaluates to ``True``
-
-
-
-
-
x will get the value that y currently has
-
-
- ``x==y`` is a Boolean expression, not an assignment statement
-
-
-
-
-
Nothing will happen
-
-
- The expression ``x==y`` evaluates to ``True``
-
-
-
-
-
A message is printed out saying that the test passed.
-
-
- When an assertion test passes, no message is printed.
-
-
-
+
+
+
When assert x==y is executed and x and y have the same values, what will happen?
+
+
+
+
+
A runtime error will occur
+
+
+ The expression ``x==y`` evaluates to ``True``
+
+
+
+
+
A message is printed out saying that the test failed.
+
+
+ The expression ``x==y`` evaluates to ``True``
+
+
+
+
+
x will get the value that y currently has
+
+
+ ``x==y`` is a Boolean expression, not an assignment statement
+
+
+
+
+
Nothing will happen
+
+
+ The expression ``x==y`` evaluates to ``True``
+
+
+
+
+
A message is printed out saying that the test passed.
+
+
+ When an assertion test passes, no message is printed.
+
+
+
-assert with for loops
Why would you ever want to write a line of code that can never compute anything useful for you, but sometimes causes
@@ -116,7 +116,7 @@ assert type(9.0//5) == int
In the code below, lst is bound to a list object. In python, not all the elements of a list have to be of the
same type. We can check that they all have the same type and get an error if they are not. Notice that with lst2,
one of the assertions fails.
-
+
lst = ['a', 'b', 'c']
first_type = type(lst[0])
@@ -135,7 +135,7 @@ for item in lst2:
Testing whether a function returns the correct value is the easiest test case to define. You simply check whether the
result of invoking the function on a particular input produces the particular output that you expect. Take a look at
the following code.
-
+
def square(x):
#raise x to the second power
@@ -148,7 +148,7 @@ assert square(3) == 9
principle, a function might work properly on all the inputs that are tested in the test cases, but still not work
properly on some other inputs. That's where the art of defining test cases comes in: you try to find specific inputs that
are representative of all the important kinds of inputs that might ever be passed to the function.
-
+
For the hangman game, this ‘blanked' function takes a word and some letters that have been guessed, and returns a version
of the word with _ for all the letters that haven't been guessed. Which of the following is the correct way to write
diff --git a/pretext/Functions/Variablesandparametersarelocal.ptx b/pretext/Functions/Variablesandparametersarelocal.ptx
index 3451b4f86..e611bb3ce 100644
--- a/pretext/Functions/Variablesandparametersarelocal.ptx
+++ b/pretext/Functions/Variablesandparametersarelocal.ptx
@@ -5,7 +5,7 @@
variable on the left hand side of the assignment operator. It is called local because this variable only
exists inside the function and you cannot use it outside. For example,
consider again the square function:
-
+
def square(x):
y = x * x
@@ -39,7 +39,7 @@
On the other hand, it is legal for a function to access a global variable. However, this is considered
bad form by nearly all programmers and should be avoided. Look at the following,
nonsensical variation of the square function.
-
+
def badsquare(x):
y = x ** power
@@ -62,7 +62,7 @@ print(result)
There is another variation on this theme of local versus global variables. Assignment statements in the local function cannot
change variables defined outside the function, without further (discouraged) special syntax. Consider the following
codelens example:
-
+
def powerof(x, p):
power = p # Another dumb mistake
@@ -96,7 +96,7 @@ print(result)
formal parameter will cause a change to the value of the variable that was
used as the actual parameter, especially when the two share the same name.
But this example demonstrates that that is clearly not how Python operates.
-
+
def square(x):
y = x * x
@@ -111,7 +111,7 @@ print(result)
Check your understanding
-
+
What is a variable's scope?
@@ -142,7 +142,7 @@ print(result)
-
+
What is a local variable?
@@ -173,7 +173,7 @@ print(result)
-
+
Can you use the same name for a local variable as a global variable?
In Python, a function is a named sequence of statements
that belong together. Their primary purpose is to help us
organize programs into chunks that match how we think about
@@ -34,7 +34,7 @@ def name( parameters ):
-
We've already seen the for loop which follows this pattern.
+
We've already seen the while and for loops which follow this pattern.
In a function definition, the keyword in the header is def, which is
followed by the name of the function and some parameters enclosed in
parentheses. The parameter list may be empty, or it may contain any number of
@@ -45,34 +45,24 @@ def name( parameters ):
The figure below shows this relationship. A function needs certain information to do its work. These values, often called arguments or actual parameters, are passed to the function by the user.
This type of diagram is often called a black-box diagram because it only states the requirements from the perspective of the user. The user must know the name of the function and what arguments need to be passed. The details of how the function works are hidden inside the black-box.
-
Suppose we're working with turtles and a common operation we need is to draw
- squares. It would make sense if we did not have to duplicate all the steps each time we want to make a square. Draw a square can be thought of as an abstraction of a number of smaller steps. We will need to provide two pieces of information for the function to do its work: a turtle to do the drawing and a size for the side of the square. We could represent this using the following black-box diagram.
-
+
Suppose we're working with lists of numeric data and a common operation we need is to find the size of the range of numbers in a list.
+ It would make sense if we did not have to duplicate all the steps each time we want to find the size of the range. "printRange" can be thought of as an
+ abstraction of a number of smaller steps. We will need to provide one piece of information for the function to do its work: the list we need the range of.
Here is a program containing a function to capture this idea. Give it a try.
-
+
-import turtle
+ def printRange(lst):
+ """Prints the size of the range of lst."""
+ smallest = min(lst)
+ largest = max(lst)
+ print(largest - smallest)
-def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
-
- for i in range(4):
- t.forward(sz)
- t.left(90)
-
-
-wn = turtle.Screen() # Set up the window and its attributes
-wn.bgcolor("lightgreen")
-
-alex = turtle.Turtle() # create alex
-drawSquare(alex, 50) # Call the function to draw the square passing the actual turtle and the actual side size
-
-wn.exitonclick()
-
+ my_list1 = [1, 2, 3, 4, 5, 6]
+ printRange(my_list1)
+
-
This function is named drawSquare. It has two parameters — one to tell
- the function which turtle to move around and the other to tell it the size
- of the square we want drawn. In the function definition they are called t and sz respectively. Make sure you know where the body of the function
+
This function is named printRange. It has one parameter --- a variable storing a list of numbers. In the function definition this parameter is called
+ lst. Make sure you know where the body of the function
ends — it depends on the indentation and the blank lines don't count for
this purpose!
@@ -93,71 +83,24 @@ wn.exitonclick()
print, range and int. Function calls contain the name of the function to be
executed followed by a list of values in parentheses, called arguments, which are assigned
to the parameters in the function definition.
- So in the second to the last line of
- the program, we call the function, and pass alex as the turtle to be manipulated,
- and 50 as the size of the square we want.
-
-
+ So in the last line of
+ the program, we call the function, and pass my_list1 as the list to be analyzed.
Once we've defined a function, we can call it as often as we like and its
statements will be executed each time we call it. In this case, we could use it to get
- one of our turtles to draw a square and then we can move the turtle and have it draw a different square in a
- different location. Note that we lift the tail so that when alex moves there is no trace. We put the tail
- back down before drawing the next square. Make sure you can identify both invocations of the drawSquare function.
-
-
-import turtle
-
-def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
-
- for i in range(4):
- t.forward(sz)
- t.left(90)
-
-
-wn = turtle.Screen() # Set up the window and its attributes
-wn.bgcolor("lightgreen")
-
-alex = turtle.Turtle() # create alex
-drawSquare(alex, 50) # Call the function to draw the square
-
-alex.penup()
-alex.goto(100,100)
-alex.pendown()
-
-drawSquare(alex,75) # Draw another square
-
-wn.exitonclick()
-
-
-
In the next example, we've changed the drawSquare
- function a little and we get tess to draw 15 squares with some variations. Once the function has
- been defined, we can call it as many times as we like with whatever actual parameters we like.
-
+ the size of the range of multiple lists. Make sure you can identify all three invocations of the printRange function.
+
-import turtle
-
-def drawMulticolorSquare(t, sz):
- """Make turtle t draw a multi-colour square of sz."""
- for i in ['red','purple','hotpink','blue']:
- t.color(i)
- t.forward(sz)
- t.left(90)
-
-wn = turtle.Screen() # Set up the window and its attributes
-wn.bgcolor("lightgreen")
+def printRange(lst):
+ """Prints the size of the range of lst."""
+ smallest = min(lst)
+ largest = max(lst)
+ print(largest - smallest)
-tess = turtle.Turtle() # create tess and set some attributes
-tess.pensize(3)
-
-size = 20 # size of the smallest square
-for i in range(15):
- drawMulticolorSquare(tess, size)
- size = size + 10 # increase the size for next time
- tess.forward(10) # move tess along a little
- tess.right(18) # and give her some extra turn
-
-wn.exitonclick()
+my_list1 = [1, 2, 3, 4, 5, 6]
+my_list2 = [2, 6, 9, 16, 42, 100, 2, 5]
+printRange(my_list1)
+printRange(my_list2)
+printRange([5, 10, 1000, 2])
@@ -165,12 +108,12 @@ wn.exitonclick()
the parentheses ( ) after the function name are required. This
can lead to a difficult bug: A function name without the
parenthesis is a legal expression referring to the function; for example,
- print and alex.penup, but they do
- not call the associated functions.
+ print, but it does
+ not call the associated function. Try it below if you want to see.
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
-
+
@@ -180,7 +123,7 @@ wn.exitonclick()
Check your understanding
-
+
What is a function in Python?
@@ -219,7 +162,7 @@ wn.exitonclick()
-
+
What is one main purpose of a function?
@@ -258,7 +201,7 @@ wn.exitonclick()
-
+
Which of the following is a valid function header (first line of a function definition)?
@@ -297,23 +240,22 @@ wn.exitonclick()
-
+
What is the name of the following function?
-def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
- for i in range(4):
- t.forward(sz)
- t.left(90)
-
+def printSquare(size):
+ """Print a square of asterices with side size."""
+ for i in range(size):
+ print("*"*size)
+
-
def drawSquare(t, sz)
+
def printSquare(size)
This line is the complete function header (except for the semi-colon) which includes the name as well as several other components.
@@ -321,7 +263,7 @@ def drawSquare(t, sz):
-
drawSquare
+
printSquare
Yes, the name of the function is given after the keyword def and before the list of parameters.
@@ -329,7 +271,7 @@ def drawSquare(t, sz):
-
drawSquare(t, sz)
+
printSquare(size)
This includes the function name and its parameters
@@ -337,7 +279,7 @@ def drawSquare(t, sz):
-
Make turtle t draw a square with side sz.
+
Print a square of asterices with side size.
This is a comment stating what the function does.
@@ -345,16 +287,15 @@ def drawSquare(t, sz):
-
+
What are the parameters of the following function?
-def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
- for i in range(4):
- t.forward(sz)
- t.left(90)
+def printSquare(size):
+ """Print a square of asterices with side size."""
+ for i in range(size):
+ print("*"*size)
@@ -369,87 +310,86 @@ def drawSquare(t, sz):
-
t
+
size, i
- t is only one of the parameters to this function.
+ i is a variable used inside of the function, but not a parameter, which is passed in to the function.
-
t, sz
+
size
- Yes, the function specifies two parameters: t and sz.
+ Yes, the function specifies one parameter: size.
-
t, sz, i
+
"*"*size
- the parameters include only those variables whose values that the function expects to receive as input. They are specified in the header of the function.
+ This is an argument provided to the call to print().
-
+
-
Considering the function below, which of the following statements correctly invokes, or calls, this function (i.e., causes it to run)? Assume we already have a turtle named alex.
+
Considering the function below, which of the following statements correctly invokes, or calls, this function (i.e., causes it to run)? Assume we already have a variable named my_size.
-def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
- for i in range(4):
- t.forward(sz)
- t.left(90)
+def printSquare(size):
+ """Print a square of asterices with side size."""
+ for i in range(size):
+ print("*"*size)
-
def drawSquare(t, sz)
+
def printSquare(size)
- No, t and sz are the names of the formal parameters to this function. When the function is called, it requires actual values to be passed in.
+ No, size is the name of the formal parameter to this function. When the function is called, it requires an actual value to be passed in.
-
drawSquare
+
printSquare
A function call always requires parentheses after the name of the function.
-
+
-
drawSquare(10)
+
printSquare(10)
- This function takes two parameters (arguments)
+ Yes, this would work
-
+
-
drawSquare(alex, 10):
+
printSquare(my_size)
- A colon is only required in a function definition. It will cause an error with a function call.
+ Yes, this would work since my_size is already defined.
-
+
-
drawSquare(alex, 10)
+
printSquare(size):
- Since alex was already previously defined and 10 is a value, we have passed in two correct values for this function.
+ A colon is only required in a function definition. It will cause an error with a function call.
-
+
True or false: A function can be called several times by placing a function call in the body of a loop.
diff --git a/pretext/Functions/mainfunction.ptx b/pretext/Functions/mainfunction.ptx
index ca984a2b8..6d06e4730 100644
--- a/pretext/Functions/mainfunction.ptx
+++ b/pretext/Functions/mainfunction.ptx
@@ -2,59 +2,51 @@
Using a Main Function
Using functions is a good idea. It helps us to modularize our code by breaking a program
- into logical parts where each part is responsible for a specific task. For example, in one of our first programs there
- was a function called drawSquare that was responsible for having some turtle draw a square of some size.
- The actual turtle and the actual size of the square were defined to be provided as parameters. Here is that original program.
+ into logical parts where each part is responsible for a specific task. For example, in one of our recent programs there
+ was a function called square that was responsible for calculating the square of a number.
+ After the function definition we defined a variable, called the function, and printed its results. Here is that original program.
-import turtle
-
-def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
-
- for i in range(4):
- t.forward(sz)
- t.left(90)
+def square(x):
+ y = x * x
+ return y
+toSquare = 10
+squareResult = square(toSquare)
+print("The result of", toSquare, "squared is", squareResult)
+
+
+
If you look closely at the structure of this program, we first define the function square. At this point, we could have defined as many functions as were needed.
-wn = turtle.Screen() # Set up the window and its attributes
-wn.bgcolor("lightgreen")
+
The final three statements perform the main processing that the program will do. Notice that much of the detail has been pushed inside the square function.
+ However, there are still these three lines of code that are needed to get things done.
-alex = turtle.Turtle() # create alex
-drawSquare(alex, 50) # Call the function to draw the square
+
In many programming languages (e.g. Java and C++), it is not possible to simply have statements sitting alone like this at the bottom of the program.
+ They are required to be part of a special function that is automatically invoked by the operating system when the program is executed.
+ This special function is called main. Although this is not required by the Python programming language, it is actually a good idea that we
+ can incorporate into the logical structure of our program. In other words, these three lines are logically related to one another in that they provide the
+ main tasks that the program will perform. Since functions are designed to allow us to break up a program into logical pieces, it makes sense to call this
+ piece main.
-wn.exitonclick()
-
-
-
If you look closely at the structure of this program, you will notice that we first perform all of our necessary import statements, in this case to be able to use the turtle module. Next, we define the function drawSquare. At this point, we could have defined as many functions as were needed. Finally, there are five statements that set up the window, create the turtle, perform the function invocation, and wait for a user click to terminate the program.
-
These final five statements perform the main processing that the program will do. Notice that much of the detail has been pushed inside the drawSquare function. However, there are still these five lines of code that are needed to get things done.
-
In many programming languages (e.g. Java and C++), it is not possible to simply have statements sitting alone like this at the bottom of the program. They are required to be part of a special function that is automatically invoked by the operating system when the program is executed. This special function is called main. Although this is not required by the Python programming language, it is actually a good idea that we can incorporate into the logical structure of our program. In other words, these five lines are logically related to one another in that they provide the main tasks that the program will perform. Since functions are designed to allow us to break up a program into logical pieces, it makes sense to call this piece main.
The following activecode shows this idea. In line 11 we have defined a new function called main that doesn't need any parameters. The five lines of main processing are now placed inside this function. Finally, in order to execute that main processing code, we need to invoke the main function (line 20). When you push run, you will see that the program works the same as it did before.
-
+
-import turtle
-
-def drawSquare(t, sz):
- """Make turtle t draw a square of with side sz."""
-
- for i in range(4):
- t.forward(sz)
- t.left(90)
+def square(x):
+ y = x * x
+ return y
def main(): # Define the main function
- wn = turtle.Screen() # Set up the window and its attributes
- wn.bgcolor("lightgreen")
-
- alex = turtle.Turtle() # create alex
- drawSquare(alex, 50) # Call the function to draw the square
-
- wn.exitonclick()
+ toSquare = 10
+ squareResult = square(toSquare)
+ print("The result of", toSquare, "squared is", squareResult)
main() # Invoke the main function
-
+
-
Now our program structure is as follows. First, import any modules that will be required. Second, define any functions that will be needed. Third, define a main function that will get the process started. And finally, invoke the main function (which will in turn call the other functions as needed).
+
Now our program structure is as follows. First, import any modules that will be required (you'll read about those in the next chapter). Second, define any functions
+ that will be needed. Third, define a main function that will get the process started. And finally, invoke the main function
+ (which will in turn call the other functions as needed).
In Python there is nothing special about the name main. We could have called this function anything we wanted. We chose main just to be consistent with some of the other languages.
@@ -64,7 +56,7 @@ main() # Invoke the main function
Before the Python interpreter executes your program, it defines a few special variables. One of those variables is called __name__ and it is automatically set to the string value "__main__" when the program is being executed by itself in a standalone fashion. On the other hand, if the program is being imported by another program, then the __name__ variable is set to the name of that module. This means that we can know whether the program is being run by itself or whether it is being used by another program and based on that observation, we may or may not choose to execute some of the code that we have written.
For example, assume that we have written a collection of functions to do some simple math. We can include a main function to invoke these math functions. It is much more likely, however, that these functions will be imported by another program for some other purpose. In that case, we would not want to execute our main function.
The activecode below defines two simple functions and a main.
-
+
def squareit(n):
return n * n
@@ -82,7 +74,4 @@ if __name__ == "__main__":
Line 12 uses an if statement to ask about the value of the __name__ variable. If the value is "__main__", then the main function will be called. Otherwise, it can be assumed that the program is being imported into another program and we do not want to call main because that program will invoke the functions as needed. This ability to conditionally execute our main function can be extremely useful when we are writing code that will potentially be used by others. It allows us to include functionality that the user of the code will not need, most often as part of a testing process to be sure that the functions are working correctly.
-
-
In order to conditionally execute the main function, we used a structure called an if statement to create what is known as selection. This topic will be studied in much more detail later.
What is the most important skill for a computer scientist?
@@ -49,7 +49,7 @@
-
+
An algorithm is:
diff --git a/pretext/GeneralIntro/Comments.ptx b/pretext/GeneralIntro/Comments.ptx
index 8c3159fd1..c9fe4a8ef 100644
--- a/pretext/GeneralIntro/Comments.ptx
+++ b/pretext/GeneralIntro/Comments.ptx
@@ -10,7 +10,7 @@
reader - it is completely ignored by the interpreter.
In Python, the # token starts a comment. The rest of the line is ignored.
Here is a new version of Hello, World!.
-
+
#---------------------------------------------------
# This demo program shows off how elegant Python is!
@@ -28,7 +28,7 @@ print("Hello, World!") # Isn't this easy!
A unique interpreter environment that allows Python to be executed from within a web browser.
- algorithm
A general step by step process for solving a problem.
@@ -20,10 +16,6 @@
modern languages first compile source code into byte code and then
interpret the byte code with a program called a virtual machine.
-
- codelens
-
An interactive environment that allows the user to control the step by step execution of a Python program
- comment
Information in a program that is meant for other programmers (or anyone
diff --git a/pretext/GeneralIntro/MoreAboutPrograms.ptx b/pretext/GeneralIntro/MoreAboutPrograms.ptx
index bfcecddda..3c06b0556 100644
--- a/pretext/GeneralIntro/MoreAboutPrograms.ptx
+++ b/pretext/GeneralIntro/MoreAboutPrograms.ptx
@@ -43,7 +43,7 @@
diff --git a/pretext/GeneralIntro/SpecialWaystoExecutePythoninthisBook.ptx b/pretext/GeneralIntro/SpecialWaystoExecutePythoninthisBook.ptx
index 501724dda..89cab944b 100644
--- a/pretext/GeneralIntro/SpecialWaystoExecutePythoninthisBook.ptx
+++ b/pretext/GeneralIntro/SpecialWaystoExecutePythoninthisBook.ptx
@@ -1,13 +1,13 @@
Executing Python in this Book
-
+
This book provides two special ways to execute Python programs. Both techniques are designed to assist you as you
learn the Python programming language. They will help you increase your understanding of how Python programs work.
First, you can write, modify, and execute programs using a unique activecode interpreter that allows you to execute Python code right
in the text itself (right from the web browser). Although this is certainly not the way real programs are written, it provides an excellent
environment for learning a programming language like Python since you can experiment with the language as you are reading.
-
+
print("My first program adds two numbers, 2 and 3:")
print(2 + 3)
@@ -53,7 +53,7 @@ print(2 + 3)
In codelens you can see and control the step by step progress.
Note that the red arrow always points to the next line of code that is going to be executed.
The light green arrow points to the line that was just executed.
-
+
print("My first program adds two numbers, 2 and 3:")
print(2 + 3)
@@ -65,7 +65,7 @@ print(2 + 3)
Check your understanding
-
+
The activecode interpreter allows you to (select all that apply):
diff --git a/pretext/GeneralIntro/ThePythonProgrammingLanguage.ptx b/pretext/GeneralIntro/ThePythonProgrammingLanguage.ptx
index 237728fcb..33491dac4 100644
--- a/pretext/GeneralIntro/ThePythonProgrammingLanguage.ptx
+++ b/pretext/GeneralIntro/ThePythonProgrammingLanguage.ptx
@@ -34,10 +34,6 @@
executable. Once a program is compiled, you can execute it repeatedly
without further translation.
-
Many modern languages use both processes. They are first compiled into a lower
- level language, called byte code, and then interpreted by a program called
- a virtual machine. Python uses both processes, but because of the way
- programmers interact with it, it is usually considered an interpreted language.
There are two ways to use the Python interpreter: shell mode and program
mode. In shell mode, you type Python expressions into the Python shell,
and the interpreter immediately shows the result. The example below shows the Python shell at work.
@@ -75,20 +71,10 @@ My first program adds two numbers, 2 and 3:
These examples show Python being run from a Unix command line. In other
development environments, the details of executing programs may differ. Also,
most programs are more interesting than this one.
-
- Want to learn more about Python?
-
If you would like to learn more about installing and using Python, here are some video links.
- Installing Python for Windows shows you how to install the Python environment under
- Windows Vista,
- Installing Python for Mac shows you how to install under Mac OS/X, and
- Installing Python for Linux shows you how to install from the Linux
- command line.
- Using Python shows you some details about the Python shell and source code.
-
Check your understanding
-
+
Source code is another name for:
@@ -127,7 +113,7 @@ My first program adds two numbers, 2 and 3:
-
+
What is the difference between a high-level programming language and a low-level programming language?
@@ -168,7 +154,7 @@ My first program adds two numbers, 2 and 3:
-
+
Pick the best replacements for 1 and 2 in the following sentence: When comparing compilers and interpreters, a compiler is like 1 while an interpreter is like 2.
diff --git a/pretext/GeneralIntro/toctree.ptx b/pretext/GeneralIntro/toctree.ptx
index bf79d640a..7458c8409 100644
--- a/pretext/GeneralIntro/toctree.ptx
+++ b/pretext/GeneralIntro/toctree.ptx
@@ -11,9 +11,8 @@
4
4
4
-4
4
4
+4
4
-4
diff --git a/pretext/IntroRecursion/CalculatingtheSumofaListofNumbers.ptx b/pretext/IntroRecursion/CalculatingtheSumofaListofNumbers.ptx
index a5ceb8a32..a3e867a89 100644
--- a/pretext/IntroRecursion/CalculatingtheSumofaListofNumbers.ptx
+++ b/pretext/IntroRecursion/CalculatingtheSumofaListofNumbers.ptx
@@ -8,7 +8,7 @@
is shown below. The function uses an accumulator variable
(theSum) to compute a running total of all the numbers in the list
by starting with and adding each number in the list.
-
+
def listsum(numList):
theSum = 0
@@ -51,7 +51,7 @@ total = \ 25
In this equation returns the first element of
the list and returns a list of everything but
the first element. This is easily expressed in Python.
Write a function that takes a string as a parameter and returns a new string that is the reverse of the old string.
-
+
from test import testEqual
def reverse(s):
@@ -134,7 +134,7 @@ testEqual(reverse(""),"")
-
+
from test import testEqual
def removeWhite(s):
diff --git a/pretext/IntroRecursion/ProgrammingExercises.ptx b/pretext/IntroRecursion/ProgrammingExercises.ptx
index 13afd1da1..f0aa6dbe5 100644
--- a/pretext/IntroRecursion/ProgrammingExercises.ptx
+++ b/pretext/IntroRecursion/ProgrammingExercises.ptx
@@ -54,123 +54,43 @@ myTests().main()
-
-
Modify the recursive tree program using one or all of the following
- ideas:
-
-
-
-
Modify the thickness of the branches so that as the branchLen
- gets smaller, the line gets thinner.
-
-
-
Modify the color of the branches so that as the branchLen gets
- very short it is colored like a leaf.
-
-
-
Modify the angle used in turning the turtle so that at each branch
- point the angle is selected at random in some range. For example
- choose the angle between 15 and 45 degrees. Play around to see
- what looks good.
-
-
-
Modify the branchLen recursively so that instead of always
- subtracting the same amount you subtract a random amount in some
- range.
-
-
-
-
If you implement all of the above ideas you will have a very
- realistic looking tree.
-
-
-
-
-
-
-
-
-
-
Find or invent an algorithm for drawing a fractal mountain. Hint: One
- approach to this uses triangles again.
-
-
-
-
-
-
-
-
Write a recursive function to compute the Fibonacci sequence. How
does the performance of the recursive function compare to that of an
iterative version?
-
-
-
-
-
-
-
-
-
Implement a solution to the Tower of Hanoi using three stacks to keep
- track of the disks.
-
-
-
-
-
-
-
-
-
-
Using the turtle graphics module, write a recursive program to
- display a Hilbert curve.
-
-
-
-
-
-
-
-
-
-
Using the turtle graphics module, write a recursive program to
- display a Koch snowflake.
-
-
+
-
+
Write a program to solve the following problem: You have two jugs: a
4-gallon jug and a 3-gallon jug. Neither of the jugs have markings on
them. There is a pump that can be used to fill the jugs with water.
How can you get exactly two gallons of water in the 4-gallon jug?
-
+
-
+
Generalize the problem above so that the parameters to your solution
include the sizes of each jug and the final amount of water to be
left in the larger jug.
-
+
-
+
Write a program that solves the following problem: Three missionaries
and three cannibals come to a river and find a boat that holds two
@@ -180,25 +100,25 @@ myTests().main()
crossings that will get everyone safely to the other side of the
river.
-
+
-
+
Modify the Tower of Hanoi program using turtle graphics to animate
the movement of the disks. Hint: You can make multiple turtles and
have them shaped like rectangles.
-
+
-
+
Pascal's triangle is a number triangle with numbers arranged in
staggered rows such that
@@ -218,7 +138,7 @@ myTests().main()
should accept a parameter that tells how many rows of the triangle to
print.
-
+
diff --git a/pretext/IntroRecursion/TheThreeLawsofRecursion.ptx b/pretext/IntroRecursion/TheThreeLawsofRecursion.ptx
index 9d4bddde1..14c0b1365 100644
--- a/pretext/IntroRecursion/TheThreeLawsofRecursion.ptx
+++ b/pretext/IntroRecursion/TheThreeLawsofRecursion.ptx
@@ -44,9 +44,12 @@
In the remainder of this chapter we will look at more examples of
recursion. In each case we will focus on designing a solution to a
problem by using the three laws of recursion.
-
- Self Check
-
+
+
+ Check your understanding
+
+
+
How many recursive calls are made when computing the sum of the list [2,4,6,8,10]?
@@ -85,7 +88,7 @@
-
+
Suppose you are going to write a recusive function to calculate the factorial of a number. fact(n) returns n * n-1 * n-2 * … * 1, and the factorial of zero is definded to be 1. What would be the most appropriate base case?
+
+
+
diff --git a/pretext/MoreAboutIteration/2DimensionalIterationImageProcessing.ptx b/pretext/Iteration/2DimensionalIterationImageProcessing.ptx
similarity index 99%
rename from pretext/MoreAboutIteration/2DimensionalIterationImageProcessing.ptx
rename to pretext/Iteration/2DimensionalIterationImageProcessing.ptx
index 8e2da7033..f862b0e52 100644
--- a/pretext/MoreAboutIteration/2DimensionalIterationImageProcessing.ptx
+++ b/pretext/Iteration/2DimensionalIterationImageProcessing.ptx
@@ -499,7 +499,7 @@ for i in range(5):
Another way to see this in more detail is to examine the behavior with codelens. Step through the iterations to see the
flow of control as it occurs with the nested iteration. Again, for every value of i, all of the values of j will occur. You can see that the inner iteration completes before going on to the next pass of the outer iteration.
-
+
for i in range(5):
for j in range(3):
diff --git a/pretext/MoreAboutIteration/AlgorithmsRevisited.ptx b/pretext/Iteration/AlgorithmsRevisited.ptx
similarity index 100%
rename from pretext/MoreAboutIteration/AlgorithmsRevisited.ptx
rename to pretext/Iteration/AlgorithmsRevisited.ptx
diff --git a/pretext/Iteration/BreakAndContinue.ptx b/pretext/Iteration/BreakAndContinue.ptx
new file mode 100644
index 000000000..e6068f9d0
--- /dev/null
+++ b/pretext/Iteration/BreakAndContinue.ptx
@@ -0,0 +1,40 @@
+
+
+ break and continue
+
+
In loops, we sometimes want to traverse until we reach a certain value.
+ We could make a loop condition with a boolean that is toggled as True once we
+ reach that value, but there's an easier way: the break statement.
+
+
When a break statement is reached, the loop immediately ends and proceeds with the code after the loop.
+ break is only a valid statement inside of loops, such as the following:
+
+
+
+i = 0
+while i < 10:
+ if i == 5:
+ break
+ print(i)
+ i += 1
+
+
+
+
The continue statement is another keyword that we can use in loops.
+ When a continue statement is reached, the current iteration is stopped (similar to break),
+ however, the loop will continue running for all iterations after the current one.
+
+
+
+i = 0
+while i < 10:
+ if i == 5:
+ continue
+ print(i)
+ i += 1
+
+
+
+
Notice the difference between the activecode example above for break and this example with continue.
+ Neither loop prints 5, but in the loop with continue, it continues iterating after where 5 would have been.
Write code that calculates and prints the first
+ 5 triangular numbers. It should
+ produce the following output:
+
1 1
+2 3
+3 6
+4 10
+5 15
+
(hint: use a web search to find out what a triangular number is.)
+
+
+ # your code here
+
+
+
+
diff --git a/pretext/Iteration/FlowofExecutionofthewhileLoop.ptx b/pretext/Iteration/FlowofExecutionofthewhileLoop.ptx
new file mode 100644
index 000000000..eef5fe495
--- /dev/null
+++ b/pretext/Iteration/FlowofExecutionofthewhileLoop.ptx
@@ -0,0 +1,20 @@
+
+
+ Flow of Execution of the while Loop
+
As before with if, loops allow us as programmers to manipulate the control flow of a Python program.
+ We can now possibly skip a portion of code, or choose to repeat it an indefinite number of times.
+
The flowchart below provides the general sequence of steps that govern execution of a while loop.
+
+
A codelens demonstration is a good way to help you visualize exactly how the flow of control
+ works with the while loop. Try stepping forward and backward through the program by pressing
+ the buttons. You can see the value of count change as the loop iterates through the values from 10 to 0.
A loop inside the body of another loop. We will work more on nested loops in Chapter 10.
newline
@@ -79,6 +79,11 @@
tab
A special character that causes the cursor to move to the next tab stop
on the current line.
+
+
+ traverse
+
To iterate through the elements of a collection, performing a similar
+ operation on each.
diff --git a/pretext/MoreAboutIteration/ImageProcessingonYourOwn.ptx b/pretext/Iteration/ImageProcessingonYourOwn.ptx
similarity index 100%
rename from pretext/MoreAboutIteration/ImageProcessingonYourOwn.ptx
rename to pretext/Iteration/ImageProcessingonYourOwn.ptx
diff --git a/pretext/Lists/Listsandforloops.ptx b/pretext/Iteration/Listsandforloops.ptx
similarity index 85%
rename from pretext/Lists/Listsandforloops.ptx
rename to pretext/Iteration/Listsandforloops.ptx
index 0d84e038d..b3d7b04b2 100644
--- a/pretext/Lists/Listsandforloops.ptx
+++ b/pretext/Iteration/Listsandforloops.ptx
@@ -1,8 +1,8 @@
-
- Lists and for loops
-
It is also possible to perform list traversal using iteration by item as well as iteration by index.
-
+
+ Traversing lists with the for loop
+
It is possible to perform list traversal using iteration by item as well as iteration by index.
+
fruits = ["apple", "orange", "banana", "cherry"]
@@ -13,7 +13,7 @@ for afruit in fruits: # by item
It almost reads like natural language: For (every) fruit in (the list of) fruits,
print (the name of the) fruit.
We can also use the indices to access the items in an iterative fashion.
-
+
fruits = ["apple", "orange", "banana", "cherry"]
@@ -25,7 +25,7 @@ for position in range(len(fruits)): # by index
list, printing the position-eth element. Note that we used len as the upper bound on the range
so that we can iterate correctly no matter how many items are in the list.
Any sequence expression can be used in a for loop. For example, the range function returns a sequence of integers.
-
+
for number in range(20):
if number % 3 == 0:
@@ -36,7 +36,7 @@ for number in range(20):
Since lists are mutable, it is often desirable to traverse a list, modifying
each of its elements as you go. The following code squares all the numbers from 1 to
5 using iteration by position.
diff --git a/pretext/MoreAboutIteration/NewtonsMethod.ptx b/pretext/Iteration/NewtonsMethod.ptx
similarity index 71%
rename from pretext/MoreAboutIteration/NewtonsMethod.ptx
rename to pretext/Iteration/NewtonsMethod.ptx
index e4c677c9c..37de5498f 100644
--- a/pretext/MoreAboutIteration/NewtonsMethod.ptx
+++ b/pretext/Iteration/NewtonsMethod.ptx
@@ -21,21 +21,21 @@ better = 1/2 * (approx + n/approx)
calculation yielding a better result.
-def newtonSqrt(n, howmany):
- approx = 0.5 * n
- for i in range(howmany):
- betterapprox = 0.5 * (approx + n/approx)
- approx = betterapprox
- return betterapprox
+n = 100
+howmany = 10
-print(newtonSqrt(100, 10))
-print(newtonSqrt(4, 10))
-print(newtonSqrt(1, 10))
+approx = 0.5 * n
+for i in range(howmany):
+ betterapprox = 0.5 * (approx + n/approx)
+ approx = betterapprox
+prin(betterapprox)
Modify the program …
-
All three of the calls to newtonSqrt in the previous example produce the correct square root for the first parameter. However, were 10 iterations required to get the correct answer? Experiment with different values for the number of repetitions (the 10 on lines 8, 9, and 10). For each of these calls, find the smallest value for the number of repetitions that will produce the correct result.
+
The values used in the previous example produce the correct square root for 100. However, were 10 iterations required to get the correct answer?
+ Experiment with different values for the number of repetitions (howmany on line 2). Find the smallest value for the number of
+ repetitions that will produce the correct result.
Repeating more than the required number of times is a waste of computing resources. So definite iteration is not a good solution to this problem.
In general, Newton's algorithm will eventually reach a point where the new approximation is no better than the previous. At that point, we could simply stop.
@@ -43,17 +43,15 @@ print(newtonSqrt(1, 10))
enough to the previous one, we can write a function for computing the square root that uses the number of iterations necessary and no more.
This implementation, shown in codelens,
uses a while condition to execute until the approximation is no longer changing. Each time through the loop we compute a better approximation using the formula described earlier. As long as the better is different, we try again. Step through the program and watch the approximations get closer and closer.
Indefinite loops are much more common in the real world than definite loops.
+
The indefinite loops provided by the while statement are common in the real world.
@@ -53,26 +53,23 @@
We don't have a little plastic bar data type in Python, so we'll do the next best thing: we
will use a price of zero to mean this is my last item. In this program,
zero is a sentinel value, a value used to signal the end of the loop. Here's the code:
-
+
-def checkout():
- total = 0
- count = 0
- moreItems = True
- while moreItems:
- price = float(input('Enter price of item (0 when done): '))
- if price != 0:
+ total = 0
+ count = 0
+ moreItems = True
+ while moreItems:
+ price = float(input('Enter price of item (0 when done): '))
+ if price != 0:
count = count + 1
total = total + price
print('Subtotal: $', total)
- else:
+ else:
moreItems = False
- average = total / count
- print('Total items:', count)
- print('Total $', total)
- print('Average price per item: $', average)
-
-checkout()
+ average = total / count
+ print('Total items:', count)
+ print('Total $', total)
+ print('Average price per item: $', average)
There are still a few problems with this program.
@@ -89,67 +86,63 @@ checkout()
division by zero and tell the user that you can't compute an average without data.
-
This program doesn't display the amounts to two decimal places. In the next chapter you will
- see the that will do the trick.
-
- Check your understanding
-
-
-
-
True or False: A while loop will continue to iterate forever unless it meets a condition to stop.
-
-
-
-
-
True
-
-
- Keep in mind there are multiple ways to stop a while loop, such as a sentinal value.
-
-
-
-
-
False
-
-
- While loops do not have a set number of times they will iterate, so they will continue until something breaks the loop. Keep this in mind while coding with while loops.
-
-
-
-
+
This program doesn't display the amounts to two decimal places. Thankfully, you already know how to fix this issue.
+ Recall how you learned to format floats to a specific number of decimal points in .
+
+ Check your understanding
+
+
+
+
True or False: A while loop will continue to iterate forever unless it meets a condition to stop.
+
+
+
+
+
True
+
+
+ Keep in mind there are multiple ways to stop a while loop, such as a sentinal value.
+
+
+
+
+
False
+
+
+ While loops do not have a set number of times they will iterate, so they will continue until something breaks the loop. Keep this in mind while coding with while loops.
+
+
+
+
-
+ Validating Input
You can also use a while loop when you want to validate input; when you want to make
sure the user has entered valid input for a prompt. Let's say you want a function
that asks a yes-or-no question. In this case, you want to make sure that the person using
your program enters either a Y for yes or N for no (in either upper or lower case).
Here is a program that uses a while loop to keep asking until it receives a valid answer.
- As a preview of coming attractions, it uses
+ Note that it uses
the upper() method which is described in to convert a string to upper case.
When you run the following code, try typing something other than Y or N to see how the code reacts:
-
+
-def get_yes_or_no(message):
- valid_input = False
- answer = input(message)
- while not valid_input:
- answer = answer.upper() # convert to upper case
- if answer == 'Y' or answer == 'N':
+ valid_input = False
+ response = input('Do you like lima beans? Y)es or N)o: ')
+ while not valid_input:
+ response = response.upper() # convert to upper case
+ if response == 'Y' or response == 'N':
valid_input = True
+ else:
+ response = input('Please enter Y for yes or N for no. \n' + message)
+ if response == 'Y':
+ print('Great! They are very healthy.')
else:
- answer = input('Please enter Y for yes or N for no. \n' + message)
- return answer
-
-response = get_yes_or_no('Do you like lima beans? Y)es or N)o: ')
-if response == 'Y':
- print('Great! They are very healthy.')
-else:
- print('Too bad. If cooked right, they are quite tasty.')
-
+ print('Too bad. If cooked right, they are quite tasty.')
+
diff --git a/pretext/MoreAboutIteration/SimpleTables.ptx b/pretext/Iteration/SimpleTables.ptx
similarity index 100%
rename from pretext/MoreAboutIteration/SimpleTables.ptx
rename to pretext/Iteration/SimpleTables.ptx
diff --git a/pretext/MoreAboutIteration/The3n1Sequence.ptx b/pretext/Iteration/The3n1Sequence.ptx
similarity index 83%
rename from pretext/MoreAboutIteration/The3n1Sequence.ptx
rename to pretext/Iteration/The3n1Sequence.ptx
index 1b7602f41..53cb7d31c 100644
--- a/pretext/MoreAboutIteration/The3n1Sequence.ptx
+++ b/pretext/Iteration/The3n1Sequence.ptx
@@ -1,27 +1,26 @@
-
+The 3n + 1 Sequence
-
As another example of indefinite iteration, let's look at a sequence that has fascinated mathematicians for many years.
+
As another example of iteration with while, let's look at a sequence that has fascinated mathematicians for many years.
The rule for creating the sequence is to start from
some positive integer, call it n, and to generate
the next term of the sequence from n, either by halving n,
whenever n is even, or else by multiplying it by three and adding 1 when it is odd. The sequence
terminates when n reaches 1.
-
This Python function captures that algorithm. Try running this program several times supplying different values for n.
-
+
This Python code captures that algorithm. Try running this program several times supplying different values for n.
+
-def seq3np1(n):
- """ Print the 3n+1 sequence from n, terminating when it reaches 1."""
- while n != 1:
+ n = 3
+
+ """ Print the 3n+1 sequence from n, terminating when it reaches 1."""
+ while n != 1:
print(n)
if n % 2 == 0: # n is even
- n = n // 2
+ n = n // 2
else: # n is odd
- n = n * 3 + 1
- print(n) # the last print is 1
-
-seq3np1(3)
-
+ n = n * 3 + 1
+ print(n) # the last print is 1
+
The condition for this loop is n != 1. The loop will continue running until
n == 1 (which will make the condition false).
@@ -36,16 +35,7 @@ seq3np1(3)
time through the loop until it reaches 1.
You might like to have some fun and see if you can find a small starting
number that needs more than a hundred steps before it terminates.
-
- Lab
-
-
-
-
Experimenting with the 3n+1 Sequence In this guided lab exercise we will try to learn more about this sequence.
-
-
-
-
+
Particular values aside, the interesting question is whether we can prove that
this sequence terminates for all positive values of n. So far, no one has been able
to prove it or disprove it!
@@ -57,7 +47,7 @@ seq3np1(3)
You'll notice that if you don't stop when you reach one, the sequence gets into
its own loop: 1, 4, 2, 1, 4, 2, 1, 4, and so on. One possibility is that there might
be other cycles that we just haven't found.
-
+
-
+
Check your understanding
-
+
Consider the code that prints the 3n+1 sequence in ActiveCode box 6. Will the while loop in this code always terminate for any positive integer value of n?
diff --git a/pretext/Iteration/TheforLoop.ptx b/pretext/Iteration/TheforLoop.ptx
new file mode 100644
index 000000000..8efd54db4
--- /dev/null
+++ b/pretext/Iteration/TheforLoop.ptx
@@ -0,0 +1,87 @@
+
+
+ The for loop
+
The while statement is a general-purpose tool for iteration, and is necessary for any instance of iteration where we don't know how many repetitions will be needed.
+However, if we do know how many are needed, there is a more efficient approach: the for statement.
+
As a simple example, let's say we have some friends, and
+we'd like to send them each an email inviting them to our party. We
+don't quite know how to send email yet, so for the moment we'll just print a
+message for each friend.
+
+
+ for name in ["Joe", "Amy", "Brad", "Angelina", "Zuki", "Thandi", "Paris"]:
+ print(f"Hi {name}! Please come to my party on Saturday!")
+
+
+
Take a look at the output produced when you press the run button. There is one line printed for each friend. Here's how it works:
+
+
name is the loop variable in this case.
+
Frustratingly, in here is not the same as the keyword used to check for membership. This just a necessary part of every for loop construction and not an operator.
+
The list of names in the square brackets is a regular list. Later we'll see that other types besides lists can be put in this spot.
+
Line 2 is the loop body. Like with while, the loop body is always indented. The loop body is performed one time for each name in the list.
+
On each iteration or pass of the loop, a check is done to see if
+ there are still more items to be processed. If there are none left (this is
+ called the terminating condition of the loop), the loop has finished.
+ Program execution continues at the next statement after the loop body.
+
If there are items still to be processed, the loop variable is updated to
+ refer to the next item in the list. This means, in this case, that the loop
+ body is executed here 7 times, and each time name will refer to a different
+ friend.
+
At the end of each execution of the body of the loop, Python returns
+ to the for statement, to see if there are more items to be handled.
+
+
+
+
Introduction of the for statement causes us to think about the types of iteration we have seen. The for statement will always iterate through a sequence of
+ values like the list of names for the party.
+
Since we know that it will iterate once for each value in the collection, it is often said that a for loop creates a
+ definite iteration because we definitely know how many times we are going to iterate. On the other
+ hand, the while statement is dependent on a condition that needs to evaluate to False in order
+ for the loop to terminate. Since we do not necessarily know when this will happen, it creates what we
+ call indefinite iteration. Indefinite iteration simply means that we don't know how many times we will repeat but eventually the condition
+ controlling the iteration will fail and the iteration will stop. (Unless we have an infinite loop which is of course a problem.)
+
+
+
+ Choosing between for and while
+
Use a for loop if you know the maximum number of times that you'll
+ need to execute the body. For example, if you're traversing a list of elements,
+ or can formulate a suitable call to range, then choose the for loop.
+
So any problem like "iterate this weather model run for 1000 cycles", or "search this
+ list of words", "check all integers up to 10000 to see which are prime" suggest that a for loop is best.
+
By contrast, if you are required to repeat some computation until some condition is
+ met, as we did in the 3n + 1 problem last week, you'll need a while loop.
+
+
+
What you will notice here is that the while loop is more work for
+you --- the programmer --- than the equivalent for loop. When using a while
+loop you have to control the loop variable yourself. You give it an initial value, test
+for completion, and then make sure you change something in the body so that the loop
+terminates.
+
+ Check your understanding
+
+
+
+
True or False: You can rewrite any for-loop as a while-loop.
+
+
+
+
+
True
+
+
+ The syntax for a for-loop can make it easier and more appealing, but a while loop is just as powerful as a for-loop and often more flexible.
+
+
+
+
+
False
+
+
+ Often a for-loop is more natural and convenient for a task, but that same task can always be expressed using a while loop.
+
+
+
+
+
diff --git a/pretext/MoreAboutIteration/Theforlooprevisited.ptx b/pretext/Iteration/Theforlooprevisited.ptx
similarity index 100%
rename from pretext/MoreAboutIteration/Theforlooprevisited.ptx
rename to pretext/Iteration/Theforlooprevisited.ptx
diff --git a/pretext/PythonTurtle/TherangeFunction.ptx b/pretext/Iteration/TherangeFunction.ptx
similarity index 88%
rename from pretext/PythonTurtle/TherangeFunction.ptx
rename to pretext/Iteration/TherangeFunction.ptx
index 1c79cedd4..d646ee538 100644
--- a/pretext/PythonTurtle/TherangeFunction.ptx
+++ b/pretext/Iteration/TherangeFunction.ptx
@@ -1,24 +1,11 @@
-
+The range Function
-
-
In our simple example from the last section (shown again below), we used a list of four integers to cause the iteration
- to happen four times. We said that we could have used any four values. In fact, we even used four colors.
-
-
-import turtle # set up alex
-wn = turtle.Screen()
-alex = turtle.Turtle()
-
-for i in [0, 1, 2, 3]: # repeat four times
- alex.forward(50)
- alex.left(90)
-
-wn.exitonclick()
-
-
+
+
In our first example of a while loop, we counted down from 10 to 0. If we were to consider doing this with a for loop, we would need to construct our own series of numbers
+ to loop through them.
It turns out that generating lists with a specific number of integers is a very common thing to do, especially when you
- want to write simple for loop controlled iteration. Even though you can use any four items, or any four integers for that matter, the conventional thing to do is to use a list of integers starting with 0.
+ want to write simple for loop controlled iteration. Even though you can use any four items, or any four integers for that matter, the conventional thing to do is to use a list of integers starting with 0.
In fact, these lists are so popular that Python gives us special built-in
range objects
that can deliver a sequence of values to
@@ -37,9 +24,8 @@ for x in range(10):
So to repeat something four times, a good Python programmer would do this:
-for i in range(4):
- alex.forward(50)
- alex.left(90)
+ for i in range(4):
+ #do something
The range function is actually a very powerful function
@@ -64,14 +50,14 @@ for i in range(4):
The range function is lazy: It produces the next element only when needed.
With a regular Python 3 interpreter, printing a range does not calculate all the elements.
To immediately calculate all the elements in a range,
- wrap the range in a list, like list(range(4)).
+ convert the range object to a list, like list(range(4)).
Activecode is not designed to work on very long sequences, and it may allow you to be
sloppy, avoiding the list function, and see the elements in the range with print(range(4)).
Here are two examples for you to run. Try them and then add another line below to create a sequence starting
at 10 and going up to 20 (including 20).
Codelens will help us to further understand the way range works. In this case, the variable i will take on values
produced by the range function.
-
+
for i in range(10):
print(i)
@@ -92,7 +78,7 @@ print(list(range(1, 5)))
range(0,19,2). The most general form of the range is
range(start, beyondLast, step). You can also create a sequence of numbers that
starts big and gets smaller by using a negative value for the step parameter.
-
+
print(list(range(0, 19, 2)))
print(list(range(0, 20, 2)))
@@ -100,7 +86,7 @@ print(list(range(10, 0, -1)))
Try it in codelens. Do you see why the first two statements produce the same result?
-
+
for i in range(0, 20, 2):
print(i)
@@ -109,7 +95,7 @@ for i in range(0, 20, 2):
Check your understanding
-
+
In the command range(3, 10, 2), what does the second argument (10) specify?
@@ -148,7 +134,7 @@ for i in range(0, 20, 2):
-
+
What command correctly generates the sequence 2, 5, 8?
@@ -187,7 +173,7 @@ for i in range(0, 20, 2):
-
+
What happens if you give range only one argument? For example: range(4)
@@ -226,7 +212,7 @@ for i in range(0, 20, 2):
-
+
Which range function call will produce the sequence 20, 15, 10, 5?
@@ -265,7 +251,7 @@ for i in range(0, 20, 2):
-
+
What could the second parameter (12) in range(2, 12, 4) be replaced with and generate exactly the same sequence?
diff --git a/pretext/MoreAboutIteration/ThewhileStatement.ptx b/pretext/Iteration/ThewhileStatement.ptx
similarity index 53%
rename from pretext/MoreAboutIteration/ThewhileStatement.ptx
rename to pretext/Iteration/ThewhileStatement.ptx
index 1a9d87cf7..72fca7571 100644
--- a/pretext/MoreAboutIteration/ThewhileStatement.ptx
+++ b/pretext/Iteration/ThewhileStatement.ptx
@@ -1,75 +1,52 @@
-
+The while Statement
-
-
There is another Python statement that can also be used to build an iteration. It is called the while statement.
- The while statement provides a much more general mechanism for iterating. Similar to the if statement, it uses
- a boolean expression to control the flow of execution. The body of while will be repeated as long as the controlling boolean expression evaluates to True.
-
-
The following figure shows the flow of control.
-
-
We can use the while loop to create any type of iteration we wish, including anything that we have previously done with a for loop. For example, the program in the previous section could be rewritten using while.
- Instead of relying on the range function to produce the numbers for our summation, we will need to produce them ourselves. To to this, we will create a variable called aNumber and initialize it to 1, the first number in the summation. Every iteration will add aNumber to the running total until all the values have been used.
- In order to control the iteration, we must create a boolean expression that evaluates to True as long as we want to keep adding values to our running total. In this case, as long as aNumber is less than or equal to the bound, we should keep going.
-
Here is a new version of the summation program that uses a while statement.
-
+
+
Let's look at our first Python statement that can be used to build an iteration. It is called the while statement. When used with other code it can be used to
+ repeat code in a while loop. Similar to the if statement, it uses
+ a boolean expression to control the flow of execution. The body of while (code indented one space in) will be repeated as long as the controlling boolean
+ expression evaluates to True.
+
Here is a simple example that counts down from 10 to 0.
You can almost read the while statement as if it were in natural language. It means,
- while aNumber is less than or equal to aBound, continue executing the body of the loop. Within
- the body, each time, update theSum using the accumulator pattern and increment aNumber. After the body of the loop, we go back up to the condition of the while and reevaluate it. When aNumber becomes greater than aBound, the condition fails and flow of control continues to the return statement.
-
The same program in codelens will allow you to observe the flow of execution.
-
-
-def sumTo(aBound):
- """ Return the sum of 1+2+3 ... n """
-
- theSum = 0
- aNumber = 1
- while aNumber <= aBound:
- theSum = theSum + aNumber
- aNumber = aNumber + 1
- return theSum
-print(sumTo(4))
-
-
-
More formally, here is the flow of execution for a while statement:
-
-
-
Evaluate the condition, yielding False or True.
-
-
-
-
If the condition is False, exit the while statement and continue
- execution at the next statement.
-
-
-
If the condition is True, execute each of the statements in the body and
- then go back to step 1.
-
-
+
+
count is a normal variable here, but since it is governing the while loop it is also called the loop variable.
+
+
+
Line 2 here is the loop condition. It must always be a boolean expression that will evaluate to False or True.
+
+
+
Lines 3 and 4 are the loop body. The loop body is always
+ indented. The indentation determines exactly what statements are "in the
+ loop". The loop body is run each time the loop is repeated.
+
+
+
On each iteration or pass of the loop, a check is done to see if
+ the loop condition is True (if count is greater than zero). If it is not (this is
+ called the terminating condition of the loop), the loop has finished.
+ Program execution continues at the next statement after the loop body.
+
+
+
If count is greater than zero, the loop body is executed again.
+
+
+
At the end of each execution of the body of the loop, Python returns
+ to the while statement, to see if the loop should repeat.
+
-
The body consists of all of the statements below the header with the same
- indentation.
-
This type of flow is called a loop because the third step loops back around
- to the top. Notice that if the condition is False the first time through the
- loop, the statements inside the loop are never executed.
+
+
Notice that if the condition is False the first time through the
+ loop, the statements inside the loop are never executed.
+
Though Python's while is very close to the English while,
there is an important difference: In English while X, do Y,
@@ -78,34 +55,62 @@ print(sumTo(4))
initial test, any following tests come only after the execution of
the whole body, even if the condition becomes false in the middle of the loop body.
+
The body of the loop should change the value of one or more variables so that
eventually the condition becomes False and the loop terminates. Otherwise the
loop will repeat forever. This is called an infinite loop.
An endless
source of amusement for computer scientists is the observation that the
directions written on the back of the shampoo bottle (lather, rinse, repeat) create an infinite loop.
+
+
We can use the while loop to create any type of iteration we wish, making it more general-purpose than the for loop we'll learn next week.
+ For example, let us consider a program that adds all numbers from 1 to n. To do this, we will create a variable called aNumber and initialize it to
+ 1, the first number in the summation. Every iteration will add aNumber to the running total until all the values have been used.
+ In order to control the iteration, we must create a boolean expression that evaluates to True as long as we want to keep adding values to our
+ running total. In this case, as long as aNumber is less than or equal to the bound, we should keep going.
+
+
Here is the summation program that uses a while statement.
+
+
+
+ """ Return the sum of 1+2+3 ... n """
+ aBound = int(input("Please give a number n: "))
+ theSum = 0
+ aNumber = 1
+ while aNumber <= aBound:
+ theSum = theSum + aNumber
+ aNumber = aNumber + 1
+ print(theSum)
+
+
+
+
You can almost read the while statement as if it were in natural language. It means,
+ while aNumber is less than or equal to aBound, continue executing the body of the loop. Within
+ the body, each time, update theSum using the accumulator pattern and increment aNumber. After the body of the loop, we go back up to the condition of the while and reevaluate it. When aNumber becomes greater than aBound, the condition fails and flow of control continues to the return statement.
+
+
+
In the case shown above, we can prove that the loop terminates because we
know that the value of aBound is finite, and we can see that the value of aNumber
increments each time through the loop, so eventually it will have to exceed aBound. In
other cases, it is not so easy to tell.
-
-
Introduction of the while statement causes us to think about the types of iteration we have seen. The for statement will always iterate through a sequence of values like the list of names for the party or the list of numbers created by range. Since we know that it will iterate once for each value in the collection, it is often said that a for loop creates a
- definite iteration because we definitely know how many times we are going to iterate. On the other
- hand, the while statement is dependent on a condition that needs to evaluate to False in order
- for the loop to terminate. Since we do not necessarily know when this will happen, it creates what we
- call indefinite iteration. Indefinite iteration simply means that we don't know how many times we will repeat but eventually the condition controlling the iteration will fail and the iteration will stop. (Unless we have an infinite loop which is of course a problem.)
-
-
What you will notice here is that the while loop is more work for
- you — the programmer — than the equivalent for loop. When using a while
- loop you have to control the loop variable yourself. You give it an initial value, test
- for completion, and then make sure you change something in the body so that the loop
- terminates.
-
So why have two kinds of loop if for looks easier? The next section,
-, shows an indefinite iteration where
- we need the extra power that we get from the while loop.
+
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
-
+
@@ -115,7 +120,7 @@ print(sumTo(4))
Check your understanding
-
+
True or False: You can rewrite any for-loop as a while-loop.
@@ -138,7 +143,7 @@ print(sumTo(4))
-
+
The following code contains an infinite loop. Which is the best explanation for why the loop does not terminate?
@@ -187,7 +192,7 @@ print(answer)
-
+
What is printed by this code?
diff --git a/pretext/Strings/TraversalandtheforLoopByIndex.ptx b/pretext/Iteration/TraversalandtheforLoopByIndex.ptx
similarity index 89%
rename from pretext/Strings/TraversalandtheforLoopByIndex.ptx
rename to pretext/Iteration/TraversalandtheforLoopByIndex.ptx
index baaa97702..74f053802 100644
--- a/pretext/Strings/TraversalandtheforLoopByIndex.ptx
+++ b/pretext/Iteration/TraversalandtheforLoopByIndex.ptx
@@ -1,11 +1,11 @@
-
- Traversal and the for Loop: By Index
+
+ Traversing strings with the for Loop: By Index
It is also possible to use the range function to systematically generate the indices of the characters. The for loop can then be used to iterate over these positions.
These positions can be used together with the indexing operator to access the individual
characters in the string.
Consider the following codelens example.
-
+
fruit = "apple"
for idx in range(5):
@@ -17,7 +17,7 @@ for idx in range(5):
of the characters.
In order to make the iteration more general, we can use the len function to provide the bound for range. This is a very common pattern for traversing any sequence by position. Make sure you understand why the range function behaves
correctly when using len of the string as its parameter value.
-
+
fruit = "apple"
for idx in range(len(fruit)):
@@ -27,7 +27,7 @@ for idx in range(len(fruit)):
You may also note that iteration by position allows the programmer to control the direction of the
traversal by changing the sequence of index values. Recall that we can create ranges that count down as
well as up so the following code will print the characters from right to left.
-
+
fruit = "apple"
for idx in range(len(fruit)-1, -1, -1):
@@ -38,7 +38,7 @@ for idx in range(len(fruit)):
Check your understanding
-
+
How many times is the letter o printed by the following statements?
diff --git a/pretext/Strings/TraversalandtheforLoopByItem.ptx b/pretext/Iteration/TraversalandtheforLoopByItem.ptx
similarity index 85%
rename from pretext/Strings/TraversalandtheforLoopByItem.ptx
rename to pretext/Iteration/TraversalandtheforLoopByItem.ptx
index 55ae76d80..3eed094f8 100644
--- a/pretext/Strings/TraversalandtheforLoopByItem.ptx
+++ b/pretext/Iteration/TraversalandtheforLoopByItem.ptx
@@ -1,31 +1,31 @@
-
- Traversal and the for Loop: By Item
+
+ Traversing strings with the for Loop: By Item
A lot of computations involve processing a collection one item at a time. For strings this means
that we would like to process one character at a time.
Often we start at the beginning, select each character in turn, do something
to it, and continue until the end. This pattern of processing is called a
traversal.
We have previously seen that the for statement can iterate over the items of a sequence (a list of names in the case below).
-
+
-for aname in ["Joe", "Amy", "Brad", "Angelina", "Zuki", "Thandi", "Paris"]:
- invitation = "Hi " + aname + ". Please come to my party on Saturday!"
+for name in ["Joe", "Amy", "Brad", "Angelina", "Zuki", "Thandi", "Paris"]:
+ invitation = "Hi " + name + ". Please come to my party on Saturday!"
print(invitation)
Recall that the loop variable takes on each value in the sequence of names. The body is performed once for each name. The same was true for the sequence of integers created by the range function.
-
+
-for avalue in range(10):
- print(avalue)
+for value in range(10):
+ print(value)
Since a string is simply a sequence of characters, the for loop iterates over each character automatically.
-
+
-for achar in "Go Spot Go":
- print(achar)
+for char in "Go Spot Go":
+ print(char)
The loop variable achar is automatically reassigned each character in the string Go Spot Go.
@@ -34,7 +34,7 @@ for achar in "Go Spot Go":
Check your understanding
-
+
How many times is the word HELLO printed by the following statements?
@@ -80,7 +80,7 @@ for ch in s:
-
+
How many times is the word HELLO printed by the following statements?
diff --git a/pretext/Strings/TraversalandthewhileLoop.ptx b/pretext/Iteration/TraversalandthewhileLoop.ptx
similarity index 83%
rename from pretext/Strings/TraversalandthewhileLoop.ptx
rename to pretext/Iteration/TraversalandthewhileLoop.ptx
index c76db6f79..3164d2fd7 100644
--- a/pretext/Strings/TraversalandthewhileLoop.ptx
+++ b/pretext/Iteration/TraversalandthewhileLoop.ptx
@@ -1,11 +1,11 @@
-
+Traversal and the while Loop
The while loop can also control the
- generation of the index values. Remember that the programmer is responsible for setting up the initial
+ generation of index values used to navigate strings or lists. The programmer is responsible for setting up the initial
condition, making sure that the condition is correct, and making sure that something changes inside the
body to guarantee that the condition will eventually fail.
-
+
fruit = "apple"
@@ -20,7 +20,7 @@ while position < len(fruit):
executed. The last character accessed is the one with the index
len(fruit)-1, which is the last character in the string.
Here is the same example in codelens so that you can trace the values of the variables.
-
+
fruit = "apple"
@@ -33,7 +33,7 @@ while position < len(fruit):
Check your understanding
-
+
How many times is the letter o printed by the following statements?
@@ -75,7 +75,7 @@ while idx < len(s):
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
-
+
diff --git a/pretext/MoreAboutIteration/accumulatorRevisited.ptx b/pretext/Iteration/accumulatorRevisited.ptx
similarity index 100%
rename from pretext/MoreAboutIteration/accumulatorRevisited.ptx
rename to pretext/Iteration/accumulatorRevisited.ptx
diff --git a/pretext/Iteration/intro-Iteration.ptx b/pretext/Iteration/intro-Iteration.ptx
new file mode 100644
index 000000000..d443a1be6
--- /dev/null
+++ b/pretext/Iteration/intro-Iteration.ptx
@@ -0,0 +1,11 @@
+
+
+ Iteration Introduction
+
Computers are often used to automate repetitive tasks. Repeating identical or
+ similar tasks without making errors is something that computers do well and
+ people do poorly.
+
Repeated execution of a sequence of statements is called iteration. Because
+ iteration is so common, Python provides several language features to make it
+ easier. In this chapter we are going to look at two common forms of iteration: the while statement
+ and the for statement.
+
+
+
diff --git a/pretext/Iteration/video-while.ptx b/pretext/Iteration/video-while.ptx
new file mode 100644
index 000000000..83b92278d
--- /dev/null
+++ b/pretext/Iteration/video-while.ptx
@@ -0,0 +1,7 @@
+
+
+ Practice Video Lecture
+
Week 5 Video Lecture:
+
+
+
diff --git a/pretext/Lists/AccessingElements.ptx b/pretext/Lists/AccessingElements.ptx
index d9cae3bd3..9d950f42e 100644
--- a/pretext/Lists/AccessingElements.ptx
+++ b/pretext/Lists/AccessingElements.ptx
@@ -7,7 +7,7 @@
the index. Remember that the indices start at 0. Any integer expression can be used
as an index and as with strings, negative index values will locate items from the right instead
of from the left.
-
+
numbers = [17, 123, 87, 34, 66, 8398, 44]
print(numbers[2])
@@ -19,7 +19,7 @@ print(numbers[len(numbers) - 1])
Check your understanding
-
+
What is printed by the following statements?
@@ -56,7 +56,7 @@ print(alist[5])
-
+
What is printed by the following statements?
@@ -93,7 +93,7 @@ print(alist[2].upper())
-
+
What is printed by the following statements?
diff --git a/pretext/Lists/AppendversusConcatenate.ptx b/pretext/Lists/AppendversusConcatenate.ptx
index 85d82a24c..3cf7c3fd0 100644
--- a/pretext/Lists/AppendversusConcatenate.ptx
+++ b/pretext/Lists/AppendversusConcatenate.ptx
@@ -3,7 +3,7 @@
Append versus Concatenate
The append method adds a new item to the end of a list. It is also possible to add a new item to the end of a list by using the concatenation operator. However, you need to be careful.
Consider the following example. The original list has 3 integers. We want to add the word cat to the end of the list.
Here we have used append which simply modifies the list. In order to use concatenation, we need to write an assignment statement that uses the accumulator pattern:
origlist = origlist + ["cat"]
Note that the word cat needs to be placed in a list since the concatenation operator needs two lists to do its work.
-
+
origlist = [45, 32, 88]
@@ -24,7 +24,7 @@ origlist = origlist + ["cat"]
On the other hand, with concatenation, an entirely new list is created. This can be seen in the following codelens example where
newlist refers to a list which is a copy of the original list, origlist, with the new item cat added to the end. origlist still contains the three values it did before the concatenation. This is why the assignment operation is necessary as part of the
accumulator pattern.
-
+
origlist = [45, 32, 88]
@@ -34,7 +34,7 @@ origlist = origlist + ["cat"]
It is important to see that these operators create new lists from the elements of the operand lists. If you concatenate a list with 2 items and a list with 4 items, you will get a new list with 6 items (not a list with two sublists). Similarly, repetition of a list of 2 items 4 times will give a list with 8 items.
One way for us to make this more clear is to run a part of this example in codelens. As you step through the code, you will see the variables being created and the lists that they refer to. Pay particular attention to the fact that when newlist is created by the statement newlist = fruit + numlist, it refers to a completely new list formed by making copies of the items from fruit and numlist. You can see this very clearly in the codelens object diagram. The objects are different.
diff --git a/pretext/Lists/Glossary.ptx b/pretext/Lists/Glossary.ptx
index 39204b03a..662f8d442 100644
--- a/pretext/Lists/Glossary.ptx
+++ b/pretext/Lists/Glossary.ptx
@@ -62,11 +62,6 @@
patterns and algorithms that form your toolkit. Patterns often
correspond to your mental chunking.
-
- pure function
-
A function which has no side effects. Pure functions only make changes
- to the calling program through their return values.
- sequence
Any of the data types that consist of an ordered collection of elements, with
diff --git a/pretext/Lists/ListDeletion.ptx b/pretext/Lists/ListDeletion.ptx
index 98c5b4aad..386f02678 100644
--- a/pretext/Lists/ListDeletion.ptx
+++ b/pretext/Lists/ListDeletion.ptx
@@ -4,7 +4,7 @@
Using slices to delete list elements can be awkward and therefore error-prone.
Python provides an alternative that is more readable.
The del statement removes an element from a list by using its position.
-
+
a = ['one', 'two', 'three']
del a[1]
@@ -22,7 +22,7 @@ print(alist)
index, but do not cause runtime errors if the index limits go too far.
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
-
+
diff --git a/pretext/Lists/ListLength.ptx b/pretext/Lists/ListLength.ptx
index c7e1ca7fb..a16bd17a6 100644
--- a/pretext/Lists/ListLength.ptx
+++ b/pretext/Lists/ListLength.ptx
@@ -5,7 +5,7 @@
of items in the list). However, since lists can have items which are themselves lists, it important to note
that len only returns the top-most length. In other words, sublists are considered to be a single
item when counting the length of the list.
-
+
alist = ["hello", 2.0, 5, [10, 20]]
print(len(alist))
@@ -15,7 +15,7 @@ print(len(['spam!', 1, ['Brie', 'Roquefort', 'Pol le Veq'], [1, 2, 3]]))
Check your understanding
-
+
What is printed by the following statements?
@@ -44,7 +44,7 @@ print(len(alist))
-
+
What is printed by the following statements?
diff --git a/pretext/Lists/ListMethods.ptx b/pretext/Lists/ListMethods.ptx
index 263c05652..175f25daa 100644
--- a/pretext/Lists/ListMethods.ptx
+++ b/pretext/Lists/ListMethods.ptx
@@ -1,49 +1,16 @@
List Methods
-
The dot operator can also be used to access built-in methods of list objects.
- append is a list method which adds the argument passed to it to the end of
- the list. Continuing with this example, we show several other list methods. Many of them are
- easy to understand.
-
-
-mylist = []
-mylist.append(5)
-mylist.append(27)
-mylist.append(3)
-mylist.append(12)
-print(mylist)
-
-mylist.insert(1, 12) # Insert 12 at pos 1, shift other items up
-print(mylist)
-print(mylist.count(12)) # How many times is 12 in mylist?
-print(mylist.index(3)) # Find index of first 3 in mylist
-print(mylist.count(5))
-
-mylist.reverse()
-print(mylist)
-
-mylist.sort()
-print(mylist)
+
The dot operator can also be used to access built-in methods of list objects.
+ As you remember, unlike strings, lists are mutable. As a consequence, list methods can have different behaviors than string methods. Let's look at these.
+
+
Return Type Methods: These methods work the same way as string methods: they give us a value but keep the original list the same.
+
Mutating Methods: These methods modify the list but do not return anything. Because of this, we shouldn't use these methods on the right hand side of assignment (we shouldn't assign them to a variable).
+
Hybrid Methods: These methods behave as both mutating and return type methods. They change the list and also return a value.
+
-mylist.remove(5) # Removes the first 12 in the list
-print(mylist)
-
-lastitem = mylist.pop() # Removes and returns the last item of the list
-print(lastitem)
-print(mylist)
-
-
-
There are two ways to use the pop method. The first, with no parameter, will remove and return the
- last item of the list. If you provide a parameter for the position, pop will remove and return the
- item at that position. Either way the list is changed.
-
The following table provides a summary of the list methods shown above. The column labeled
- result gives an explanation as to what the return value is as it relates to the new value of the list. The word
- mutator means that the list is changed by the method but nothing is returned (actually None is returned). A hybrid method is one that not only changes the list but also returns a value as its result. Finally, if the result is simply a return, then the list
- is unchanged by the method.
-
Be sure
- to experiment with these methods to gain a better understanding of what they do.
+
The following table provides a summary of the list methods shown above. The column labeled behavior gives an explanation as to what the return value is as it relates to the new value of the list.
@@ -54,7 +21,7 @@ print(mylist)
Parameters
- Result
+ Behavior
Description
@@ -68,7 +35,7 @@ print(mylist)
item
- mutator
+ mutating
Adds a new item to the end of a list
@@ -82,7 +49,7 @@ print(mylist)
position, item
- mutator
+ mutating
Inserts a new item at the position given
@@ -124,7 +91,7 @@ print(mylist)
none
- mutator
+ mutating
Modifies a list to be sorted
@@ -138,7 +105,7 @@ print(mylist)
none
- mutator
+ mutating
Modifies a list to be in reverse order
@@ -155,7 +122,7 @@ print(mylist)
return idx
- Returns the position of first occurrence of item
+ Returns the position of first occurrence of item, error if not found
@@ -180,7 +147,7 @@ print(mylist)
item
- mutator
+ mutating
Removes the first occurrence of item
@@ -188,27 +155,98 @@ print(mylist)
-
Details for these and others
- can be found in the Python Documentation.
-
It is important to remember that methods like append, sort,
- and reverse all return None. This means that re-assigning mylist to the result of sorting mylist will result in losing the entire list. Calls like these will likely never appear as part of an assignment statement (see line 8 below).
-
+
+
+
+
Here are some examples on these methods. Be sure to experiment with them to gain a better understanding of what they do. You are expected to be comfortable using these methods!
+
+
+
+# Let's create a list and fill it with some values
mylist = []
mylist.append(5)
mylist.append(27)
mylist.append(3)
mylist.append(12)
print(mylist)
+
+
-mylist = mylist.sort() #probably an error
+
Another way to add items:
+
+
+
+mylist = [5, 27, 3, 12]
+mylist.insert(1, 12) # Insert 12 at pos 1, shift other items up
+print(mylist)
+
+
+
+
Some return type methods:
+
+
+
+mylist = [5, 27, 3, 12]
+print(mylist.count(12)) # How many times is 12 in mylist?
+print(mylist.index(3)) # Find index of first 3 in mylist
+print(mylist) # mylist is unchanged as count and index are return type methods
+
+
+
+
Some mutating methods:
+
+
+
+mylist = [5, 27, 3, 12]
+mylist.reverse()
+print(mylist)
+
+mylist.sort()
+print(mylist)
+
+mylist.remove(5) # Removes the value 5 from the list
+print(mylist)
+
+my_second_list = mylist.append(5) # We shouldn't assign the result of a mutating method to a variable!
+print(my_second_list) # It will be None
+
+
+
+
It is important to remember that methods like append, sort,
+ and reverse all return None. This means that re-assigning mylist
+ to the result of sorting mylist will result in losing the entire list.
+
+
+
Some hybrid methods:
+
+
+
+
+mylist = [5, 27, 3, 12]
+lastitem = mylist.pop() # Removes and returns the last item of the list
+print(lastitem)
+print(mylist)
+
+seconditem = mylist.pop(1) # Removes and returns the item at index 1
+print(seconditem)
+
+mylist.pop() # Remember that pop is a hybrid method
print(mylist)
+
Notice that there are two ways to use the pop method. The first, with no parameter, will remove and return the
+ last item of the list. If you provide a parameter for the position, pop will remove and return the
+ item at that position. Either way the list is changed. Hybrid methods will also change
+ the list without assignment to a variable, as shown with the last example above.
+
+
Details for these methods and others
+ can be found in the Python Documentation.
+
Check your understanding
-
+
What is printed by the following statements?
@@ -247,7 +285,7 @@ print(alist)
-
+
What is printed by the following statements?
@@ -286,7 +324,7 @@ print(alist)
-
+
What is printed by the following statements?
@@ -325,7 +363,7 @@ print(alist)
-
+
What is printed by the following statements?
@@ -373,7 +411,7 @@ print(alist)
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
-
+
diff --git a/pretext/Lists/ListSlices.ptx b/pretext/Lists/ListSlices.ptx
index 44ad1b42e..6909e2054 100644
--- a/pretext/Lists/ListSlices.ptx
+++ b/pretext/Lists/ListSlices.ptx
@@ -5,7 +5,7 @@
that if you omit the first index (before the colon), the slice starts at the
beginning of the sequence. If you omit the second index, the slice goes to the
end of the sequence.
-
+
a_list = ['a', 'b', 'c', 'd', 'e', 'f']
print(a_list[1:3])
@@ -17,7 +17,7 @@ print(a_list[:])
Check your understanding
-
+
What is printed by the following statements?
@@ -54,4 +54,87 @@ print(alist[4:])
+
+
+
+
Slices also take an optional third value, the step size.
+ This specifies the rate at which the slice region increments (if the step size is positive)
+ or the rate at which it decrements (if the step size is negative).
+ It is also possible to specify -1 as the step term to slice with the values in reverse.
+
+
+ Correct! Everything is sliced backwards in this case.
+
+
+
+
+
[3, 67, "cat", [56, 57, "dog"], [ ], 3.14, False]
+
+
+ This is the original list!
+
+
+
+
+
False, 3.14, []
+
+
+ This operation is done on all of the items in the list, not just the first few.
+
+
+
+
diff --git a/pretext/Lists/ListValues.ptx b/pretext/Lists/ListValues.ptx
index b30b2b489..3acfed0ce 100644
--- a/pretext/Lists/ListValues.ptx
+++ b/pretext/Lists/ListValues.ptx
@@ -22,7 +22,7 @@
Finally, there is a special list that contains no elements. It is called the
empty list and is denoted [].
As you would expect, we can also assign list values to variables and pass lists as parameters to functions.
Unlike strings, lists are mutable. This means we can change an item in a list by accessing
it directly as part of the assignment statement. Using the indexing operator (square brackets) on the left side of an assignment, we can
update one of the list items.
-
+
fruit = ["banana", "apple", "cherry"]
print(fruit)
@@ -18,7 +18,7 @@ print(fruit)
assignment to an element of a list is called item assignment. Item
assignment does not work for strings. Recall that strings are immutable.
Here is the same example in codelens so that you can step through the statements and see the changes to the list elements.
None, or the NoneType, is a type which represents the absence of a value.
+ But let's take a step back and think: why is this useful?
+
+
In Python, sometimes we don't want to return anything from a function. However, when we don't
+ explicitly return anything from a function, Python will implicitly return None.
+
+
For the purposes of this class, you should just understand when None appears and why.
+
+
Most commonly when students are learning about strings and lists, us educators see a similar issue, which links back
+ to sections on mutability. Strings are immutable and lists are mutable, remember?
+
+
When we want to modify a string, we must reassign it, because it's immutable:
+
+
+print(my_list[0])
+~~~~~~~^^^
+TypeError: 'NoneType' object is not subscriptable
+
+
+
+
Frustratingly, your code actually did exactly what you told it to. List functions modify the list directly, because
+ lists are mutable. Therefore, their functions (such as .append(element)) don't return anything.
+
+
But now we know why: append is actually implicitly returning None. This means that in the previous example, we reassigned my_list
+ to None, and then we tried to list access element 0 of None, which caused the 'not subscriptable' error, because None isn't a list
+ and can't have list access done to it.
+
+
The solution is simple: don't reassign the list when calling list functions.
If you remember nothing else, remember: strings get reassigned, lists don't. This is because
+ strings are immutable; lists are mutable and most of their functions don't return anything (meaning they implicitly return None!).
+
+
You may be wondering how to tell the difference between functions that return something or not. Sometimes
+ the name of the method can be a hint (e.g. if it has "set" in the name, it probably won't return, whereas "get" will).
+ If that doesn't help or you're still curious, you should reference the documentation (whether it's official Python
+ documentation or for a library). No shame in looking it up!
+
+
You won't be tested on the information below, but read on for some interesting thoughts on this.
+
+
If you've been around any other programming languages, you may have heard of equivalent ideas like
+ null, NULL, nullptr, nil, and more. This is such a universal concept
+ in programming and is hugely frustrating to many programmers as it often represents something that went wrong.
+
+
Fun (or depressing) fact -- the inventor of null actually regrets his invention:
+
+
+
+ I call it my billion-dollar mistake... At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
+
+
+
+
+
+ - Tony Hoare
+
+
+
+
Despite this, None, null, and nil don't seem to be going anywhere anytime soon. :)
+
diff --git a/pretext/Lists/StringsandLists.ptx b/pretext/Lists/StringsandLists.ptx
index dbe5d3d00..9bb57321b 100644
--- a/pretext/Lists/StringsandLists.ptx
+++ b/pretext/Lists/StringsandLists.ptx
@@ -5,28 +5,40 @@
strings. The split method
breaks a string into a list of words. By
default, any number of whitespace characters is considered a word boundary.
-
+
song = "The rain in Spain..."
wds = song.split()
print(wds)
+
An optional argument called a delimiter can be used to specify which
- characters to use as word boundaries. The following example uses the string
- ai as the delimiter:
-
+ characters to use as word boundaries.
+
-song = "The rain in Spain..."
+song = "The rain, and the flood in Spain..."
+
+#These are the same as the default is to split on whitespace:
+print(song.split())
+print(song.split(' '))
+
+#If we want to split on something else, we can do that too:
+abc = song.split(',')
+print(abc)
wds = song.split('ai')
print(wds)
+
+# Notice that the split is a string method, so it does not modify the original string.
+print(song)
+
Notice that the delimiter doesn't appear in the result.
The inverse of the split method is join. You choose a
desired separator string, (often called the glue)
and join the list with the glue between each of the elements.
The list that you glue together (wds in this example) is not modified. Also,
you can use empty glue or multi-character strings as glue.
+
+
+ index Method in Lists and Strings
+
+
One important thing to note is that even though index methods is named the same in the context of strings and lists, they behave differently.
+With strings, the index method looks for a substring (or a character), and returns the first instance of that character.
+However, with lists, the index method looks for an element and returns the first instance of that element.
+
+
+
+
+
+my_str = "To a great mind, nothing is little,' remarked Holmes, sententiously."
+print(my_str.index("great")) # Finds the substring "great" in my_str, expected result is 5
+print(my_str.index("n")) # Finds the character "n" in my_str, expected result is 13 (first occurence)
+
+
+
+
What happens when I split the string to a list?
+
+
+
+my_str = "To a great mind, nothing is little,' remarked Holmes, sententiously."
+my_list = my_str.split()
+print(my_list)
+print(my_list.index("great")) # Finds the element "great" in my_list, expected result is 2
+print(my_list.index("n")) # "n" is NOT an element in my_list, expected result is an error
+
+
+
+
BONUS: Check this example after reading the next section (List Type Conversion Function) and spot the difference!
+
+
+
+my_str = "To a great mind, nothing is little,' remarked Holmes, sententiously."
+
+char_by_char = list(my_str)
+print(char_by_char)
+print(char_by_char.index("n")) # Finds the element "n" in char_by_char, expected result is 13
+print(char_by_char.index("great")) # "great" is NOT an element in char_by_char, expected result is an error
+
+
+
+
+
- Yes, split creates a list of the three names. The for loop iterates through the names and creates a string from the first characters.
+ Yes, split creates a list of the three names.
diff --git a/pretext/Lists/listTypeConversionFunction.ptx b/pretext/Lists/listTypeConversionFunction.ptx
index d3efb3713..e5e6bb786 100644
--- a/pretext/Lists/listTypeConversionFunction.ptx
+++ b/pretext/Lists/listTypeConversionFunction.ptx
@@ -4,7 +4,7 @@
Python has a built-in type conversion function called
list that tries to turn whatever you give it
into a list. For example, try the following:
Our course mentor Ethan has generously put together short video lectures to culminate each weekly reading. Now that you have finished chapters 3 and 4, the video is embedded below.
+ It is not required, but you may find it helpful if the reading left you with questions.
Add a print statement to Newton's sqrt function that
- prints out better each time it is calculated. Call your modified
- function with 25 as an argument and record the results.
Write a function print_triangular_numbers(n) that prints out the first
- n triangular numbers. A call to print_triangular_numbers(5) would
- produce the following output:
-
1 1
-2 3
-3 6
-4 10
-5 15
-
(hint: use a web search to find out what a triangular number is.)
-
-
-
-
-
-Write a function ``print_triangular_numbers(n)`` that prints out the first
-n triangular numbers. A call to ``print_triangular_numbers(5)`` would
-produce the following output::
-
- 1 1
- 2 3
- 3 6
- 4 10
- 5 15
-
-(*hint: use a web search to find out what a triangular number is.*)
-~~~~
-def print_triangular_numbers(n):
- # your code here
-
-
-
-
-
-
Write a function, is_prime, that takes a single integer argument
- and returns True when the argument is a prime number and False
- otherwise.
-
-
-
-
-def is_prime(n):
- # your code here
-
-====
-from unittest.gui import TestCaseGui
-
-class myTests(TestCaseGui):
-
- def testOne(self):
- self.assertEqual(is_prime(2),True,"Tested on 2, which is a prime number.")
- self.assertEqual(is_prime(4187),False,"Tested on 4187, which is not a prime number. It is divisible by 53 and 79.")
- self.assertEqual(is_prime(22),False,"Tested on 22, which is not a prime number. It is divisible by 2 and 11.")
- self.assertEqual(is_prime(4813),True,"Tested on 4813, which is a prime number.")
-
-myTests().main()
-
-
-
-
-
-def is_prime(n):
- for i in range(2, n):
- if n % i == 0:
- return False
- return True
-
-print(is_prime(25))
-print(is_prime(7))
-print(is_prime(251))
-print(is_prime(20))
-
-
-
-
-
-
-
Modify the walking turtle program so that rather than a 90 degree left or right turn the
- angle of the turn is determined randomly at each step.
-
-
-
-
-
-
-
-
-
-
Modify the turtle walk program so that you have two turtles each with a
- random starting location. Keep the turtles moving until one of them leaves the screen.
Modify the previous turtle walk program so that the turtle turns around
- when it hits the wall or when one turtle collides with another turtle
- (when the positions of the two turtles are closer than some small number).
-
-
-
-
-
-
-
-
-
-
Write a function to remove all the red from an image.
- <img src="../_static/LutherBellPic.jpg" id="luther.jpg">
-<h4 style="text-align: left;">For this and the following exercises, use the
-luther.jpg photo.</h4>
-
-
-
-
-
-
-
-
-
-import image
-
-img = image.Image("luther.jpg")
-newimg = image.EmptyImage(img.getWidth(), img.getHeight())
-win = image.ImageWin()
-
-for col in range(img.getWidth()):
- for row in range(img.getHeight()):
- p = img.getPixel(col, row)
-
- newred = 0
- green = p.getGreen()
- blue = p.getBlue()
-
- newpixel = image.Pixel(newred, green, blue)
-
- newimg.setPixel(col, row, newpixel)
-
-newimg.draw(win)
-win.exitonclick()
-
-
-
-
-
-
-
Write a function to convert the image to grayscale.
-
-
-
-
-
-
-
-
-
-
Write a function to convert an image to black and white.
-
-
-
-
-
-
-
-
-
-import image
-
-def convertBlackWhite(input_image):
- grayscale_image = image.EmptyImage(input_image.getWidth(), input_image.getHeight())
-
- for col in range(input_image.getWidth()):
- for row in range(input_image.getHeight()):
- p = input_image.getPixel(col, row)
-
- red = p.getRed()
- green = p.getGreen()
- blue = p.getBlue()
-
- avg = (red + green + blue) / 3.0
-
- newpixel = image.Pixel(avg, avg, avg)
- grayscale_image.setPixel(col, row, newpixel)
-
- blackwhite_image = image.EmptyImage(input_image.getWidth(), input_image.getHeight())
- for col in range(input_image.getWidth()):
- for row in range(input_image.getHeight()):
- p = grayscale_image.getPixel(col, row)
- red = p.getRed()
- if red > 140:
- val = 255
- else:
- val = 0
-
- newpixel = image.Pixel(val, val, val)
- blackwhite_image.setPixel(col, row, newpixel)
- return blackwhite_image
-
-
-win = image.ImageWin()
-img = image.Image("luther.jpg")
-
-bw_img = convertBlackWhite(img)
-bw_img.draw(win)
-
-win.exitonclick()
-
-
-
-
-
-
-
Sepia Tone images are those brownish colored images that may remind you of
- times past. The formula for creating a sepia tone is as follows:
-
newR = (R × 0.393 + G × 0.769 + B × 0.189)
-newG = (R × 0.349 + G × 0.686 + B × 0.168)
-newB = (R × 0.272 + G × 0.534 + B × 0.131)
-
Write a function to convert an image to sepia tone. Hint:
- Remember that rgb values must be integers between 0 and 255.
-
-
-
-
-
-
-
-
-
-
Write a function to uniformly enlarge an image by a factor of 2 (double the size).
After you have scaled an image too much it looks blocky. One way of
- reducing the blockiness of the image is to replace each pixel with the
- average values of the pixels around it. This has the effect of smoothing
- out the changes in color. Write a function that takes an image as a
- parameter and smooths the image. Your function should return a new image
- that is the same as the old but smoothed.
-
-
-
-
-
-
-
-
-
-
Write a general pixel mapper function that will take an image and a pixel mapping function as
- parameters. The pixel mapping function should perform a manipulation on a single pixel and return
- a new pixel.
When you scan in images using a scanner they may have lots of noise due to
- dust particles on the image itself or the scanner itself,
- or the images may even be damaged. One way of eliminating this noise is
- to replace each pixel by the median value of the pixels surrounding it.
-
-
-
-
-
-
-
-
-
-
Research the Sobel edge detection algorithm and implement it.
-
-
-
-
-
-
-
-
-
-import image
-import math
-import sys
-
-# Code adapted from http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/image-processing/edge_detection.html
-# Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
-
-# this algorithm takes some time for larger images - this increases the amount of time
-# the program is allowed to run before it times out
-sys.setExecutionLimit(20000)
-
-img = image.Image("luther.jpg")
-newimg = image.EmptyImage(img.getWidth(), img.getHeight())
-win = image.ImageWin()
-
-for x in range(1, img.getWidth()-1): # ignore the edge pixels for simplicity (1 to width-1)
- for y in range(1, img.getHeight()-1): # ignore edge pixels for simplicity (1 to height-1)
-
- # initialise Gx to 0 and Gy to 0 for every pixel
- Gx = 0
- Gy = 0
-
- # top left pixel
- p = img.getPixel(x-1, y-1)
- r = p.getRed()
- g = p.getGreen()
- b = p.getBlue()
-
- # intensity ranges from 0 to 765 (255 * 3)
- intensity = r + g + b
-
- # accumulate the value into Gx, and Gy
- Gx += -intensity
- Gy += -intensity
-
- # remaining left column
- p = img.getPixel(x-1, y)
- r = p.getRed()
- g = p.getGreen()
- b = p.getBlue()
-
- Gx += -2 * (r + g + b)
-
- p = img.getPixel(x-1, y+1)
- r = p.getRed()
- g = p.getGreen()
- b = p.getBlue()
-
- Gx += -(r + g + b)
- Gy += (r + g + b)
-
- # middle pixels
- p = img.getPixel(x, y-1)
- r = p.getRed()
- g = p.getGreen()
- b = p.getBlue()
-
- Gy += -2 * (r + g + b)
-
- p = img.getPixel(x, y+1)
- r = p.getRed()
- g = p.getGreen()
- b = p.getBlue()
-
- Gy += 2 * (r + g + b)
-
- # right column
- p = img.getPixel(x+1, y-1)
- r = p.getRed()
- g = p.getGreen()
- b = p.getBlue()
-
- Gx += (r + g + b)
- Gy += -(r + g + b)
-
- p = img.getPixel(x+1, y)
- r = p.getRed()
- g = p.getGreen()
- b = p.getBlue()
-
- Gx += 2 * (r + g + b)
-
- p = img.getPixel(x+1, y+1)
- r = p.getRed()
- g = p.getGreen()
- b = p.getBlue()
-
- Gx += (r + g + b)
- Gy += (r + g + b)
-
- # calculate the length of the gradient (Pythagorean theorem)
- length = math.sqrt((Gx * Gx) + (Gy * Gy))
-
- # normalise the length of gradient to the range 0 to 255
- length = length / 4328 * 255
-
- length = int(length)
-
- # draw the length in the edge image
- newpixel = image.Pixel(length, length, length)
- newimg.setPixel(x, y, newpixel)
-
-newimg.draw(win)
-win.exitonclick()
-
-
-
-
-
diff --git a/pretext/MoreAboutIteration/intro-IterationRevisited.ptx b/pretext/MoreAboutIteration/intro-IterationRevisited.ptx
deleted file mode 100644
index daecea209..000000000
--- a/pretext/MoreAboutIteration/intro-IterationRevisited.ptx
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
- Iteration Revisited
-
Computers are often used to automate repetitive tasks. Repeating identical or
- similar tasks without making errors is something that computers do well and
- people do poorly.
-
Repeated execution of a sequence of statements is called iteration. Because
- iteration is so common, Python provides several language features to make it
- easier. We've already seen the for statement in a previous chapter. This is a very common
- form of iteration in Python. In this chapter
- we are going to look at the while statement — another way to have your
- program do iteration.
This is a Python script named coffee_shop.py that contains three variables: shop_name, coffee_sizes, and coffee_roasts. The shop_name is a string, coffee_sizes is a list containing strings, and coffee_roasts is also a list containing strings.
diff --git a/pretext/PythonModules/MoreAboutUsingModules.ptx b/pretext/PythonModules/MoreAboutUsingModules.ptx
index 2ca17a267..b8a719511 100644
--- a/pretext/PythonModules/MoreAboutUsingModules.ptx
+++ b/pretext/PythonModules/MoreAboutUsingModules.ptx
@@ -1,15 +1,16 @@
More About Using Modules
+
Before we move on to exploring other modules, we should say a bit more about what modules are and how we
- typically use them. One of the most important things to realize about modules is the fact that they are data objects, just
- like any other data in Python. Module objects simply contain other Python elements.
+ typically use them. One of the most important things to realize about modules is the fact that they are data objects, just
+ like any other data in Python. Module objects simply contain other Python elements.
+
The first thing we need to do when we wish to use a module is perform an import. In the example above, the statement
- import turtle creates a new name, turtle, and makes it refer to a module object. This looks very much like
- the reference diagrams we saw earlier for simple variables.
-
-
In order to use something contained in a module, we use the dot notation, providing the module name and the specific item joined together with a dot. For example, to use the Turtle class, we say turtle.Turtle. You should read
- this as: In the module turtle, access the Python element called Turtle.
-
We will now turn our attention to a few other modules that you might find useful.
-
+ import math creates a new name, math, and makes it refer to a `module object`. This looks very much like
+ the reference diagrams we saw earlier for simple variables.
+
+
In order to use something contained in a module, we use the `dot` notation, providing the module name and the specific item joined together with a "dot". For example, to use the sqrt function, we say math.sqrt. You should read
+this as: "In the module math, access the Python element called sqrt".
+
diff --git a/pretext/PythonModules/Packages.ptx b/pretext/PythonModules/Packages.ptx
new file mode 100644
index 000000000..0854b2bb1
--- /dev/null
+++ b/pretext/PythonModules/Packages.ptx
@@ -0,0 +1,44 @@
+
+
+ Packages and Dependencies
+
+
You won't ever need to deal with dependencies in this course unless you are adding modules to your final project. Nonetheless, using packages
+ (a package is just a collection of Python modules) is a common practice in Python programming that you should at least be aware of.
+
+
One key tenant of computer science (or anything, for that matter) is that we don't want to reinvent
+ the wheel if we don't have to. A lot of very smart people have made very useful code, so why not use it?
+
+
The is a website that maintains packages, or code that other people
+ have written for our use. You might also hear the term dependencies, which describes essentially the same thing: code
+ that our code depends on.
+
+
PyPI can be accessed with pip, which is the command that you will use when installing dependencies. Pip should come
+ preinstalled with most Python installations on Mac and Windows.
+
+
Some common packages include: pytest (for testing your code), python-dateutil (for working with dates), flask (for making websites), and more.
+
+
Some common packages for data science include numpy, matplotlib, scipy, pandas and more.
+
+
But this is all sounding like a lot to keep track of, right? How can we ensure consistency between
+ versions installed on different people's computers?
+
+
requirements.txt is a file we can specify for others to be able to easily install dependencies
+ (which are needed to run our code), since others may not have them installed on their own computers yet.
+
+
The following code represents a requirements.txt file that specifies numpy as a dependency:
+
+
+numpy==1.26.2
+
+
+
+
Note that dependencies are not installed immediately. For someone to install the requirements which you specify,
+ they would run the command: pip install -r requirements.txt.
+
+
If you're unsure what version of a dependency you have installed, you can run the command: pip show DEPENDENCY, like pip show numpy.
+ Somewhat ironically, there are also packages that can autogenerate a requirements.txt file for you.
+
+
One additional tip worth mentioning is to always specify the bare minimum requirements your code needs to work.
+ Dependencies normally have dependencies of their own, so we want to minimize the install time and space taken up
+ when someone is installing your program's requirements.
Python provides a module random that helps with tasks like this. You can
take a look at it in the documentation. Here are the key things we can do with it.
-
+
import random
@@ -50,7 +50,7 @@ print(diceThrow)
the range [0.0, 5.0). Once more, these are uniformly distributed numbers — numbers
close to 0 are just as likely to occur as numbers close to 0.5, or numbers close to 1.0.
If you continue to press the run button you will see random values between 0.0 and up to but not including 5.0.
-
+
import random
@@ -67,7 +67,7 @@ print(result)
of the attributes of the generator) will be updated. The good news is that each time you run your program, the seed value
is likely to be different meaning that even though the random numbers are being created algorithmically, you will likely
get random behavior each time you execute.
-
+
Check your understanding
-
+
Which of the following is the correct way to reference the value pi within the math module. Assume you have already imported the math module.
@@ -119,7 +119,7 @@ print(result)
-
+
Which module would you most likely use if you were writing a function to simulate rolling dice?
@@ -158,7 +158,7 @@ print(result)
-
+
The correct code to generate a random number between 1 and 100 (inclusive) is:
@@ -197,7 +197,7 @@ print(result)
-
+
One reason that lotteries don't use computers to generate random numbers is:
@@ -238,7 +238,7 @@ print(result)
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
-
+
diff --git a/pretext/PythonModules/modules.ptx b/pretext/PythonModules/modules.ptx
index a18b44559..2a16d94a1 100644
--- a/pretext/PythonModules/modules.ptx
+++ b/pretext/PythonModules/modules.ptx
@@ -1,27 +1,25 @@
Modules and Getting Help
-
+
A module is a file containing Python definitions and statements intended
for use in other Python programs. There are many Python modules that come with
- Python as part of the standard library. We have already used one of these quite extensively,
- the turtle module. Recall that once we import the module, we can use things
+ Python as part of the standard library. We have already used one of these briefly,
+ the math module. Recall that once we import the module, we can use things
that are defined inside.
-
+
-import turtle # allows us to use the turtles library
+import math # allows us to use the math library
-wn = turtle.Screen() # creates a graphics window
-alex = turtle.Turtle() # create a turtle named alex
+print(math.factorial(10)) # prints 10!
+print(math.exp(4)) # prints e^4
-alex.forward(150) # tell alex to move forward by 150 units
-alex.left(90) # turn by 90 degrees
-alex.forward(75) # complete the second side of a rectangle
-wn.exitonclick()
+print(math.log2(1024)) # prints log2(1024)
+print(math.sqrt(100)) # prints the square root of 100
-
Here we are using Screen and Turtle, both of which are defined inside the turtle module.
-
But what if no one had told us about turtle? How would we know
+
Here we are using factorial, exp, log2, and sqrt, all of which are defined inside the math module.
+
But what if no one had told us about math? How would we know
that it exists. How would we know what it can do for us? The answer is to ask for help and the best place to get
help about the Python programming environment is to consult with the Python Documentation.
The Python Documentation site for Python version 3 (the home page is shown below) is an extremely useful reference
@@ -35,10 +33,10 @@ wn.exitonclick()
and to use it often.
If you have not done so already, take a look at the Global Module Index. Here you will see an alphabetical listing of all
- the modules that are available as part of the standard library. Find the turtle module.
+ the modules that are available as part of the standard library. Find the math module.
-
-
You can see that all the turtle functionality that we have talked about is there. However, there is so much more. Take some time to read through and familiarize yourself with some of the other things that turtles can do.
+
You can see that all the math functionality that we have talked about is there. However, there is so much more.
+ Take some time to read through and familiarize yourself with some of the other things that math can do.
Note: Python modules and limitations with activecode
Throughout the chapters of this book, activecode windows allow you to practice the Python that you are learning.
@@ -46,14 +44,14 @@ wn.exitonclick()
environment and that the
activecode used here was strictly to help us learn. It is not the way we write production programs.
To that end, it is necessary to mention that many of the modules available in standard Python
- will not work in the activecode environment. In fact, only turtle, math, and random have been
+ will not work in the activecode environment. In fact, only math and random have been
completely ported at this point. If you wish to explore any
additional modules, you will need to also explore using a more robust development environment.
Check your understanding
-
+
In Python a module is:
@@ -92,7 +90,7 @@ wn.exitonclick()
-
+
To find out information on the standard modules available with Python you should:
@@ -131,7 +129,7 @@ wn.exitonclick()
-
+
True / False: All standard Python modules will work in activecode.
@@ -141,7 +139,7 @@ wn.exitonclick()
True
- Only turtle, math, and random have been ported to work in activecode at this time.
+ Only math, and random have been ported to work in activecode at this time.
@@ -149,7 +147,7 @@ wn.exitonclick()
False
- Only turtle, math, and random have been ported to work in activecode at this time.
+ Only math, and random have been ported to work in activecode at this time.
diff --git a/pretext/PythonModules/toctree.ptx b/pretext/PythonModules/toctree.ptx
index 0eb0cfa06..896c0c70a 100644
--- a/pretext/PythonModules/toctree.ptx
+++ b/pretext/PythonModules/toctree.ptx
@@ -3,9 +3,9 @@
4Python Modules
4
4
-4
4
4
+4
4
-4
+4
diff --git a/pretext/PythonModules/video-functions.ptx b/pretext/PythonModules/video-functions.ptx
new file mode 100644
index 000000000..0df11c907
--- /dev/null
+++ b/pretext/PythonModules/video-functions.ptx
@@ -0,0 +1,7 @@
+
+
+ Practice Video Lecture
+
A codelens demonstration is a good way to help you visualize exactly how the flow of control
works with the for loop. Try stepping forward and backward through the program by pressing
the buttons. You can see the value of name change as the loop iterates through the list of friends.
-
+
for name in ["Joe", "Amy", "Brad", "Angelina", "Zuki", "Thandi", "Paris"]:
print("Hi ", name, " Please come to my party on Saturday!")
diff --git a/pretext/PythonTurtle/TheforLoop.ptx b/pretext/PythonTurtle/TheforLoop.ptx
index 3da7d495c..062e40387 100644
--- a/pretext/PythonTurtle/TheforLoop.ptx
+++ b/pretext/PythonTurtle/TheforLoop.ptx
@@ -11,7 +11,7 @@
we'd like to send them each an email inviting them to our party. We
don't quite know how to send email yet, so for the moment we'll just print a
message for each friend.
-
+
for name in ["Joe", "Amy", "Brad", "Angelina", "Zuki", "Thandi", "Paris"]:
print("Hi", name, "Please come to my party on Saturday!")
diff --git a/pretext/PythonTurtle/toctree.ptx b/pretext/PythonTurtle/toctree.ptx
index 84e786e12..5e1bb934e 100644
--- a/pretext/PythonTurtle/toctree.ptx
+++ b/pretext/PythonTurtle/toctree.ptx
@@ -7,7 +7,7 @@
4
4
4
-4
+
4
4
4
diff --git a/pretext/Selection/BooleanFunctions.ptx b/pretext/Selection/BooleanFunctions.ptx
deleted file mode 100644
index 9acd737e2..000000000
--- a/pretext/Selection/BooleanFunctions.ptx
+++ /dev/null
@@ -1,166 +0,0 @@
-
-
- Boolean Functions
-
-
We have already seen that boolean values result from the evaluation of boolean expressions. Since the result of any
- expression evaluation can be returned by a function (using the return statement),
- functions can return boolean values. This turns out to be a very convenient way to hide the details of complicated tests. For example:
-
-
-def isDivisible(x, y):
- if x % y == 0:
- result = True
- else:
- result = False
-
- return result
-
-print(isDivisible(10, 5))
-
-
-
The name of this function is isDivisible. It is common to give boolean
- functions names that sound like yes/no questions. isDivisible returns
- either True or False to indicate whether the x is or is not
- divisible by y.
-
-
We can make the function more concise by taking advantage of the fact that the
- condition of the if statement is itself a boolean expression. We can return
- it directly, avoiding the if statement altogether:
-
-
-def isDivisible(x, y):
- return x % y == 0
-
-
-
Boolean functions are often used in conditional statements:
It might be tempting to write something like
- if isDivisible(x, y) == True:
- but the extra comparison is redundant. You only need an == expression if you are comparing some other type than boolean. (isDivisible(x, y) == False can also be made more concise as
- not isDivisible(x, y)). The following example shows the isDivisible function at work. Notice how
- descriptive the code is when we move the testing details into a boolean function. Try it
- with a few other actual parameters to see what is printed.
-
-
-def isDivisible(x, y):
- return x % y == 0
-
-if isDivisible(10, 5):
- print("That works")
-else:
- print("Those values are no good")
-
-
-
Here is the same program in codelens. When we evaluate the if statement in the main part of the program, the evaluation of
- the boolean expression causes a call to the isDivisible function. This is very easy to see in codelens.
-
-
- def isDivisible(x, y):
- return x % y == 0
-
- if isDivisible(10, 5):
- print("That works")
- else:
- print("Those values are no good")
-
-
-
- Check your understanding
-
-
-
-
What is a Boolean function?
-
-
-
-
-
A function that returns True or False
-
-
- A Boolean function is just like any other function, but it always returns True or False.
-
-
-
-
-
A function that takes True or False as an argument
-
-
- A Boolean function may take any number of arguments (including 0, though that is rare), of any type.
-
-
-
-
-
The same as a Boolean expression
-
-
- A Boolean expression is a statement that evaluates to True or False, e.g. 5+3==8. A function is a series of expressions grouped together with a name that are only executed when you call the function.
-
-
-
-
-
-
-
Is the following statement legal in a Python function (assuming x, y and z are defined to be numbers)?
-
-
-return x + y < z
-
-
-
-
-
-
-
Yes
-
-
- It is perfectly valid to return the result of evaluating a Boolean expression.
-
-
-
-
-
No
-
-
- x +y < z is a valid Boolean expression, which will evaluate to True or False. It is perfectly legal to return True or False from a function, and to have the statement to be evaluated in the same line as the return keyword.
-
-
-
-
-
-
- More Unit Testing
-
When we write unit tests, we should also consider output equivalence classes that result in significantly different results.
-
The isDivisible function can return either True or False. These two different outputs give us two equivalence classes. We then choose inputs that should give each of the different results. It is important to have at least one test for each output equivalence class.
-
-
-
-def isDivisible(x, y):
- '''is x evenly divisible by y?'''
- return x % y == 0
-
-if __name__ == "__main__":
- import test
-
-
-
- Extend the program …
-
Starting on line 7, write two unit tests (that should pass), one for each output equivalence class.
-
-
-
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
The Python type for storing true and false values is called bool, named
after the British mathematician, George Boole. George Boole created Boolean
Algebra, which is the basis of all modern computer arithmetic.
There are only two boolean values. They are True and False. Capitalization
is important, since true and false are not boolean values (remember Python is case
sensitive).
-
+
print(True)
print(type(True))
@@ -21,7 +21,7 @@ print(type(False))
surrounded by quotes. They are the only two values in the data type bool. Take a close look at the
types shown below.
-
+
print(type(True))
print(type("True"))
@@ -30,7 +30,7 @@ print(type("True"))
A boolean expression is an expression that evaluates to a boolean value.
The equality operator, ==, compares two values and produces a boolean value related to whether the
two values are equal to one another.
-
+
print(5 == 5)
@@ -69,7 +69,7 @@ x <= y # x is less than or equal to y
Check your understanding
-
+
Which of the following is a Boolean expression? Select all that apply.
diff --git a/pretext/Selection/Chainedconditionals.ptx b/pretext/Selection/Chainedconditionals.ptx
index 835b296d8..0f60f135b 100644
--- a/pretext/Selection/Chainedconditionals.ptx
+++ b/pretext/Selection/Chainedconditionals.ptx
@@ -25,7 +25,7 @@ else:
statement ends. Even if more than one condition is true, only the first true
branch executes.
Here is the same program using elif.
-
+
x = 10
y = 10
@@ -40,7 +40,7 @@ else:
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
-
+
@@ -50,7 +50,7 @@ else:
Check your understanding
-
+
Which of I, II, and III below gives the same result as the following nested if?
@@ -146,45 +146,4 @@ else:
-
-
-
What will the following code print if x = 3, y = 5, and z = 2?
-
-
-if x < y and x < z:
- print("a")
-elif y < x and y < z:
- print("b")
-else:
- print("c")
-
-
-
-
-
-
-
a
-
-
- While the value in x is less than the value in y (3 is less than 5) it is not less than the value in z (3 is not less than 2).
-
-
-
-
-
b
-
-
- The value in y is not less than the value in x (5 is not less than 3).
-
-
-
-
-
c
-
-
- Since the first two Boolean expressions are false the else will be executed.
-
-
-
-
diff --git a/pretext/Selection/ConditionalExecutionBinarySelection.ptx b/pretext/Selection/ConditionalExecutionBinarySelection.ptx
index 68e3b156b..eb6a31a3b 100644
--- a/pretext/Selection/ConditionalExecutionBinarySelection.ptx
+++ b/pretext/Selection/ConditionalExecutionBinarySelection.ptx
@@ -1,12 +1,12 @@
Conditional Execution: Binary Selection
-
+
In order to write useful programs, we almost always need the ability to check
- conditions and change the behavior of the program accordingly. Selection statements, sometimes
- also referred to as conditional statements, give us this ability. The simplest form of selection is the if statement.
+ conditions and change the behavior of the program accordingly. Branching statements, sometimes
+ also referred to as conditional statements or Selection statements, give us this ability. The simplest form of branching is the if statement.
This is sometimes referred to as binary selection since there are two possible paths of execution.
-
+
x = 15
@@ -32,12 +32,29 @@ else:
Flowchart of a if statement with an else
-
As with the function definition from the last chapter and other compound
- statements like for, the if statement consists of a header line and a body. The header
+
The if statement consists of a header line and a body. The header
line begins with the keyword if followed by a boolean expression and ends with
a colon (:).
-
The more indented statements that follow are called a block.
-
Each of the statements inside the first block of statements is executed in order if the boolean
+
The more indented statements that follow are called a block. We will see this construction repeated several times in the future. Indent is 4 spaces in Python and must be same for each line. In your Python interpreter, you can easily indent lines using the tab key on your keyboard.
+
+
As a program executes, the interpreter always keeps track of which statement is
+ about to be executed. We call this the control flow, or the flow of
+ execution of the program. When humans execute programs, they often use their
+ finger to point to each statement in turn. So you could think of control flow
+ as "Python's moving finger".
+
+
Control flow until now has been strictly top to bottom, one statement at a
+ time. We call this type of control sequential. In Python, flow is sequential as long as
+ successive statements are indented the same amount. The if statement
+ introduces indented sub-statements after the if heading.
+
+
+
+
Back to the example, each of the statements inside the first block of statements is executed in order if the boolean
expression evaluates to True. The entire first block of statements
is skipped if the boolean expression evaluates to False, and instead
all the statements under the else clause are executed.
@@ -47,7 +64,7 @@ else:
the block after the heading. The if - else statement is an unusual compound statement because it
has more than one part at the same level of indentation as the if heading,
(the else clause, with its own indented block).
-
+
Check your understanding
-
+
How many statements can appear in each block (the if and the else) in a conditional statement?
@@ -100,7 +117,7 @@ else:
-
+
What does the following code print (choose from output a, b, c or nothing)?
Write a function which is given an exam mark, and it returns a string — the grade for that mark — according to this
+
Write code that takes an exam mark and prints a string — the grade for that mark — according to this
scheme:
@@ -145,135 +145,13 @@
The square and round brackets denote closed and open intervals.
A closed interval includes the number, and open interval excludes it. So 79.99999 gets grade C , but 80 gets grade B.
-
Test your function by printing the mark and the grade for a number of different marks.
+
Test your code by printing the mark and the grade for a number of different marks.
-
-
-def getGrade(grade):
- #your code here
-
-
-====
-
-from unittest.gui import TestCaseGui
-
-class myTests(TestCaseGui):
-
- def testOne(self):
- self.assertEqual(getGrade(95),'A','Tested getGrade on input of 95')
- self.assertEqual(getGrade(85),'B','Tested getGrade on input of 85')
- self.assertEqual(getGrade(65),'D','Tested getGrade on input of 65')
- self.assertEqual(getGrade(79.99999),'C','Tested getGrade on input of 79.9999')
- self.assertEqual(getGrade(80),'B','Tested getGrade on input of 80')
-
-
-myTests().main()
-
-
-
-
-
-def grade(mark):
- if mark >= 90:
- return "A"
- else:
- if mark >= 80:
- return "B"
- else:
- if mark >= 70:
- return "C"
- else:
- if mark >= 60:
- return "D"
- else:
- return "F"
-
-mark = 83
-print( "Mark:", str(mark), "Grade:", grade(mark))
-
-
-
-
-
-
-
Modify the turtle bar chart program from the previous chapter so that the bar for any value
- of 200 or more is filled with red, values between [100 and 200) are filled yellow,
- and bars representing values less than 100 are filled green.
-
-
-
-
-
-
-
-
-
-
In the turtle bar chart program, what do you expect to happen if one or more
- of the data values in the list is negative? Go back and try it out. Change the
- program so that when it prints the text value for the negative bars, it puts
- the text above the base of the bar (on the 0 axis).
-
-
-
-
-
-
-
-
-
-import turtle
-
-def drawBar(t, height):
- """ Get turtle t to draw one bar, of height. """
- t.begin_fill() # start filling this shape
- if height < 0:
- t.write(str(height))
- t.left(90)
- t.forward(height)
- if height >= 0:
- t.write(str(height))
- t.right(90)
- t.forward(40)
- t.right(90)
- t.forward(height)
- t.left(90)
- t.end_fill() # stop filling this shape
-
-
-
-xs = [48, -50, 200, 240, 160, 260, 220] # here is the data
-maxheight = max(xs)
-minheight = min(xs)
-numbars = len(xs)
-border = 10
-
-tess = turtle.Turtle() # create tess and set some attributes
-tess.color("blue")
-tess.fillcolor("red")
-tess.pensize(3)
-
-wn = turtle.Screen() # Set up the window and its attributes
-wn.bgcolor("lightgreen")
-if minheight > 0:
- lly = 0
-else:
- lly = minheight - border
-
-wn.setworldcoordinates(0-border, lly, 40*numbars+border, maxheight+border)
-
-
-for a in xs:
- drawBar(tess, a)
-
-wn.exitonclick()
-
-
-
-
Write a function findHypot. The function will be given the length of two sides of a right-angled triangle and it should return
- the length of the hypotenuse. (Hint: x ** 0.5 will return the square root, or use sqrt from the math module)
+
Write code that will calculate the length of the hypotenuse function will be given the length of two sides of a right-angled triangle and it should return
+ the . (Hint: x ** 0.5 will return the square root, or use sqrt from the math module)
@@ -298,48 +176,13 @@ myTests().main()
-
Write a function called is_even(n) that takes an integer as an argument
- and returns True if the argument is an even number and False if
+
Write code that takes an integer and prints True if the integer is an even number and False if
it is odd.
-
-
-def is_even(n):
- # your code here
-
-====
-
-from unittest.gui import TestCaseGui
-
-class myTests(TestCaseGui):
- def testOne(self):
- self.assertEqual(is_even(10),True,"Tested is_even on input of 10")
- self.assertEqual(is_even(5),False,"Tested is_even on input of 5")
- self.assertEqual(is_even(1),False,"Tested is_even on input of 1")
- self.assertEqual(is_even(0),True,"Tested is_even on input of 0")
-
-myTests().main()
+ # your code here
-
-
-
-from test import testEqual
-
-def is_even(n):
- if n % 2 == 0:
- return True
- else:
- return False
-
-testEqual(is_even(10), True)
-testEqual(is_even(5), False)
-testEqual(is_even(1), False)
-testEqual(is_even(0), True)
-
-
-
diff --git a/pretext/Selection/Glossary.ptx b/pretext/Selection/Glossary.ptx
index 45f9621a2..1c0683c58 100644
--- a/pretext/Selection/Glossary.ptx
+++ b/pretext/Selection/Glossary.ptx
@@ -69,5 +69,10 @@
One program structure within another, such as a conditional statement
inside a branch of another conditional statement.
+
+ Pseudocode
+
A mix of English and code (in our case, Python) that
+ programmers use to plan out their programs.
+
diff --git a/pretext/Lists/ListMembership.ptx b/pretext/Selection/ListMembership.ptx
similarity index 74%
rename from pretext/Lists/ListMembership.ptx
rename to pretext/Selection/ListMembership.ptx
index 5a3390b01..a5893b443 100644
--- a/pretext/Lists/ListMembership.ptx
+++ b/pretext/Selection/ListMembership.ptx
@@ -1,9 +1,9 @@
-
+List Membership
in and not in are boolean operators that test membership in a sequence. We
used them previously with strings and they also work here.
-
+
fruit = ["apple", "orange", "banana", "cherry"]
@@ -11,10 +11,24 @@ print("apple" in fruit)
print("pear" in fruit)
+
+
Remember that in and not in only checks for membership in the top level of a list.
+
+
+
+my_list = ["apple", "orange", "banana", "cherry", ["pear", "kiwi"]]
+print("pear" in my_list) # prints False because "pear" is in a sublist
+print("g" in my_list) # prints False because "g" is not an member in my_list by itself
+
+
+
+
+
There are three logical operators: and, or, and not. The
- semantics (meaning) of these operators is similar to their meaning in English.
- For example, x > 0 and x < 10 is true only if x is greater than 0 and
- at the same time, x is less than 10. How would you describe this in words? You would say that
- x is between 0 and 10, not including the endpoints.
+ semantics (meaning) of these operators is similar to their meaning in English.
+ For example, x > 0 and x < 10 is true only if x is greater than 0 and
+ at the same time, x is less than 10. How would you describe this in words? You would say that
+ x is between 0 and 10, not including the endpoints.
+
n % 2 == 0 or n % 3 == 0 is true if either of the conditions is true,
- that is, if the number is divisible by 2 or divisible by 3. In this case, one, or the other, or
- both of the parts has to be true for the result to be true.
+ that is, if the number is divisible by 2 or divisible by 3. In this case, one, or the other, or
+ both of the parts has to be true for the result to be true.
Finally, the not operator negates a boolean expression, so not x > y
- is true if x > y is false, that is, if x is less than or equal to
- y.
-
-
+ is true if x > y is false, that is, if x is less than or equal to
+ y.
+
+
x = 5
print(x > 0 and x < 10)
n = 25
print(n % 2 == 0 or n % 3 == 0)
-
+
When trying to show how logical operators work, computer scientists and mathematicians alike will use
- truth tables. A truth table is a small table that lists all possible inputs on its left columns and
- then will display the output of its particular logical operator in the right column. Take the logical
- operator and for example:
+ truth tables. A truth table is a small table that lists all possible inputs on its left columns and
+ then will display the output of its particular logical operator in the right column. Take the logical
+ operator and for example:
-
-
-
-
-
-
-
-
-
-
-
- a
-
-
- b
-
-
- a
- and
- b
-
-
-
-
- T
-
-
- T
-
-
- T
-
-
-
-
- T
-
-
- F
-
-
- F
-
-
-
-
- F
-
-
- T
-
-
- F
-
-
-
-
- F
-
-
- F
-
-
- F
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+ a
+
+
+ b
+
+
+ a
+ and
+ b
+
+
+
+
+ T
+
+
+ T
+
+
+ T
+
+
+
+
+ T
+
+
+ F
+
+
+ F
+
+
+
+
+ F
+
+
+ T
+
+
+ F
+
+
+
+
+ F
+
+
+ F
+
+
+ F
+
+
+
The T in the table stands for True while the F stands for False. Notice that when a and b
- are both True, the logcial operator and outputs True. This is exactly how
- we normally use and in everyday conversation. Here are the rest of the operators:
+ are both True, the logcial operator and outputs True. This is exactly how
+ we normally use and in everyday conversation. Here are the rest of the operators:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- a
-
-
- b
-
-
- a
- and
- b
-
-
- a
- or
- b
-
-
- not
- a
-
-
- not
- b
-
-
-
-
- T
-
-
- T
-
-
- T
-
-
- T
-
-
- F
-
-
- F
-
-
-
-
- T
-
-
- F
-
-
- F
-
-
- T
-
-
- F
-
-
- T
-
-
-
-
- F
-
-
- T
-
-
- F
-
-
- T
-
-
- T
-
-
- F
-
-
-
-
- F
-
-
- F
-
-
- F
-
-
- F
-
-
- T
-
-
- T
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a
+
+
+ b
+
+
+ a
+ and
+ b
+
+
+ a
+ or
+ b
+
+
+ not
+ a
+
+
+ not
+ b
+
+
+
+
+ T
+
+
+ T
+
+
+ T
+
+
+ T
+
+
+ F
+
+
+ F
+
+
+
+
+ T
+
+
+ F
+
+
+ F
+
+
+ T
+
+
+ F
+
+
+ T
+
+
+
+
+ F
+
+
+ T
+
+
+ F
+
+
+ T
+
+
+ T
+
+
+ F
+
+
+
+
+ F
+
+
+ F
+
+
+ F
+
+
+ F
+
+
+ T
+
+
+ T
+
+
+
-
Also, Google has provided this short video showing different logical operators:
+
- WARNING!
-
There is a very common mistake that occurs when programmers try to write boolean expressions. For example, what if we have a variable number and we want to check to see if its value is 5,6, or 7. In words we might say: number equal to 5 or 6 or 7. However, if we translate this into Python, number == 5 or 6 or 7, it will not be correct. The or operator must join the results of three equality checks. The correct way to write this is number == 5 or number == 6 or number == 7. This may seem like a lot of typing but it is absolutely necessary. You cannot take a shortcut.
+ WARNING!
+
There is a very common mistake that occurs when programmers try to write boolean expressions. For example, what if we have a variable number and we want to check to see if its value is 5,6, or 7. In words we might say: number equal to 5 or 6 or 7. However, if we translate this into Python, number == 5 or 6 or 7, it will not be correct. The or operator must join the results of three equality checks. The correct way to write this is number == 5 or number == 6 or number == 7. This may seem like a lot of typing but it is absolutely necessary. You cannot take a shortcut.
- Check your understanding
+ Check your understanding
-
-
-
What is a correct Python expression for checking to see if a number stored in a variable x is between 0 and 5?
-
-
-
-
-
x > 0 and < 5
-
-
- Each comparison must be between exactly two values. In this case the right-hand expression < 5 lacks a value on its left.
-
-
-
-
-
x > 0 or x < 5
-
-
- Although this is legal Python syntax, the expression is incorrect. It will evaluate to true for all numbers that are either greater than 0 or less than 5. Because all numbers are either greater than 0 or less than 5, this expression will always be True.
-
-
-
-
-
x > 0 and x < 5
-
-
- Yes, with an and keyword both expressions must be true so the number must be greater than 0 an less than 5 for this expression to be true. Although most other programming languages do not allow this mathematical syntax, in Python, you could also write 0 < x < 5.
-
-
-
+
+
+
What is a correct Python expression for checking to see if a number stored in a variable x is between 0 and 5?
+
+
+
+
+
x > 0 and < 5
+
+
+ Each comparison must be between exactly two values. In this case the right-hand expression < 5 lacks a value on its left.
+
+
+
+
+
x > 0 or x < 5
+
+
+ Although this is legal Python syntax, the expression is incorrect. It will evaluate to true for all numbers that are either greater than 0 or less than 5. Because all numbers are either greater than 0 or less than 5, this expression will always be True.
+
+
+
+
+
x > 0 and x < 5
+
+
+ Yes, with an and keyword both expressions must be true so the number must be greater than 0 an less than 5 for this expression to be true. Although most other programming languages do not allow this mathematical syntax, in Python, you could also write 0 < x < 5.
+
+
+
-
-
-
Say you are registering for next semester's classes. You have choice A, which is your art class, and choice B, which is your math class. You need both of them, but it's a race between time and luck.
- If you end up registering on time for choice A, but you don't get your choice B, which logical operators would be true?
-
-
-
-
-
A and B
-
-
- Both A and B need to be True in order for this to be True.
-
-
-
-
-
A or B
-
-
- Either A or B need to be True in order for this to be True.
-
-
-
-
-
not A
-
-
- A needs to be False in order for this to be True.
-
-
-
-
-
not B
-
-
- B needs to be False in order for this to be True.
-
-
-
+
+
+
Say you are registering for next semester's classes. You have choice A, which is your art class, and choice B, which is your math class. You need both of them, but it's a race between time and luck.
+ If you end up registering on time for choice A, but you don't get your choice B, which logical operators would be true?
+
+
+
+
+
A and B
+
+
+ Both A and B need to be True in order for this to be True.
+
+
+
+
+
A or B
+
+
+ Either A or B need to be True in order for this to be True.
+
+
+
+
+
not A
+
+
+ A needs to be False in order for this to be True.
+
+
+
+
+
not B
+
+
+ B needs to be False in order for this to be True.
+
+
+
-Logical Opposites
Each of the six relational operators has a logical opposite: for example, suppose we can get a driving licence when our age is greater or equal to 17, we can not get the driving licence when we are less than 17.
The flow of control for this example can be seen in this flowchart illustration.
Here is a complete program that defines values for x and y. Run the program and see the result. Then change the values of the variables to change the flow of control.
-
+
x = 10
y = 10
@@ -41,7 +41,7 @@ else:
belongs to which if.
If you are still a bit unsure, here is the same selection as part of a codelens example. Step through it to see how the correct print is chosen.
-
+
x = 10
y = 10
@@ -58,7 +58,7 @@ else:
Check your understanding
-
+
Will the following code cause an error?
diff --git a/pretext/Selection/OmittingtheelseClauseUnarySelection.ptx b/pretext/Selection/OmittingtheelseClauseUnarySelection.ptx
index 5ad91c115..98f7cae36 100644
--- a/pretext/Selection/OmittingtheelseClauseUnarySelection.ptx
+++ b/pretext/Selection/OmittingtheelseClauseUnarySelection.ptx
@@ -1,7 +1,7 @@
Omitting the else Clause: Unary Selection
-
+
Flowchart of an if with no else
@@ -10,7 +10,7 @@
This creates what is sometimes called unary selection.
In this case, when the condition evaluates to True, the statements are
executed. Otherwise the flow of execution continues to the statement after the body of the if.
-
+
x = 10
if x < 0:
@@ -22,7 +22,7 @@ print("This is always printed")
Check your understanding
-
+
What does the following code print?
@@ -78,7 +78,7 @@ The negative number -10 is not valid here
-
+
With the introduction of conditionals and branching, our programs are about to become more complex on average. This is a good time to introduce a technique
+ that will help you plan and structure your programs before you start writing the more complex code. That technique is to use pseudocode.
+
+
Pseudocode is a mix of English and code (in our case, Python) that
+ programmers use to plan out their programs.
+
+
Writing pseudocode can be helpful for reasons such as:
+
+
It's quicker to write than actual code!
+
It's readable to more people than actual code, and can still be critiqued like regular code.
+
It can help you to take on a large or confusing programming task.
+
It can help you to document your code with comments for yourself and others' readability.
+
+
+
There isn't necessarily a right or wrong syntax for pseudocode (except wrong would be if you just wrote the program!).
+ Your pseudocode and language will probably look different from this, but should be along the same lines.
+
+
Take the following prompt for a problem:
+
+
+
+ Write a program that takes in a fraction in the format NUMERATOR/DENOMINATOR
+ from the user and outputs the quotient and the remainder.
+ If the denominator is 0, print out an error message; if the denominator is anything else,
+ let the user run the program normally.
+
+
+
+
We can approach this problem first by writing the following pseudocode:
+
+
+take user input for fraction
+split the user input by "/"
+make a variable for numerator, type convert to int
+make a variable for denominator, type convert to int
+if the denominator is 0,
+ print an error message
+otherwise
+ make a variable for the numerator divided by denominator
+ make a variable for the numerator mod denominator
+ print out both variables
+
+
+
+
As you can see, this is basically just a high level outline of your program. It may help you
+ better see the control flow of your program, or even remind you to do the small things, like
+ converting your string input to an integer if necessary.
+
+
This pseudocode can then be more readily converted to Python:
This won't be something you see often, but let's reverse engineer and see what
+ existing Python code might look like in pseudocode.
+
+
+
+character = input()
+if character == "Yoda":
+ print("No! Try not. Do. Or do not. There is no try.")
+elif character == "Han Solo":
+ print("Never tell me the odds!")
+elif character == "Obi Wan Kenobi":
+ print("Use the Force, Luke.")
+else:
+ print("Character not found!")
+
+
+
+
We could write the following pseudocode for this program:
+
+
+take user input for a Star Wars character
+if the character is Yoda, print "No! Try not. Do. Or do not. There is no try."
+if the character is Han Solo, print "Never tell me the odds!"
+if the character is Obi Wan Kenobi, print "Use the Force, Luke."
+in all other cases, print that the character wasn't found
+
+
+
+
As you may start to notice, Python is so close to the English language that pseudocode can often
+ be quickly translated into code.
+
+
Feel free to use pseudocode on exams (for planning before writing code) and in your actual programs.
+
diff --git a/pretext/Strings/StringComparison.ptx b/pretext/Selection/StringComparison.ptx
similarity index 87%
rename from pretext/Strings/StringComparison.ptx
rename to pretext/Selection/StringComparison.ptx
index 18e900be0..1fdb4b30a 100644
--- a/pretext/Strings/StringComparison.ptx
+++ b/pretext/Selection/StringComparison.ptx
@@ -1,9 +1,9 @@
-
+String Comparison
The comparison operators also work on strings. To see if two strings are equal you simply write a boolean
expression using the equality operator.
-
+
word = "banana"
if word == "banana":
@@ -16,7 +16,7 @@ else:
lexicographical order.
This is similar to the alphabetical order you would use with a dictionary,
except that all the uppercase letters come before all the lowercase letters.
-
+
word = "zebra"
@@ -31,7 +31,7 @@ else:
It is probably clear to you that the word apple would be less than (come before) the word banana.
After all, a is before b in the alphabet. But what if we consider the words apple and Apple?
Are they the same?
It turns out, as you recall from our discussion of variable names, that uppercase and lowercase letters are considered to be different from one another. The way the computer knows they are different is that
- each character is assigned a unique integer value. A is 65, B is 66, and 5 is 53. The way you can
+ each character is assigned a unique integer value which is called character encoding, as you may recall from Character Classification section. For instance, A is 65, B is 66, a is 97, b is 98 and 5 is 53. The way you can
find out the so-called ordinal value for a given character is to use a character function called ord.
Humans commonly ignore capitalization when comparing two words. However, computers do not. A common way to address this issue is to convert strings to a standard
format, such as all lowercase, before performing the comparison.
There is also a similar function called chr that converts integers into their character equivalent.
diff --git a/pretext/Strings/Theinandnotinoperators.ptx b/pretext/Selection/Theinandnotinoperators.ptx
similarity index 73%
rename from pretext/Strings/Theinandnotinoperators.ptx
rename to pretext/Selection/Theinandnotinoperators.ptx
index 72b360b84..771621981 100644
--- a/pretext/Strings/Theinandnotinoperators.ptx
+++ b/pretext/Selection/Theinandnotinoperators.ptx
@@ -1,8 +1,8 @@
-
+The in and not in operators
The in operator tests if one string is a substring of another:
-
+
print('p' in 'apple')
print('i' in 'apple')
@@ -13,7 +13,7 @@ print('pa' in 'apple')
Note that a string is a substring of itself, and the empty string is a
substring of any other string. (Also note that computer scientists
like to think about these edge cases quite carefully!)
-
+
print('a' in 'a')
print('apple' in 'apple')
@@ -22,7 +22,7 @@ print('' in 'apple')
The not in operator returns the logical opposite result of in.
-
+
print('x' not in 'apple')
diff --git a/pretext/Selection/toctree.ptx b/pretext/Selection/toctree.ptx
index 981367449..f39344864 100644
--- a/pretext/Selection/toctree.ptx
+++ b/pretext/Selection/toctree.ptx
@@ -1,14 +1,18 @@
-4Selection
+4Branching
4
-4
-4
4
4
4
4
-4
+4
+4
+4
+4
+4
+4
+4
4
-4
+4
diff --git a/pretext/Selection/video-branching.ptx b/pretext/Selection/video-branching.ptx
new file mode 100644
index 000000000..e54f4cc78
--- /dev/null
+++ b/pretext/Selection/video-branching.ptx
@@ -0,0 +1,7 @@
+
+
+ Practice Video Lecture
+
Week 3 Video Lecture:
+
+
+
diff --git a/pretext/Selection/video-logic.ptx b/pretext/Selection/video-logic.ptx
new file mode 100644
index 000000000..f82b5f8c5
--- /dev/null
+++ b/pretext/Selection/video-logic.ptx
@@ -0,0 +1,7 @@
+
+
+ Practice Video Lecture
+
Week 4 Video Lecture:
+
+
+
diff --git a/pretext/SimplePythonData/Glossary.ptx b/pretext/SimplePythonData/Glossary.ptx
index 2ccfbf9d4..13454234b 100644
--- a/pretext/SimplePythonData/Glossary.ptx
+++ b/pretext/SimplePythonData/Glossary.ptx
@@ -25,10 +25,7 @@ n = n + 1
= is Python's assignment token, which should not be confused
with the mathematical comparison operator using the same symbol.
-
- class
-
see data type below
-
+
comment
Information in a program that is meant for other programmers (or anyone
diff --git a/pretext/SimplePythonData/Input.ptx b/pretext/SimplePythonData/Input.ptx
index d3cc2f98e..95da096fe 100644
--- a/pretext/SimplePythonData/Input.ptx
+++ b/pretext/SimplePythonData/Input.ptx
@@ -1,7 +1,7 @@
Input
-
+
The program in the previous section works fine but is very limited in that it only works with one value for total_secs. What if we wanted to rewrite the program so that it was more general. One thing we could
do is allow the user to enter any value they wish for the number of seconds. The program could then print the
proper result for that starting value.
@@ -18,7 +18,7 @@ n = input("Please enter your name: ")
happens the text that has been entered is returned from the input function,
and in this case assigned to the variable n. Make sure you run this example a number
of times and try some different names in the input box that appears.
-
+
n = input("Please enter your name: ")
print("Hello", n)
@@ -31,7 +31,7 @@ print("Hello", n)
To modify our previous program, we will add an input statement to allow the user to enter the number of seconds. Then
we will convert that string to an integer. From there the process is the same as before. To complete the example, we will
print some appropriate output.
-
+
str_seconds = input("Please enter the number of seconds you wish to convert")
total_secs = int(str_seconds)
@@ -49,7 +49,7 @@ print("Hrs=", hours, "mins=", minutes, "secs=", secs_finally_remaining)
Check your understanding
-
+
What is printed when the following statements execute?
@@ -95,7 +95,7 @@ print ( type(n) )
-
+
Click on all of the variables of type `int` in the code below
@@ -111,7 +111,7 @@ print ( type(n) )
-
+
Click on all of the variables of type `str` in the code below
@@ -120,7 +120,7 @@ print ( type(n) )
seconds = input("Please enter the number of seconds you wish to convert")hours = int(seconds) // 3600
- total_secs = int(seconds)
+ total_secs = int(seconds)secs_still_remaining = total_secs % 3600print(secs_still_remaining)
diff --git a/pretext/SimplePythonData/OperatorsandOperands.ptx b/pretext/SimplePythonData/OperatorsandOperands.ptx
index 4ae5e4825..88334eba6 100644
--- a/pretext/SimplePythonData/OperatorsandOperands.ptx
+++ b/pretext/SimplePythonData/OperatorsandOperands.ptx
@@ -14,80 +14,78 @@ hour * 60 + minute
minute / 60
5 ** 2
(5 + 9) * (15 - 7)
-
The tokens +, -, and *, and the use of parenthesis for grouping,
- mean in Python what they mean in mathematics. The asterisk (*) is the
- token for multiplication, and ** is the token for exponentiation.
- Addition, subtraction, multiplication, and exponentiation all do what you
- expect.
-
+
+
Python uses special characters called operators that perform the following operations:
+
+
+ addition
+
- subtraction
+
* multiplication
+
/ division
+
** exponentiation
+
() grouping
+
// integer division (round down division)
+
% modulo (remainder)
+
+
+
There are several other operators that we will learn in future chapters. But these are the ones that you're going to need more or less all of your assignments!
+
+
-print(2 + 3)
-print(2 - 3)
-print(2 * 3)
-print(2 ** 3)
-print(3 ** 2)
+print(2 + 3) # Addition operator, expected result is 5
+print(2 - 3) # Subtraction operator, expected result is -1
+print(2 * 3) # Multiplication operator, expected result is 6
+print(5 / 3) # Division operator, expected result is 1.6666666666666666
+print(3 ** 2) # Exponentiation operator, expected result is 9
+print(3*(2+4)) # Grouping operator, changes the precedence expected result is 18
-
When a variable name appears in the place of an operand, it is replaced with
- the value that it refers to before the operation is performed.
- For example, what if we wanted to convert 645 minutes into hours.
- In Python 3, division is denoted by the operator token / which always evaluates to a floating point
- result.
-
+
+
The first six operators have functionality that you're most probably pretty familiar with! On the other hand, we have two more operators that are used frequently in programming but not that much in math classes.
+These are integer division, and modulo.
+
+
In the previous example 5 / 3 resulted 1.66666666 . This is because / always returns a floating point result. However, in certain situations, we need an integer result from division.
+Integer division, or the // operator, divides the number, but rounds it down to the nearest integer. So for the previous example, 5 // 3 will result 1
+
+
The modulo operator, % yields
+ the remainder when the first operand is divided by the second (that's why you can also remember it as remainder operator). For example, 5 % 3 will result 2 as 5 = 3 * 1 + 2 .
+
+
-minutes = 645
-hours = minutes / 60
-print(hours)
+print(5//3) # Integer division operator, expected result is 1
+print(60//7) # Integer division operator, expected result is 8
+print(50//2) # Integer division operator works same as division operator when the result is integer
+
+print(5%3) # Modulo operator, expected result is 2
+print(60%7) # Modulo operator, expected result is 4
+print(4%2) # Modulo operator, expected result is 0
-
What if, on the other hand, we had wanted to know how many whole hours there
- are and how many minutes remain. To help answer this question, Python gives us a second flavor of
- the division operator. This version, called integer division, uses the token
- //. It always truncates its result down to the next smallest integer (to
- the left on the number line).
-
-
-print(7 / 4)
-print(7 // 4)
+
When a variable name appears in place of an operand,
+ python substitutes that variable name with its assigned value. For example, what if we wanted to convert 645 minutes into hours?
+
Pay particular attention to the first two examples above. Notice that the result of floating point division
- is 1.75 but the result of the integer division is simply 1.
- Take care that you choose the correct flavor of the division operator. If
- you're working with expressions where you need floating point values, use the
- division operator /. If you want an integer result, use //.
-
-
The modulus operator, sometimes also called the remainder operator or integer remainder operator works on integers (and integer expressions) and yields
- the remainder when the first operand is divided by the second. In Python, the
- modulus operator is a percent sign (%). The syntax is the same as for other
- operators.
-
-
-quotient = 7 // 3 # This is the integer division operator
-print(quotient)
-remainder = 7 % 3
-print(remainder)
-
-
-
In the above example, 7 divided by 3 is 2 when we use integer division and there is a remainder of 1 when we use the modulus operator.
-
The modulus operator turns out to be surprisingly useful. For example, you can
+
+
+
+
The modulo operator turns out to be surprisingly useful. For example, you can
check whether one number is divisible by another—if x % y is zero, then
x is divisible by y.
Also, you can extract the right-most digit or digits from a number. For
example, x % 10 yields the right-most digit of x (in base 10).
Similarly x % 100 yields the last two digits.
-
Finally, returning to our time example, the remainder operator is extremely useful for doing conversions, say from seconds,
+
+
The remainder operator is extremely useful for doing conversions, say from seconds,
to hours, minutes and seconds.
If we start with a number of seconds, say 7684, the following program uses integer division and remainder to convert to an easier form. Step through it to be sure you understand how the division and remainder operators are being used to
compute the correct values.
What value is printed when the following statement executes?
@@ -143,7 +143,7 @@ print(18 / 4)
-
+
What value is printed when the following statement executes?
@@ -187,7 +187,7 @@ print(18 // 4)
-
+
What value is printed when the following statement executes?
diff --git a/pretext/SimplePythonData/OrderofOperations.ptx b/pretext/SimplePythonData/OrderofOperations.ptx
index 7b5bfaf3e..9fc5a2732 100644
--- a/pretext/SimplePythonData/OrderofOperations.ptx
+++ b/pretext/SimplePythonData/OrderofOperations.ptx
@@ -1,7 +1,7 @@
Order of Operations
-
+
When more than one operator appears in an expression, the order of evaluation
depends on the rules of precedence. Python follows the same precedence
rules for its mathematical operators that mathematics does.
@@ -45,7 +45,7 @@
left-associative rule is the exponentiation operator **. A useful hint
is to always use parentheses to force exactly the order you want when
exponentiation is involved:
-
+
print(2 ** 3 ** 2) # the right-most ** operator gets done first!
print((2 ** 3) ** 2) # use parentheses to force the order you want!
@@ -59,13 +59,13 @@ print((2 ** 3) ** 2) # use parentheses to force the order you want!
Check your understanding
-
+
What is the value of the following expression:
16 - 2 * 5 // 3 + 1
-
+
@@ -103,7 +103,7 @@ print((2 ** 3) ** 2) # use parentheses to force the order you want!
-
+
As we have mentioned previously, it is legal to make more than one assignment to the
same variable. A new assignment makes an existing variable refer to a new value
(and stop referring to the old value).
-
+
bruce = 5
print(bruce)
@@ -23,7 +23,7 @@ print(bruce)
now, then a will always equal to b. In Python, an assignment statement can make
two variables refer to the same object and therefore have the same value. They appear to be equal. However, because of the possibility of reassignment,
they don't have to stay that way:
-
+
a = 5
b = a # after executing this line, a and b are now equal
@@ -51,7 +51,7 @@ print(a, b)
Check your understanding
-
+
After the following statements, what are the values of x and y?
diff --git a/pretext/SimplePythonData/StatementsandExpressions.ptx b/pretext/SimplePythonData/StatementsandExpressions.ptx
index bb8248800..0f281001e 100644
--- a/pretext/SimplePythonData/StatementsandExpressions.ptx
+++ b/pretext/SimplePythonData/StatementsandExpressions.ptx
@@ -1,7 +1,7 @@
Statements and Expressions
-
+
A statement is an instruction that the Python interpreter can execute. We
have only seen the assignment statement so far. Some other kinds of statements
that we'll see shortly are while statements, for statements, if
@@ -9,7 +9,7 @@
An expression is a combination of values, variables, operators, and calls
to functions. Expressions need to be evaluated. If you ask Python to print an expression, the interpreter
evaluates the expression and displays the result.
The evaluation of an expression produces a value, which is why expressions
can appear on the right hand side of assignment statements. A value all by
itself is a simple expression, and so is a variable. Evaluating a variable gives the value that the variable refers to.
-
+
y = 3.14
x = len("hello")
diff --git a/pretext/SimplePythonData/Typeconversionfunctions.ptx b/pretext/SimplePythonData/Typeconversionfunctions.ptx
index 098037cb5..edd005580 100644
--- a/pretext/SimplePythonData/Typeconversionfunctions.ptx
+++ b/pretext/SimplePythonData/Typeconversionfunctions.ptx
@@ -9,7 +9,7 @@
into an int. For floating point numbers, it discards the decimal portion of
the number - a process we call truncation towards zero on the number line.
Let us see this in action:
-
+
print(3.14, int(3.14))
print(3.9999, int(3.9999)) # This doesn't round to the closest int!
@@ -26,7 +26,7 @@ print(int("23bottles"))
bottles and rerun the program. You should see the integer 23.
The type converter float can turn an integer, a float, or a syntactically
legal string into a float.
The type converter str turns its argument into a string. Remember that when we print a string, the
quotes are removed. However, if we print the type, we can see that it is definitely str.
One of the most common forms of reassignment is an update where the new
value of the variable depends on the old. For example,
@@ -16,7 +16,7 @@ x = x + 1
resulting object. The fact that x appears on both sides does not matter. The semantics of the assignment
statement makes sure that there is no confusion as to the result. The visualizer makes this very clear.
-
+
x = 6 # initialize x
print(x)
@@ -32,7 +32,7 @@ print(x)
Updating a variable by adding 1 is called an increment; subtracting 1 is
called a decrement. Sometimes programmers also talk about bumping
a variable, which means the same as incrementing it by 1.
-
+
Check your understanding
-
+
What is printed when the following statements execute?
@@ -101,7 +101,7 @@ print(x)
-
+
What is printed when the following statements execute?
@@ -149,7 +149,7 @@ print(x)
-
+
Construct the code that will result in the value 134 being printed.
@@ -161,6 +161,24 @@ print(x)
+
+
+
The shorthand x += 1 can be used to signify the same thing as x = x + 1, and other operators such as subtraction and multiplication can do this too.
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
diff --git a/pretext/SimplePythonData/ValuesandDataTypes.ptx b/pretext/SimplePythonData/ValuesandDataTypes.ptx
index 7d916bd86..22b6ae15e 100644
--- a/pretext/SimplePythonData/ValuesandDataTypes.ptx
+++ b/pretext/SimplePythonData/ValuesandDataTypes.ptx
@@ -13,7 +13,7 @@
because they are enclosed in quotation marks.
If you are not sure what class a value falls into, Python has a function called
type which can tell you.
When we show the value of a string using the print function, such as in the third example above, the quotes are not present in the output. The
value of the string is the sequence of characters inside the quotes. The quotes are only necessary to help Python know what the value is.
-
You may have used function notation in a math class, like y = f(x), likely only for functions that act on a single numeric value, and produce a single numeric value. Python has no such restrictions: Inputs and outputs may be of any type.
-
In the Python shell, it is not necessary to use the print function to see the values shown above. The shell evaluates the Python function and automatically prints the result. For example, consider the shell session shown below. When
- we ask the shell to evaluate type("Hello, World!"), it responds with the appropriate answer and then goes on to
- display the prompt for the next use.
-
Python 3.1.2 (r312:79360M, Mar 24 2010, 01:33:18)
-[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
-Type "help", "copyright", "credits" or "license" for more information.
->>> type("Hello, World!")
-<class 'str'>
->>> type(17)
-<class 'int'>
->>> "Hello, World"
-'Hello, World'
->>>
-
Note that in the last example, we simply ask the shell to evaluate the string Hello, World. The result is as you might expect, the string itself.
+
In programming, a function is a subroutine, designed to perform a specific task. When you "call" a function, you're asking it to execute its task.
+ Functions can take in information, known as arguments, work with that information, and then often return a result.
+ For example, print() is a function which takes in a single string argument between the parentheses and performs the task:
+ Printing the string argument we provided to the terminal.
+
+
You will get more familiar with functions (and design your own functions!) in the following weeks.
+
Continuing with our discussion of data types, numbers with a decimal point belong to a class
called float, because these numbers are represented in a format called
floating-point. At this stage, you can treat the words class and type
interchangeably. We'll come back to a deeper understanding of what a class
is in later chapters.
Strings in Python can be enclosed in either single quotes (') or double
quotes (" - the double quote character), or three of the same separate quote characters (''' or """).
-
+
print(type('This is a string.') )
print(type("And so is this.") )
@@ -76,13 +68,13 @@ beard", and single quoted strings can have double quotes inside them, as in
'The knights who say "Ni!"'.
Strings enclosed with three occurrences of either quote symbol are called
triple quoted strings. They can contain either single or double quotes:
-
+
print('''"Oh no", she exclaimed, "Ben's bike is broken!"''')
Triple quoted strings can even span multiple lines:
-
+
print("""This message will span
several lines
@@ -93,7 +85,7 @@ of the text.""")
three-of-a-kind quotes to surround your strings. Once it has parsed the text of
your program or command, the way it stores the value is identical in all cases,
and the surrounding quotes are not part of the value.
-
+
print('This is a string.')
print("""And so is this.""")
@@ -105,7 +97,7 @@ print("""And so is this.""")
When you type a large integer, you might be tempted to use commas between
groups of three digits, as in 42,000. This is not a legal integer in
Python, but it does mean something else, which is legal:
Well, that's not what we expected at all! Because of the comma, Python chose to
treat this as a pair of values. In fact, the print function can print any number of values as long
as you separate them by commas. Notice that the values are separated by spaces when they are displayed.
One of the most powerful features of a programming language is the ability to
manipulate variables. A variable is a name that refers to a value.
@@ -41,7 +41,7 @@ pi = 3.14159
If you ask Python to evaluate a variable, it will produce the value
that is currently linked to the variable. In other words, evaluating a variable will give you the value that is referred to
by the variable.
To see this, read and then run the following program.
You'll notice we change the value of day three times, and on the third
assignment we even give it a value that is of a different type.
In order to get started learning any programming language there are a number of
concepts and ideas that are necessary.
The goal of this chapter is to introduce you to the basic vocabulary of programming and some of the fundamental
diff --git a/pretext/SimplePythonData/toctree.ptx b/pretext/SimplePythonData/toctree.ptx
index 74d9ecdd6..f2ac61a99 100644
--- a/pretext/SimplePythonData/toctree.ptx
+++ b/pretext/SimplePythonData/toctree.ptx
@@ -13,5 +13,5 @@
4
4
4
-4
+4
diff --git a/pretext/SimplePythonData/video-simpledata.ptx b/pretext/SimplePythonData/video-simpledata.ptx
new file mode 100644
index 000000000..462730cad
--- /dev/null
+++ b/pretext/SimplePythonData/video-simpledata.ptx
@@ -0,0 +1,8 @@
+
+
+ Practice Video Lecture
+
Our course mentor Ethan has generously put together short video lectures to culminate each weekly reading. Now that you have finished chapters 1 and 2, the video is embedded below.
+ It is not required, but you may find it helpful if the reading left you with questions.
+
+
+
diff --git a/pretext/Strings/ACollectionDataType.ptx b/pretext/Strings/ACollectionDataType.ptx
index 28d162cb1..c64156c3d 100644
--- a/pretext/Strings/ACollectionDataType.ptx
+++ b/pretext/Strings/ACollectionDataType.ptx
@@ -1,12 +1,11 @@
A Collection Data Type
-
So far we have seen built-in types like: int, float,
- bool, str and we've seen lists.
- int, float, and
- bool are considered to be simple or primitive data types because their values are not composed
+
+
So far we have seen built-in types like: int, float, and str.
+
int and float are considered to be simple or primitive data types because their values are not composed
of any smaller parts. They cannot be broken down.
- On the other hand, strings and lists are different from the others because they
+ On the other hand, strings (and lists that we will talk about next chapter) are different from the others because they
are made up of smaller pieces. In the case of strings, they are made up of smaller
strings each containing one character.
Types that are comprised of smaller pieces are called collection data types.
@@ -14,5 +13,6 @@
single entity (the whole), or we may want to access its parts. This ambiguity is useful.
Strings can be defined as sequential collections of characters. This means that the individual characters
that make up the string are assumed to be in a particular order from left to right.
-
A string that contains no characters, often referred to as the empty string, is still considered to be a string. It is simply a sequence of zero characters and is represented by ‘' or (two single or two double quotes with nothing in between).
+
A string that contains no characters, often referred to as the empty string, is still considered to be a string.
+
It is simply a sequence of zero characters and is represented by ‘' or (two single or two double quotes with nothing in between).
diff --git a/pretext/Strings/Characterclassification.ptx b/pretext/Strings/Characterclassification.ptx
index 88156c9c3..360cba2af 100644
--- a/pretext/Strings/Characterclassification.ptx
+++ b/pretext/Strings/Characterclassification.ptx
@@ -11,7 +11,7 @@
uppercase letters. string.punctuation comprises all the characters considered
to be punctuation. Run the following:
For more information consult the string module documentaiton (see Global Module Index).
-
+
For more information consult the string module documentation (see Global Module Index).
+
+More About ASCII
+
ASCII is abbreviated from American Standard Code for Information Interchange. As computers store data in numeric values, for each character (words, punctuations, etc) a specific number is assigned to represent it. This process is called character encoding. In order to exchange informations between different computers, a set of standards were needed, from which ASCII was born.
+
ASCII contains 128 characters, where each character is assigned with a specific number. For instance uppercase alphabet starts from A = 65, while lowercase alphabet starts from a = 97 and continues as b=98, c=99, so on. Due to its limited size, this standard is replaced by Unicode which contains thousands of characters, however still useful to understand and work on encoding.
+
+
+
+
+
+
+
This workspace is provided for your convenience. You can use this activecode window to try out anything you like.
A variable or value used to select a member of an ordered collection, such as
a character from a string, or an element from a list.
+
+ indexing ([])
+
Access a single character in a string using its position (starting from
+ 0). Example: 'This'[2] evaluates to 'i'.
+
+
+ length
+
Number of characters in a string. It can be found by (len) function Example:
+ len('happy') evaluates to 5.
+ optional parameter
A parameter written in a function header with an assignment to a
@@ -37,13 +47,11 @@
slice
A part of a string (substring) specified by a range of indices. More
generally, a subsequence of any sequence type in Python can be created
- using the slice operator (sequence[start:stop]).
-
-
- traverse
-
To iterate through the elements of a collection, performing a similar
- operation on each.
+ using the slice operator (sequence[start:stop]). Example: 'bananas and
+cream'[3:6] evaluates to ana (so does 'bananas and cream'[1:4]).
+
+
whitespace
Any of the characters that move the cursor without printing visible
diff --git a/pretext/Strings/IndexOperatorWorkingwiththeCharactersofaString.ptx b/pretext/Strings/IndexOperatorWorkingwiththeCharactersofaString.ptx
index 89670b19a..c3327fa19 100644
--- a/pretext/Strings/IndexOperatorWorkingwiththeCharactersofaString.ptx
+++ b/pretext/Strings/IndexOperatorWorkingwiththeCharactersofaString.ptx
@@ -8,7 +8,7 @@
It is also the case that the positions are named from right to left using negative numbers where -1 is the rightmost
index and so on.
Note that the character at index 6 (or -8) is the blank character.
-
+
school = "Luther College"
m = school[2]
@@ -34,7 +34,7 @@ print(lastchar)
To get the last letter of a string, you might be tempted to try something like
this:
-
+
fruit = "Banana"
sz = len(fruit)
@@ -24,7 +24,7 @@ print(last)
Since we started counting at zero, the six indexes are
numbered 0 to 5. To get the last character, we have to subtract 1 from
the length. Give it a try in the example above.
-
+
fruit = "Banana"
sz = len(fruit)
@@ -39,7 +39,7 @@ print(lastch)
Interestingly, the + operator does work with strings, but for strings, the
+ operator represents concatenation, not addition. Concatenation means
joining the two operands by linking them end-to-end. For example:
The * operator also works on strings. It performs repetition. For example,
'Fun'*3 is 'FunFunFun'. One of the operands has to be a string and the
other has to be an integer.
We previously saw that each turtle instance has its own attributes and
- a number of methods that can be applied to the instance. For example,
- we wrote tess.right(90) when we wanted the turtle object tess to perform the right method to turn
- to the right 90 degrees. The dot notation is the way we connect the name of an object to the name of a method
- it can perform.
-
Strings are also objects. Each string instance has its own attributes and methods. The most important attribute of the string is the collection of characters. There are a wide variety of methods. Try the following program.
-
-
-ss = "Hello, World"
-print(ss.upper())
+
We previously used a few functions like print() and len() where we place the variable inside the parentheses such as len(my_str). On the other hand, a method is a function that is attached to a specific Python object.
+ To access this function, we write the object, then a dot ., and then the name of the method. The "dot notation" is the way we connect the name of an object to the name of a method
+ it can perform. For example, we can write my_str.upper() when we want the string my_str to perform the upper() method to create an upper-case version of itself.
-tt = ss.lower()
-print(tt)
-
+
+
Remember that strings are immutable. Therefore, all string methods give us a new string and must be assigned to a new variable. The original string is unchanged.
+
+
+
+my_str = "Hello, World"
+my_str.upper()
+print(my_str) # my_str is unchanged!
+print(my_str.upper()) #Gives us the new string, we can print it or assign it to a variable
+my_new_str = my_str.upper()
+print(my_new_str)
+
In this example, upper is a method that can be invoked on any string object
to create a new string in which all the
- characters are in uppercase. lower works in a similar fashion changing all characters in the string
- to lowercase. (The original string ss remains unchanged. A new string tt is created.)
-
In addition to upper and lower, the following table provides a summary of some other useful string methods. There are a few activecode examples that follow so that you can try them out.
+ characters are in uppercase.
+
In addition to upper, the following table provides some useful string methods.
@@ -57,50 +57,6 @@ print(tt)
Returns a string in all lowercase
-
-
- capitalize
-
-
- none
-
-
- Returns a string with first character capitalized, the rest lower
-
-
-
-
- strip
-
-
- none
-
-
- Returns a string with the leading and trailing whitespace removed
-
-
-
-
- lstrip
-
-
- none
-
-
- Returns a string with the leading whitespace removed
-
-
-
-
- rstrip
-
-
- none
-
-
- Returns a string with the trailing whitespace removed
-
-
count
@@ -123,61 +79,6 @@ print(tt)
Replaces all occurrences of old substring with new
-
-
- center
-
-
- width
-
-
- Returns a string centered in a field of width spaces
-
-
-
-
- ljust
-
-
- width
-
-
- Returns a string left justified in a field of width spaces
-
-
-
-
- rjust
-
-
- width
-
-
- Returns a string right justified in a field of width spaces
-
-
-
-
- find
-
-
- item
-
-
- Returns the leftmost index where the substring item is found, or -1 if not found
-
-
-
-
- rfind
-
-
- item
-
-
- Returns the rightmost index where the substring item is found, or -1 if not found
-
-
index
@@ -186,75 +87,36 @@ print(tt)
item
- Like find except causes a runtime error if item is not found
-
-
-
-
- rindex
-
-
- item
-
-
- Like rfind except causes a runtime error if item is not found
-
-
-
-
- format
-
-
- substitutions
-
-
- Involved! See , below
+ Returns the leftmost index where the substring item is found, or error if not found
You should experiment with these
- methods so that you understand what they do. Note once again that the methods that return strings do not
- change the original. You can also consult the Python documentation for strings.
-
+ methods so that you understand what they do. Note once again that the methods that return strings do not
+ change the original.
+
-ss = " Hello, World "
+ss = "Hello, World"
els = ss.count("l")
print(els)
-print("***" + ss.strip() + "***")
-print("***" + ss.lstrip() + "***")
-print("***" + ss.rstrip() + "***")
-
news = ss.replace("o", "***")
print(news)
-
-
-
-
-food = "banana bread"
-print(food.capitalize())
-
-print("*" + food.center(25) + "*")
-print("*" + food.ljust(25) + "*") # stars added to show bounds
-print("*" + food.rjust(25) + "*")
-
-print(food.find("e"))
-print(food.find("na"))
-print(food.find("b"))
-
-print(food.rfind("e"))
-print(food.rfind("na"))
-print(food.rfind("b"))
+food = "banana Bread"
+print(food.lower())
print(food.index("e"))
+print(food.index("na")) #finds the index of the first occurence of "na"
+print(food.index("b"))
+print(food.index("B")) #remember that python is case sensitive!
- Yes, s[1] is y and the index of n is 5, so 5 y characters. It is important to realize that the index method has precedence over the repetition operator. Repetition is done last.
+ Yes, s[1] is y and the index of n is 5, so 5 y characters. It is important to realize that the index method has precedence over the repetition operator.
@@ -336,190 +198,4 @@ print(s[1] * s.index("n"))
-
-
- String Format Method
-
In grade school quizzes a common convention is to use fill-in-the blanks. For instance,
-
-
Hello _____!
-
-
and you can fill in the name of the person greeted, and combine
- given text with a chosen insertion. We use this as an analogy:
- Python has a similar
- construction, better called fill-in-the-braces. The string method format, makes
- substitutions into places in a string
- enclosed in braces. Run this code:
The string for the format method has a special form, with braces embedded.
- Such a string is called a format string. Places where
- braces are embedded are replaced by the value of an expression
- taken from the parameter list for the format method. There are many
- variations on the syntax between the braces. In this case we use
- the syntax where the first (and only) location in the string with
- braces has a substitution made from the first (and only) parameter.
-
In the code above, this new string is assigned to the identifier
- greeting, and then the string is printed.
-
The identifier
- greeting was introduced to break the operations into a clearer
- sequence of steps. However, since the value of greeting is only
- referenced once, it can be eliminated with the more concise
- version:
There can be multiple substitutions, with data of any type.
- Next we use floats. Try original price $2.50 with a 7% discount:
-
-
-origPrice = float(input('Enter the original price: $'))
-discount = float(input('Enter discount percentage: '))
-newPrice = (1 - discount/100)*origPrice
-calculation = '${} discounted by {}% is ${}.'.format(origPrice, discount, newPrice)
-print(calculation)
-
-
-
The parameters are inserted into the braces in order.
-
If you used the data suggested, this result is not satisfying.
- Prices should appear with exactly two places beyond the decimal point,
- but that is not the default way to display floats.
-
Format strings can give further information inside the braces
- showing how to specially format data.
- In particular floats can be shown with a specific number of decimal places.
- For two decimal places, put :.2f inside the braces for the monetary values:
-
-
-origPrice = float(input('Enter the original price: $'))
-discount = float(input('Enter discount percentage: '))
-newPrice = (1 - discount/100)*origPrice
-calculation = '${:.2f} discounted by {}% is ${:.2f}.'.format(origPrice, discount, newPrice)
-print(calculation)
-
-
-
The 2 in the format modifier can be replaced by another integer to round to that
- specified number of digits.
-
This kind of format string depends directly on the order of the
- parameters to the format method. There are other approaches that we will
- skip here, explicitly numbering substitutions and taking substitutions from a dictionary.
-
A technical point: Since braces have special meaning in a format
- string, there must be a special rule if you want braces to actually
- be included in the final formatted string. The rule is to double
- the braces: { { and }}. For example mathematical set
- notation uses braces. The initial and final doubled
- braces in the format string below generate literal braces in the
- formatted string:
-
a = 5
-b = 9
-setStr = 'The set is {{ {},{} }}.'.format(a, b)
-print(setStr)
-
Unfortunately, at the time of this writing, the ActiveCode format implementation has a bug,
- printing doubled braces, but standard Python prints {5, 9}.
-
You can have multiple placeholders indexing the same argument, or perhaps even have extra
- arguments that are not referenced at all:
-
-
-letter = """
-Dear {0} {2}.
- {0}, I have an interesting money-making proposition for you!
- If you deposit $10 million into my bank account, I can
- double your money ...
-"""
-
-print(letter.format("Paris", "Whitney", "Hilton"))
-print(letter.format("Bill", "Henry", "Gates"))
-
-
-
-
-
What is printed by the following statements?
-
-
-x = 2
-y = 6
-print('sum of {} and {} is {}; product: {}.'.format( x, y, x+y, x*y))
-
-
-
-
-
-
-
Nothing - it causes an error
-
-
- It is legal format syntax: put the data in place of the braces.
-
-
-
-
-
sum of {} and {} is {}; product: {}. 2 6 8 12
-
-
- Put the data into the format string; not after it.
-
-
-
-
-
-
-
- The numbers before the f in the braces give the number of digits to display after the decimal point.
-
-
-
-
-
2.3 2.34 2.34567
-
-
- Close, but round to the number of digits and display the full number of digits specified.
-
-
-
-
-
2.3 2.35 2.3456700
-
-
- Yes, correct number of digits with rounding!
-
-
-
-
-
diff --git a/pretext/Strings/StringMethods_optional.ptx b/pretext/Strings/StringMethods_optional.ptx
new file mode 100644
index 000000000..4d7b9edbb
--- /dev/null
+++ b/pretext/Strings/StringMethods_optional.ptx
@@ -0,0 +1,164 @@
+
+
+ Some Extra String Methods (Optional)
+
+
In addition to what we have seen in the previous section, the following table provides a summary of some other string methods. You don't have to memorize them.
+
+
+
+
+ Method
+
+
+ Parameters
+
+
+ Description
+
+
+
+
+ capitalize
+
+
+ none
+
+
+ Returns a string with first character capitalized, the rest lower
+
+
+
+
+ strip
+
+
+ none
+
+
+ Returns a string with the leading and trailing whitespace removed
+
+
+
+
+ lstrip
+
+
+ none
+
+
+ Returns a string with the leading whitespace removed
+
+
+
+
+ rstrip
+
+
+ none
+
+
+ Returns a string with the trailing whitespace removed
+
+
+
+
+ center
+
+
+ width
+
+
+ Returns a string centered in a field of width spaces
+
+
+
+
+ ljust
+
+
+ width
+
+
+ Returns a string left justified in a field of width spaces
+
+
+
+
+ rjust
+
+
+ width
+
+
+ Returns a string right justified in a field of width spaces
+
+
+
+
+ rfind
+
+
+ item
+
+
+ Returns the rightmost index where the substring item is found, or -1 if not found
+
+
+
+
+ find
+
+
+ item
+
+
+ Like index except returns -1 if item is not found
+
+
+
+
+ rindex
+
+
+ item
+
+
+ Like rfind except causes a runtime error if item is not found
+
+
+
+
+
You should experiment with these
+ methods so that you understand what they do. Note once again that the methods that return strings do not
+ change the original. You can also consult the Python documentation for strings.
One final thing that makes strings different from some other Python collection types is that
+
One important thing that makes strings different from some other Python collection types is that
you are not allowed to modify the individual characters in the collection. It is tempting to use the [] operator on the left side of an assignment,
with the intention of changing a character in a string. For example, in the following code, we would like to change the first letter of greeting.
-
+
greeting = "Hello, world!"
greeting[0] = 'J' # ERROR!
@@ -15,7 +15,7 @@ print(greeting)
runtime error TypeError: 'str' object does not support item assignment.
Strings are immutable, which means you cannot change an existing string. The
best you can do is create a new string that is a variation on the original.
-
+
greeting = "Hello, world!"
newGreeting = 'J' + greeting[1:]
@@ -28,7 +28,7 @@ print(greeting) # same as it was
The slice operator [n:m] returns the part of the string from the n'th character
to the m'th character, including the first but excluding the last. In other words, start with the character at index n and
- go up to but do not include the character at index m.
- This
- behavior may seem counter-intuitive but if you recall the range function, it did not include its end
- point either.
+ go up to but do not include the character at index m.
If you omit the first index (before the colon), the slice starts at the
beginning of the string. If you omit the second index, the slice goes to the
end of the string.
There is no Index Out Of Range exception for a slice.
A slice is forgiving and shifts any offending index to something legal.
In grade school quizzes a common convention is to use fill-in-the blanks. For instance,
+
+
Hello _____!
+
+
and you can fill in the name of the person greeted, and combine
+ given text with a chosen insertion. We use this as an analogy:
+ Python has a similar
+ construction, called a formatted string or an f-string. An f-string makes
+ substitutions into places in a string
+ enclosed in braces. Run this code:
The string has been formatted in a new way. We have included an f before the starting quotation mark.
+ Such a string is called an f-string. Places where
+ braces are embedded are replaced by the value of the expression inside the braces. There are many
+ variations on the syntax between the braces. In this case we use
+ the syntax where the first (and only) location in the string with
+ braces has the variable person. When this code is evaluated, the value of the person variable is placed in the string in this location.
+
In the code above, this new string is assigned to the identifier
+ greeting, and then the string is printed.
+
The identifier
+ greeting was introduced to break the operations into a clearer
+ sequence of steps. However, since the value of greeting is only
+ referenced once, it can be eliminated with the more concise
+ version:
There can be multiple substitutions, with data of any type.
+ Next we use floats. Try original price $2.50 with a 7% discount:
+
+
+origPrice = float(input('Enter the original price: $'))
+discount = float(input('Enter discount percentage: '))
+newPrice = (1 - discount/100)*origPrice
+calculation = f'${origPrice} discounted by {discount}% is ${newPrice}.'
+print(calculation)
+
+
+
If you used the data suggested, this result is not satisfying.
+ Prices should appear with exactly two places beyond the decimal point,
+ but that is not the default way to display floats.
+
F-strings can give further information inside the braces
+ showing how to specially format data.
+ In particular, floats can be shown with a specific number of decimal places.
+ For two decimal places, put :.2f inside the braces but after the variable name for the monetary values:
+
+
+origPrice = float(input('Enter the original price: $'))
+discount = float(input('Enter discount percentage: '))
+newPrice = (1 - discount/100)*origPrice
+calculation = f'${origPrice:.2f} discounted by {discount}% is ${newPrice:.2f}.'
+print(calculation)
+
+
+
The 2 in the format modifier can be replaced by another integer to round to that
+ specified number of digits.
+
A technical point: Since braces have special meaning in a format
+ string, there must be a special rule if you want braces to actually
+ be included in the final formatted string. The rule is to double
+ the braces: { { and }}. For example mathematical set
+ notation uses braces. The initial and final doubled
+ braces in the format string below generate literal braces in the
+ formatted string:
+
a = 5
+b = 9
+setStr = f'The set is {{ {a},{b} }}.'
+print(setStr)
+
+
+
+
What is printed by the following statements?
+
+
+x = 2
+y = 6
+print(f'sum of {x} and {y} is {x+y}; product: {x*y}.')
+
+
+
+
+
+
+
Nothing - it causes an error
+
+
+ It is legal format syntax.
+
+
+
+
+
sum of {} and {} is {}; product: {}.
+
+
+ Put the value of each expression in place of the braces.
+
+
+
+
+