{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python tour - MCS 275 Spring 2021 - David Dumas\n", "\n", "This is a quick tour of Python syntax and features that students can use as a reference. It is a written version of live coding examples from Lecture 2 of the course. It isn't completely systematic, and it doesn't include every detail of the language that is usually covered in prerequisite courses of MCS 275, but is meant to provide a way to refresh your memory of some of the most important Python features. The optional course texts or the [course materials from MCS 260](https://dumas.io/teaching/2020/fall/mcs260/index.html) provide more detailed information." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Contents\n", "\n", "* [Scripts vs REPL vs notebooks](#Scripts-vs-REPL-vs-notebooks)\n", "* [Variables, assignment, basic types](#Variables,-assignment,-basic-types)\n", "* [Arithmetic](#Arithmetic)\n", "* [Operations on strings](#Operations-on-strings)\n", "* [Boolean expressions and logic](#Boolean-expressions-and-logic)\n", "* [Numeric conversions](#Numeric-conversions)\n", "* [String conversions](#String-conversions)\n", "* [Useful features of strings](#Useful-features-of-strings)\n", "* [Printing stuff](#Printing-stuff)\n", "* [List basics](#List-basics)\n", "* [List slices](#List-slices)\n", "* [List conversion and membership testing](#List-conversion-and-membership-testing)\n", "* [Other useful list features](#Other-useful-list-features)\n", "* [String indexing](#String-indexing)\n", "* [Dictionaries](#Dictionaries)\n", "* [Conditionals: if-else-elif](#Conditionals:-if-else-elif)\n", "* [Loops](#Loops)\n", "* [Files](#Files)\n", "* [Comments](#Comments)\n", "* [Docstrings](#Docstrings)\n", "* [Functions](#Functions)\n", "* [Modules](#Modules)\n", "* [Classes](#Classes)\n", "\n", "If the links above don't work, it might mean you are viewing the notebook at GitHub and you can fix it by [opening this same document at nbviewer.jupyter.org](https://nbviewer.jupyter.org/github/daviddumas/mcs275spring2021/blob/master/samplecode/python_tour.ipynb)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Scripts vs REPL vs notebooks" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can run the python interpreter using the interpreter name, usually `python` or `python3`. It waits for commands to run, and prints the result of each one. This is the REPL.\n", "\n", "You can run a whole file of Python code using `python FILENAME.py` or `python3 FILENAME.py` (depending on the interpreter name).\n", "\n", "This document is a notebook, which is more like the REPL. Pieces of code appear in *cells*, and the value of the last expression in the cell is printed in the output. We'll talk about notebooks more in a future MCS 275 lecture. At the beginning, you can just treat this as a nicely formatted mix of text, code, and output." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Variables, assignment, basic types" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a variable by assignment. No separate declaration needed.\n", "x = 5\n", "\n", "# What's the value of x now?\n", "x" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# Change the value of x a few times; it can change types at any time\n", "x = 10 # an integer\n", "x = 3.25 # a float\n", "x = True # a boolean\n", "x = None # None (the null value)\n", "x = \"hello\" # a string" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Some integers\n", "1234\n", "1_000_000 # one million (_ is a separator that is ignored, like a comma)\n", "0x1e # hexadecimal\n", "0b1001 # binary\n", "# only the last value in a cell appears in the output, so you should see 9 = 0b1001 below" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3000000.0" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Some floats\n", "0.01\n", "-1.3\n", "3e6 # three million. \"e\" is for exponent, means 3 * 10**6" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# The only possible values of a boolean. Note capitalization\n", "True\n", "False # Output will only show this one; it's the last value in this cell" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# The only value of type `nonetype` is None. It is used as a \"null\", a signal of the absence of something.\n", "# Displaying a None in the REPL doesn't display anything at all, so this cell has no output\n", "None" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"It was time for MCS 275 lecture\\nbut I didn't zoom installed on my\\nlaptop.\"" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Some strings. Can use \" or ' for single-line strings, or \"\"\" or ''' for multi-line strings\n", "\"2021\" # This isn't a number! It is in quotes, so it is a string\n", "\"It was the best of times\"\n", "'It was the worst of times'\n", "\"\"\"It was time for MCS 275 lecture\n", "but I didn't zoom installed on my\n", "laptop.\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arithmetic" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# addition\n", "2+2" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "56" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# multiplication\n", "7*8" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.0" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# division yields a float, even if the result is an integer\n", "6/2" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "32" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# exponentiation is **, and not ^ which is used for this in some other languages\n", "2**5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The order of operations follows the mnemonic PEMDAS:\n", "* Parentheses\n", "* Exponents\n", "* Multiplication and division (equal precedence)\n", "* Addition and subtraction (equal precedence)\n", "Operations with the same precedence will be done in left-to-right order." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "10 / 2 / 5 # The leftmost division is done first, so this becomes (10/2) / 5 which is 1" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# modulus (remainder upon division) is %\n", "1271845 % 7 # This number is one more than a multiple of 7" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operations on strings" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'hello world'" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Join two strings\n", "\"hello\" + \" world\"" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'noooooooooooooooooooooooooooooo'" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Repeat a string many times using multiplication\n", "\"n\" + ( \"o\"*30 )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Boolean expressions and logic" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Compare numbers with <, >, =, <=, >=\n", "1 < 5" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "27 >= 27" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "27 > 27" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Equality is tested with ==\n", "8 == 9" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Strings compare by dictionary order, with < meaning earlier in dictionary\n", "\"aardvark\" < \"abalone\"" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"skunk\" < \"shark\"" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Capital letters come before lower case letters in this dictionary\n", "\"Zebra\" < \"airplane\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Numeric conversions" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1500" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Convert a string to an integer\n", "int(\"1500\")" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Convert string to integer, using a base other than 10\n", "int(\"1001\",2) # base 2 = binary, so we get 0b1001 = 9" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## String conversions" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'239.1'" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Convert anything to a string with str()\n", "# Not often needed. But for example you could use this to \n", "# get the digits of an integer, since a string lets you\n", "# access individual characters\n", "str(239.1)" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'False'" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "str(False)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'[2, 7, 5]'" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "str([2,7,5]) # Lists are formatted with spaces after the commas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Useful features of strings" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'HELLO'" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = \"Hello\"\n", "# Convert to upper case (returns the converted value, doesn't change s)\n", "s.upper()" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'hello'" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Convert to lower case\n", "s.lower()" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Test for prefix\n", "s.startswith(\"He\")" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Test for suffix\n", "s.endswith(\"llo\")" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# \"string in string\" tests for the presence of a substring\n", "\"car\" in \"racecar\"" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"aaa\" in \"banana\"" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'I wish I had a pet mouse so they could eat 16 seeds'" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# String formatting: .format(value, value, ...) formats the values and puts them into the string where\n", "# there are placeholders\n", "\n", "# Basic usage\n", "\"I wish I had a pet {} so they could eat {} {}\".format(\"mouse\",16,\"seeds\")" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'First you put on your socks, and THEN you put on your shoes'" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Placeholders can have numbers to indicate which of the arguments they should take\n", "# They are 0-based indices of the list of arguments to .format(...)\n", "\"First you put on your {1}, and THEN you put on your {0}\".format(\"shoes\",\"socks\")" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'I am 75.12 percent sure of it'" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Floating point placeholders can have a formatting directive in the format :X.Yf\n", "# where X,Y are integers. The number will be formatted to have a width of at least X characters,\n", "# Y of them after the decimal point. X is optional.\n", "\"I am {:3.2f} percent sure of it\".format(75.12345)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Rounding to tenths we find that pi is approximately 3.1'" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"Rounding to tenths we find that pi is approximately {:.1f}\".format(3.14159265359)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Printing stuff\n", "\n", "In a script, you won't see any output if your program just contains expressions, because in script mode, Python doesn't print the results of evaluating each line. You need to explicitly request output." ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello world\n" ] } ], "source": [ "# Display a message in the terminal\n", "print(\"Hello world\")\n", "# Note: This statement doesn't return a value!" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "What if I told you that MCS 275 was fun?\n", "Here is a list: [5, 4, 3, 1]\n" ] } ], "source": [ "# Can print multiple values. They'll be separated by spaces, by default\n", "print(\"What if I told you that MCS\",275,\"was fun?\")\n", "# print() can handle every built-in type\n", "print(\"Here is a list:\",[5,4,3,1])" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "banana\n" ] } ], "source": [ "# print() puts a newline at the end by default\n", "# This can be disabled\n", "print(\"ba\",end=\"\") # no newline after this one\n", "print(\"nana\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## List basics\n", "Lists are mutable ordered collections of elements accessible by integer index. They are similar to arrays in other languages." ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 7, 5]" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Lists are written with square brackets and commas\n", "[2,7,5]" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [], "source": [ "# Elements of a list can have different types.\n", "# Let's set up an example to work with in the next few cells.\n", "L = [ 1, \"fish\", 2, \"fish\", False, True, False, None, 5.25, \"last\"]" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Retrieve an element of a list using brackets with 0-based index.\n", "L[0] # first element" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'fish'" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L[3] # fourth element" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'last'" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Negative index means count from the end of the list, with -1 meaning last element\n", "L[-1]" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# len(listname) gives the length of the list `listname`\n", "len(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## List slices" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [], "source": [ "# Let's set up a sample list to work with (same one used in a previous section)\n", "L = [ 1, \"fish\", 2, \"fish\", False, True, False, None, 5.25, \"last\"]" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 'fish', False]" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Select a contiguous sublist using [start_idx:end_idx]\n", "# Includes the element at start_idx, but not end_idx\n", "# This is an example of a \"slice\"\n", "L[2:5] # Has 5-2 = 3 elements" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[True, False, None, 5.25, 'last']" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Slices that extend past the end of the list don't produce an error\n", "L[5:100000] # Elements 5 to 99999 requested, but we get 5 to 9" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 'fish', 2]" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Slices start at the beginning if the start index is missing\n", "L[:3] # first three elements" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['fish', False, True, False, None, 5.25, 'last']" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Slices end at the end if the end index is missing\n", "L[3:] # everything but the first three elements" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, False, False, 5.25]" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# You can specify that a slice should use a step size other than 1\n", "L[::2] # Every other element, starting at index 0" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['fish', 'fish', True, None, 'last']" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L[1::2] # Every other element, starting at index 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## List conversion and membership testing" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['a', 'b', 'c', 'd', 'e', 'f']" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Convert a string to a list to get a list of its characters\n", "list(\"abcdef\")" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [], "source": [ "# Let's set up a sample list to work with (same one used in a previous section)\n", "L = [ 1, \"fish\", 2, \"fish\", False, True, False, None, 5.25, \"last\"]" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Checking whether an item is an element of a list\n", "5.25 in L" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 in L" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"ball\" in L" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Other useful list features" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [], "source": [ "# set up a list to work with\n", "courses_taken = [ 260, 275 ]\n", "# Add an element at the end with append\n", "courses_taken.append(320) # doesn't return anything, it just modifies the list" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[260, 275, 320]" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# What's in the list now?\n", "courses_taken" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [], "source": [ "# An element of a list can be replaced using item assignment\n", "courses_taken[0] = 261 # change first element to 261" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[261, 275, 320]" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "courses_taken # Now, the first element should be 261" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "ename": "IndexError", "evalue": "list assignment index out of range", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# But you can't add new elements to the list with item assignment\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;31m# Only existing elements can be modified\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mcourses_taken\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m501\u001b[0m \u001b[0;31m# no item 3 right now, so this gives an error.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mIndexError\u001b[0m: list assignment index out of range" ] } ], "source": [ "# But you can't add new elements to the list with item assignment\n", "# Only existing elements can be modified\n", "courses_taken[3] = 501 # no item 3 right now, so this gives an error." ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "320" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# .pop() will remove and return the last element of a list\n", "courses_taken.pop()" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[261, 275]" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Notice that 320 is no longer in the list\n", "courses_taken" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# .index(elt) will find elt and return its position\n", "# or raise an exception if it is not found\n", "courses_taken.index(275) # should return 1 since courses_taken[1] is 275" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[261, 401, 275]" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# .insert(where,what) adds an element at a specific position\n", "# Afterward, listname[where] will be equal to `what`\n", "# Existing items in the list remain, but move to higher indices\n", "# to make room (if needed).\n", "courses_taken.insert(1,401) # Put 401 at index 1, i.e. make it the second element.\n", "courses_taken # Show the resulting list" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [], "source": [ "# Sort a list in place\n", "courses_taken.sort() # note lack of any return value" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[261, 275, 401]" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# But after the previous command, the list is now sorted\n", "courses_taken" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## String indexing" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'b'" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Strings also support integer indices and slices to get characters or substrings\n", "\"banana\"[0]" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'na'" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"banana\"[2:4]" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'aaa'" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"banana\"[1::2] # every other letter " ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'ananab'" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Reverse a string\n", "\"banana\"[::-1]" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "65" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Similar to lists, you can get the total number of characters in a string with len(...)\n", "len(\"If you have a garden and a library, you have everything you need.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Dictionaries\n", "Map keys to values. Keys can be of various types (but some restrictions, e.g. lists cannot be keys). Values can be arbitrary types. Written with {} and : to separate key from value." ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [], "source": [ "# Create a dictionary and bind the name \"d\" to it\n", "d = { \"department\": \"MSCS\", \"building\": 631, \"phd_granting\": True}" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'MSCS'" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Access the value associated with a key\n", "d[\"department\"]" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [], "source": [ "# Add a new key-value pair to the dictionary\n", "d[\"college\"] = \"LAS\"" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Test if a **key** is present\n", "\"building\" in d # True because \"building\" is a key of this dict" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# You can't use `in` to directly check if a value is present\n", "631 in d # False because 631 is not a key of this dict" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Conditionals: if-else-elif" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "7 is larger\n" ] } ], "source": [ "if 5 > 7:\n", " print(\"5 is larger\")\n", "else:\n", " print(\"7 is larger\")" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "15 is divixible by 3, but is NOT divisible by 6\n" ] } ], "source": [ "x = 15 # adjust this number and run the code to test other branches\n", "if x % 6 == 0: \n", " print(x,\"is divisible by 6\")\n", "elif x % 3 == 0:\n", " print(x,\"is divixible by 3, but is NOT divisible by 6\")\n", "else:\n", " print(x,\"is not divisible by 3 (and so not by 6 either)\")" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "carpeting contains pet as a substring\n", "In fact, it appears at index 3\n" ] } ], "source": [ "s = \"carpeting\" # change this word and run the code to test conditional\n", "if \"pet\" in s:\n", " print(s,\"contains pet as a substring\")\n", " print(\"In fact, it appears at index\",s.find(\"pet\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loops" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Found it: The number 2**15 = 32768 has 7 as a digit\n" ] } ], "source": [ "# Find a power of 2 that has 7 as a digit\n", "n = 1\n", "while \"7\" not in str(2**n):\n", " n = n + 1\n", "# The next line is not indented, so it only runs when the loop is finished\n", "print(\"Found it: The number 2**{} = {} has 7 as a digit\".format(n,2**n))" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Available drink: coffee\n", "Available drink: tea\n", "Available drink: juice\n" ] } ], "source": [ "# Take each element of a list and print it\n", "available_drinks = [\"coffee\",\"tea\",\"juice\"]\n", "for drink in available_drinks:\n", " print(\"Available drink:\",drink)" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "department = MSCS\n", "building = 631\n", "phd_granting = True\n" ] } ], "source": [ "# Take each key of a dictionary and do something with it\n", "dept_data = { \"department\": \"MSCS\", \"building\": 631, \"phd_granting\": True}\n", "for field in dept_data:\n", " print(\"{} = {}\".format(field,dept_data[field]))" ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "department = MSCS\n", "building = 631\n", "phd_granting = True\n" ] } ], "source": [ "# Dictionaries support retrieving key,value pairs\n", "# which can be unpacked into two variables in a loop\n", "for field,value in dept_data.items():\n", " print(\"{} = {}\".format(field,value))" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n", "4\n", "8\n", "16\n", "32\n", "64\n", "128\n", "The loop ended, so the next element of L must have contained the digit 5\n" ] } ], "source": [ "# Break out of a loop early with `break`\n", "L = [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]\n", "for x in L:\n", " if \"5\" in str(x):\n", " # if we hit an integer containing digit 5, we stop the loop\n", " break\n", " print(x)\n", "print(\"The loop ended, so the next element of L must have contained the digit 5\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Files\n", "Be careful: It can be dangerous to run file-related commands, because **opening a file for writing will delete any existing file with that name**. It is important to make sure that any time you open a file for writing, the filename does not refer to an existing file whose contents you want to keep!" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [], "source": [ "# Open a new file (delete if it exists already) for writing\n", "output_file = open(\"output.txt\",\"wt\") # wt = write, text (not binary) file\n", "# Write some text to it. Note need to add our own newlines.\n", "output_file.write(\"Hello.\\n\")\n", "output_file.write(\"This is a text file.\\n\")\n", "output_file.write(\"That is all.\\n\")\n", "# Close the file (writes may not actually happen until now)\n", "output_file.close()" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello.\n", "This is a text file.\n", "That is all.\n", "\n" ] } ], "source": [ "# Open the file created above, for reading\n", "input_file = open(\"output.txt\",\"rt\")\n", "# Get everything in the file as a single string\n", "s = input_file.read()\n", "input_file.close()\n", "\n", "# Now print what we read from the file\n", "print(s)" ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I just read one more line from the file. The contents are:\n", "Hello.\n", "This line of the file has 7 characters\n", "\n", "I just read one more line from the file. The contents are:\n", "This is a text file.\n", "This line of the file has 21 characters\n", "\n", "I just read one more line from the file. The contents are:\n", "That is all.\n", "This line of the file has 13 characters\n", "\n" ] } ], "source": [ "# Process lines of that file one by one\n", "input_file = open(\"output.txt\",\"rt\")\n", "\n", "for line in input_file:\n", " print(\"I just read one more line from the file. The contents are:\")\n", " print(line,end=\"\") # line will already have a newline, most likely\n", " print(\"This line of the file has {} characters\\n\".format(len(line)))\n", "\n", "input_file.close()" ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The first time I read from the file I got:\n", "Hello.\n", "This is a text file.\n", "That is all.\n", "\n", "----------------------------------------------------------------------\n", "The second time I read from the file I got:\n", "\n", "(Expect nothing shown above, since we're already at the end of this file.)\n" ] } ], "source": [ "# Reading is a one-time operation. Trying to read file contents twice\n", "# gives no data the second time.\n", "input_file = open(\"output.txt\",\"rt\")\n", "s1 = input_file.read() # Read everything, after which we're at the end of the file\n", "s2 = input_file.read() # Reads nothing, already at the end of the file\n", "input_file.close()\n", "\n", "print(\"The first time I read from the file I got:\")\n", "print(s1)\n", "print(\"-\"*70)\n", "print(\"The second time I read from the file I got:\")\n", "print(s2) # will print nothing, because we read nothing\n", "print(\"(Expect nothing shown above, since we're already at the end of this file.)\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comments" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [], "source": [ "# In Python, any text after the symbol # on a line is ignored. This is a comment.\n", "# There is no multi-line comment syntax in Python; you just put # in front of each.\n", "\n", "x = 1 # You can also put comments on the same line as code\n", "\n", "# And # it is ok # for comments to contain # any number of # characters." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use comments to explain code, making it easier for humans to understand.\n", "\n", "Usually, a good comment doesn't just say what a line of code is doing, but explains *why*.\n", "\n", "A complete lack of comments is bad. Excessive comments are also bad, especially when they state the obvious. (This review document, which is expository and written for students relatively new to Python, has a number of comments that would be considered excessive/obvious in other contexts.)" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Square: 0\n", "Square: 1\n", "Square: 4\n", "Square: 9\n", "Square: 16\n", "Square: 25\n", "Square: 36\n", "Square: 49\n", "Square: 64\n", "Square: 81\n" ] } ], "source": [ "# EXAMPLE OF EXCESSIVE COMMENTS - they describe code that is already clear\n", "for i in range(10): # i from 0 to 9\n", " x = i*i # compute the square of i and store in x\n", " print(\"Square:\",x) # display the square just computed" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]\n" ] } ], "source": [ "# EXAMPLE OF INSUFFICIENT COMMENTS\n", "import math\n", "\n", "L = []\n", "for i in range(2,30):\n", " L.append(i)\n", " for j in range(2,math.floor(math.sqrt(i))+1):\n", " if i % j == 0:\n", " L.pop()\n", " break\n", "print(L)" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]\n" ] } ], "source": [ "# FIXING THE PREVIOUS EXAMPLE\n", "\"\"\"Find the primes up to 29 by the naive (inefficient) method\"\"\"\n", "import math # For sqrt\n", "\n", "L = [] # to hold the primes\n", "for i in range(2,30):\n", " L.append(i) # Add i to the list of primes for now; will remove later if composite\n", " # If i is composite, then one of its divisors is less than or equal to the\n", " # square root of i, so we need only check up to that point for divisors.\n", " for j in range(2,math.floor(math.sqrt(i))+1):\n", " if i % j == 0:\n", " # Now we know i is composite (divisible by j), so remove it from L and\n", " # exit the inner loop, moving on to the next prime candidate.\n", " L.pop()\n", " break\n", "print(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Docstrings\n", "\n", "In Python, the first statement in a file, function body, or class definition should be a string literal on a line by itself. It should contain a description of the file, function, or class. This is called a **docstring**.\n", "\n", "While having a string on a line by itself does nothing in Python, in these cases (first statement of file, function, class), Python will store the string and make it available as part of the built-in help.\n", "\n", "**Most explanatory text in a Python program should be in comments. Docstrings go in just a few special places, and describe a file, class, or function.**" ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello user!\n" ] } ], "source": [ "# Suppose this cell contains the full contents of hello.py\n", "# Print a greeting <--- this describes the file, but it isn't a docstring! Not a string literal\n", "# \"Print a greeting\" <--- also not a docstring. It's a comment, not a string literal\n", "\"\"\"Greet the user\"\"\" # <--- THIS IS A DOCSTRING\n", "\"\"\"by saying hello\"\"\" # BAD! Not a docstring, as it isn't the first statement.\n", " # It should be a commend instead\n", "\n", "# Comment line in the middle of the file. That's fine.\n", "\n", "\n", "print(\"Hello user!\")" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f(0.1) = 0.028000000000000004\n" ] } ], "source": [ "# This example involves functions. See the next section for details about functions.\n", "\n", "def f(x):\n", " \"\"\"Compute the 'smoothstep' polynomial at x and return.\"\"\" # <--- DOCSTRING (even without this comment)\n", " return 3*x**2 - 2*x**3\n", "\n", "print(\"f({}) = {}\".format(0.1,f(0.1)))" ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function f in module __main__:\n", "\n", "f(x)\n", " Compute the 'smoothstep' polynomial at x and return.\n", "\n" ] } ], "source": [ "# Retrieve help about f(...), which includes the docstring.\n", "help(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functions\n", "\n", "Functions provide reusable, named (usually) code blocks that can be called (run) at any point in a program, can accept data from the program, and can return data." ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "clamp(-0.30) = 0.00\n", "clamp(-0.20) = 0.00\n", "clamp(-0.10) = 0.00\n", "clamp(0.00) = 0.00\n", "clamp(0.10) = 0.10\n", "clamp(0.20) = 0.20\n", "clamp(0.30) = 0.30\n", "clamp(0.40) = 0.40\n", "clamp(0.50) = 0.50\n", "clamp(0.60) = 0.60\n", "clamp(0.70) = 0.70\n", "clamp(0.80) = 0.80\n", "clamp(0.90) = 0.90\n", "clamp(1.00) = 1.00\n", "clamp(1.10) = 1.00\n", "clamp(1.20) = 1.00\n", "clamp(1.30) = 1.00\n" ] } ], "source": [ "# Basic example\n", "\n", "def clamp(x):\n", " \"\"\"Clamp x between 0 and 1, i.e. if x is less than 0, return 0.\n", " If x is greater than 1, return 1. Otherwise return x.\"\"\"\n", " if x<0:\n", " return 0.0\n", " if x>1:\n", " return 1.0\n", " return x\n", "\n", "for i in range(17): # iterate over 0...16\n", " t = (i / 10) - 0.3 # so t ranges from -0.3 to 1.3, with steps of size 0.1\n", " print(\"clamp({:.2f}) = {:.2f}\".format(t,clamp(t)))" ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "clamp2(0.00,0.2,0.8) = 0.20\n", "clamp2(0.10,0.2,0.8) = 0.20\n", "clamp2(0.20,0.2,0.8) = 0.20\n", "clamp2(0.30,0.2,0.8) = 0.30\n", "clamp2(0.40,0.2,0.8) = 0.40\n", "clamp2(0.50,0.2,0.8) = 0.50\n", "clamp2(0.60,0.2,0.8) = 0.60\n", "clamp2(0.70,0.2,0.8) = 0.70\n", "clamp2(0.80,0.2,0.8) = 0.80\n", "clamp2(0.90,0.2,0.8) = 0.80\n", "clamp2(1.00,0.2,0.8) = 0.80\n" ] } ], "source": [ "# Functions can take multiple arguments, which are required if no default value is given\n", "def clamp2(x,minval,maxval):\n", " \"\"\"Clamp x between minval and maxval\"\"\"\n", " if xmaxval:\n", " return maxval\n", " return x\n", "\n", "for i in range(11): # iterate over 0...10\n", " t = (i / 10) # so t ranges from 0 to 1, with steps of size 0.1\n", " print(\"clamp2({:.2f},0.2,0.8) = {:.2f}\".format(t,clamp2(t,0.2,0.8)))" ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "clamp3(1.00) = 0.00\n", "clamp3(1.00,-1,1) = -0.20\n" ] } ], "source": [ "# Default values can be specified, and if they are, the argument is optional.\n", "def clamp3(x,minval=0.0,maxval=1.0):\n", " \"\"\"Clamp x between minval (default 0) and maxval (default 1)\"\"\"\n", " if xmaxval:\n", " return maxval\n", " return x\n", "\n", "print(\"clamp3({:.2f}) = {:.2f}\".format(t,clamp3(-0.2))) # minval, maxval get default values\n", "print(\"clamp3({:.2f},-1,1) = {:.2f}\".format(t,clamp3(-0.2,-1,1))) # minval, maxval specified" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.4\n" ] } ], "source": [ "# When calling a function, you can specify arguments by name using name=value syntax\n", "# These *keyword arguments* or *kwargs* can appear in any order, whereas arguments\n", "# given as values alone must appear in the same order as the definition.\n", "\n", "print(clamp3(minval=0.4,x=0.3)) # Using kwargs to choose the argument order\n", "\n", "# kwargs are really useful for functions with many arguments, most of which have default\n", "# values. Often you want to call them and change just a few arguments from defaults." ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello there!\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Functions don't need to return anything. If the `return` keyword is not used,\n", "# the function returns None\n", "\n", "def hello():\n", " \"\"\"Print a friendly greeting\"\"\"\n", " print(\"Hello there!\")\n", "\n", "hello() == None # True, because no return means return None" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modules\n", "\n", "Modules allow you to put a bunch of code in a separate file so it can be reused and is contained (allowing it to be used without the user worrying about all the details). Splitting code for a large program between multiple files also makes it easier to browse the source and to maintain the program." ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [], "source": [ "#%%writefile polynomials.py\n", "# Example module\n", "# To actually use this, either:\n", "# 1) Save the entire cell contents in a file \"polynomials.py\"\n", "# or 2) Remove the # in front of the first line of this cell and run in a notebook\n", "\"\"\"Some useful polynomials and other functions\"\"\"\n", "\n", "USEFUL_CONST = 1234.0 # all caps is *not* required\n", "\n", "def nozeros(x):\n", " \"\"\"A quadratic polynomial with no real zeros\"\"\"\n", " return x**2 + 1\n", "\n", "def smoothstep(x):\n", " \"\"\"Smoothstep polynomial (clamped between 0 and 1)\"\"\"\n", " if x<0:\n", " return 0.0\n", " if x>1:\n", " return 1.0\n", " return 3*x**2 - 2*x**3\n", "\n" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1234.0\n", "1.04\n", "0.42525\n" ] } ], "source": [ "\"\"\"Example of using the polynomials module\"\"\"\n", "# (Won't work unless you've saved the cell above to polynomials.py in the same directory where\n", "# you are running this code.)\n", "\n", "import polynomials\n", "\n", "print(polynomials.USEFUL_CONST)\n", "print(polynomials.nozeros(0.2)) # should be 1.004\n", "print(polynomials.smoothstep(0.45)) # should be 0.42525" ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3.8.5 (default, Jul 28 2020, 12:59:40) \n", "[GCC 9.3.0]\n", "/usr/lib/python3/dist-packages/ipykernel_launcher.py\n" ] } ], "source": [ "# There are many useful modules in the Python standard library\n", "# A few examples follow\n", "\n", "import sys\n", "print(sys.version) # Python version\n", "print(sys.argv[0]) # Name of the currently running script" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Working...\n", "Done!\n", "It is now 1610652081.4329822 seconds since 0:00 on Jan 1 1970 GMT\n" ] } ], "source": [ "import time\n", "\n", "print(\"Working...\")\n", "time.sleep(1.25) # Wait for 3.1 seconds\n", "print(\"Done!\")\n", "\n", "print(\"It is now {} seconds since 0:00 on Jan 1 1970 GMT\".format(time.time()))" ] }, { "cell_type": "code", "execution_count": 111, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Files in the current directory:\n", "polynomials.py\n", "python_tour.html\n", "__pycache__\n", ".ipynb_checkpoints\n", "output.txt\n", "python_tour.ipynb\n", "mk_contents.py\n", "A file with name 'output.txt' exists in the current directory.\n" ] } ], "source": [ "import os\n", "\n", "print(\"Files in the current directory:\")\n", "for fn in os.listdir(\".\"):\n", " print(fn)\n", "\n", "# Check for a file that exists (for the instructor developing this worksheet)\n", "if os.path.exists(\"output.txt\"):\n", " print(\"A file with name '{}' exists in the current directory.\".format(\"output.txt\"))\n", "\n", "# Check for a file that does not exist\n", "if os.path.exists(\"worksheet1soln.ipynb\"):\n", " print(\"A file with name '{}' exists in the current directory.\".format(\"worksheet1soln.ipynb\"))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Classes\n", "\n", "In Python, classes provide a way to define custom types that combine attributes (data) and methods (behavior).\n", "\n", "They are the basis of object-oriented programming in Python.\n", "\n", "Classes can extend other classes, allowing customization of certain properties while reverting to the parent class behavior on others." ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Distance from (3,4) to the origin: 5.00\n", "Before moving: P.x=3, P.y=4\n", "Moving by (5,1)\n", "After moving: P.x=8, P.y=5\n" ] } ], "source": [ "# Basic 2D point class\n", "import math # for sqrt\n", "\n", "class Point:\n", " \"\"\"A point in the xy-plane\"\"\" # DOCSTRING\n", " def __init__(self,x,y):\n", " \"\"\"Initialize new point instance\"\"\"\n", " self.x = x\n", " self.y = y\n", " def translate(self,dx,dy):\n", " \"\"\"Move the point by a vector (dx,dy)\"\"\"\n", " self.x += dx\n", " self.y += dy\n", " def distance_to(self,other):\n", " \"\"\"Distance from this point to another one\"\"\"\n", " deltax = other.x - self.x\n", " deltay = other.y - self.y\n", " return math.sqrt(deltax**2 + deltay**2)\n", "\n", "P = Point(3,4) # Creates instance of Point, which calls __init__(...)\n", "print(\"Distance from (3,4) to the origin: {:.2f}\".format(P.distance_to(Point(0,0))))\n", "print(\"Before moving: P.x={}, P.y={}\".format(P.x,P.y))\n", "print(\"Moving by (5,1)\")\n", "P.translate(5,1) # Modifies P, returns nothing!\n", "print(\"After moving: P.x={}, P.y={}\".format(P.x,P.y))" ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on class Point in module __main__:\n", "\n", "class Point(builtins.object)\n", " | Point(x, y)\n", " | \n", " | A point in the xy-plane\n", " | \n", " | Methods defined here:\n", " | \n", " | __init__(self, x, y)\n", " | Initialize new point instance\n", " | \n", " | distance_to(self, other)\n", " | Distance from this point to another one\n", " | \n", " | translate(self, dx, dy)\n", " | Move the point by a vector (dx,dy)\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data descriptors defined here:\n", " | \n", " | __dict__\n", " | dictionary for instance variables (if defined)\n", " | \n", " | __weakref__\n", " | list of weak references to the object (if defined)\n", "\n" ] } ], "source": [ "# Class help includes docstrings of the class itself and its methods\n", "help(Point)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }