Python Tutorial

w3school.com
CS 88
Composing Programs


Python Installation and Distributions


Python Anaconda Distribution

Anaconda
Anaconda (Python distribution)
Uninstalling Anaconda

Anaconda is a distribution of the Python and R programming languages for scientific computing (data science, machine learning applications, large-scale data processing, predictive analytics, etc.), that aims to simplify package management and deployment. The distribution includes data-science packages suitable for Windows, Linux, and macOS. It is developed and maintained by Anaconda, Inc., which was founded by Peter Wang and Travis Oliphant in 2012.

Python Anaconda Distribution uses conda for package managing.


Anaconda Package Management: conda

conda is Anaconda package management service that included in Anaconda environment.
We will discuss conda later in Python PIP Chapter.


Python Official Distribution

Python.org

Python Official Distribution is managed and released by Python.org. Typically, you can always find the latest version of Python on python.org. Latest version usually meaning more powerful but lack of stable and third-party packages and environment supported. Therefore, the stable one is the best. Update Python carefully.


Python Package Management: pip

pip is Python package management service that included in Python environment.
We will discuss pip later in Python PIP Chapter.


Python Environment Introduction

Python Programming/Interactive mode

After you installed Python, you need to know how to run it.

Python has two basic modes: script and interactive. The normal mode is the mode where the scripted and finished .py files are run in the Python interpreter. Interactive mode is a command line shell which gives immediate feedback for each statement, while running previously fed statements in active memory. As new lines are fed into the interpreter, the fed program is evaluated both in part and in whole.

  • Python Script: Run in CLI Terminal
    • Launch Python Interactive Session
    • Run Python file .py, which saved complete Python code with no Error.
  • Python Interactive Session: Run in Python IDLE, or third-party code editor like Visual Studio Code (VSCode)
    • Run Python code, which could be one or more Python statements

CLI Terminal

Shell (computing)

In computing, a shell is a computer program which exposes an operating system’s services to a human user or other program. In general, operating system shells use either a command-line interface (CLI) or graphical user interface (GUI), depending on a computer’s role and particular operation. It is named a shell because it is the outermost layer around the operating system.

Command-line shells require the user to be familiar with commands and their calling syntax, and to understand concepts about the shell-specific scripting language (for example, bash).

Graphical shells place a low burden on beginning computer users, and are characterized as being easy to use. Since they also come with certain disadvantages, most GUI-enabled operating systems also provide CLI shells.

For MacOS user, open Other folder to launch Terminal. This manipulate is on Graphical shells.

Once you open Terminal, you can see a shell session. Now you have a Command-line shells.


Use CLI Terminal to Launch a Python Interactive Session

Type in python3 to launch Python Interactive Session

CLI
1
python3


Use CLI Terminal to Run a Python File

Type in python3 [script.py] to run a Python script named script.py

CLI
1
python3 script.py


Python Interactive Session

The symbols >>> are called doctests. Doctests explain what the function does by showing actual Python code. The lines underneath the >>> show the expected output from running the above Python code.


You can run any Python code on Python Interactive Session.

Python
1
2
3
4
5
>>> print('Hello Amber')
Hello Amber
>>> import datetime
>>> print(datetime.datetime.now())
2021-02-03 14:14:35.118648


doctest module

After you import A Layered Design Process, you can run code with >>> in VSCode or Jupyter.

Python
1
2
3
4
5
import doctest

x = 2021
>>> print(x)
# 2021

Python
1
2
3
4
5
6
# This is a little piece of magic to help you test functions against
# their doctest as you go.
# This is equivalent to `python3 -m doctest file.py`
import doctest
def test(fun, verbose=True):
doctest.run_docstring_examples(fun, None, name=fun.__name__, verbose=verbose)

Python File

When you open a Python file, you can see some Python comments and code.

  • Comments are surrounded by docstring
    • #: one line comment
    • ''' ''' or """ """: multiple line comments
  • Code is the main part of a Python script, so other than comments parts are code.
Python
1
2
3
4
5
6
7
8
9
10
11
# This is one line comment

'''
Thess are multiple line comments
Thess are multiple line comments
'''

"""
Thess are multiple line comments
Thess are multiple line comments
"""

CLI & Python Interactive Session Shortcuts

Table of keyboard shortcuts

Remember the following important and useful CLI Terminal Shortcuts could effectively save your time.

Other Keyboard

  • ↑/↓: Scroll through History of typed commands
  • Tab: Autocomplete command/file name
  • Tab more times: Show more potential matched files or command

Control

  • Ctrl-L: Clear screen
  • Ctrl-C: Abort current command/typing
  • Ctrl-Z: Pause execution of the current job
  • Ctrl-A: Move to beginning of line
  • Ctrl-E: Move to end of line
  • Ctrl-U: Erase line to the left
  • Ctrl-K: Erase line to the right
  • Ctrl-W: Erase word to the left
  • Ctrl-Y: Yank/paste previously erased string
  • Ctrl-R: Reverse search of history

Command

  • Cmd-Z: Undo the last operation
  • Cmd-R: Redo the last operation
  • Cmd-X: Cut the selection and store it in the clipboard
  • Cmd-C: Copy the selection into the clipboard
  • Cmd-V: Paste contents of clipboard at cursor
  • Cmd-+: Zoom in
  • Cmd--: Zoom out
  • Cmd-0: Zoom 100%

Python Tutor

Python Tutor
cs88


Python tutor is a website that allows you to write python code in your web browser and see it visualized step by step. Before we explain more, let’s experiment with it a little. First, head to the python tutor website


Python Data Types


Built-in Data Types

In programming, data type is an important concept.

Variables can store data of different types, and different types can do different things.

Python has the following data types built-in by default, in these categories:

  • Text Type: str
  • Numeric Types: int, float, complex
  • Sequence Types: list, tuple, range
  • Mapping Type: dict
  • Set Types: set, frozenset
  • Boolean Type: bool
  • Binary Types: bytes, bytearray, memoryview

Getting Data Type & Type Conversion


Getting Data Type

Python
1
type(<data>)


Type Conversion

You can convert from one type to another with the int(), float(), and complex() methods:

Note: You cannot convert complex numbers into another number type.


Python Numbers: int, float, complex


There are three numeric types in Python:

  • int
  • float
  • complex

int

int, or integer, is a whole number, positive or negative, without decimals, of unlimited length.

Python
1
2
3
4
5
6
7
x = 1
type(x)
# <class 'int'>

int(x) # convert other date type to int
type(x)
# <class 'int'>

float

Float, or “floating point number” is a number, positive or negative, containing one or more decimals.

Python
1
2
3
4
5
6
7
x = 1.0
type(x)
# <class 'float'>

x = float(x) # convert other date type to int
type(x)
# <class 'float'>

complex (Optional)

Complex number

Complex numbers are written with a j as the imaginary part.

Python
1
2
3
4
5
6
7
8
9
10
11
12
x = 3+5j
y = 5j
z = -5j

print(type(x))
# <class 'complex'>

print(type(y))
# <class 'complex'>

print(type(z))
# <class 'complex'>

Python Strings: str


String Literals

String literals in python are surrounded by either single quotation marks, or double quotation marks.

'hello' is the same as "hello".

You can display a string literal with the print() function.


Assign String to a Variable

Assigning a string to a variable is done with the variable name followed by an equal sign and the string.


Multiline Strings

You can assign a multiline string to a variable by using three quotes.

Python
1
2
3
4
5
6
7
ccp = """ The most crazy terrorist organization,
which is no democracy, no freedom, and no human right.
It must be destroyed on 2020."""
print(ccp)
# The most crazy terrorist organization,
# which is no democracy, no freedom, and no human right.
# It must be destroyed on 2020.

Strings are Arrays

Like many other popular programming languages, strings in Python are arrays of bytes representing unicode characters.

However, Python does not have a character data type, a single character is simply a string with a length of 1.

Square brackets can be used to access elements of the string.

Python
1
2
"Hello World!"[0]
# 'H'

String Slicing

You can return a range of characters by using the slice syntax.

Specify the start index and the end index, separated by a colon, to return a part of the string.

Python
1
2
"Hello World!"[0:5]
# 'Hello'

Negative Indexing

Use negative indexes to start the slice from the end of the string

Python
1
2
"Hello World!"[-3:-1] # Notice : means [x, y)
# 'ld'

String Length

To get the length of a string, use the len() function.

Python
1
2
len("Fxxk CCP")
# 8

Check String

To check if a certain phrase or character is present in a string, we can use the keywords in or not in.

Python
1
2
3
4
5
'!' in "Hello World!"
# True

'H' not in "Hello World!"
# False

String Concatenation

To concatenate, or combine, two strings you can use the + operator.

Python
1
2
print("Fxxk" + " CCP")
# Fxxk CCP

String Format

As we learned in the Python Variables chapter, we cannot combine strings and numbers like this:

Python
1
2
3
age = 36
txt = "My name is John, I am " + age
print(txt)

But we can combine strings and numbers by using the format() method!

The format() method takes the passed arguments, formats them, and places them in the string where the placeholders {} are:

Python
1
2
3
4
age = 36
txt = "My name is John, and I am {}"
print(txt.format(age))
# My name is John, and I am 36

The format() method takes unlimited number of arguments, and are placed into the respective placeholders.

Pythonquantity
1
2
3
4
5
itemno = 567
price = 49.95
myorder = "I want {} pieces of item {} for {} dollars."
print(myorder.format(quantity, itemno, price))
# I want 3 pieces of item 567 for 49.95 dollars.

You can use index numbers {0} to be sure the arguments are placed in the correct placeholders. The number in {} is index.

Python
1
2
3
4
5
6
quantity = 3
itemno = 567
price = 49.95
myorder = "I want to pay {2} dollars for {0} pieces of item {1}."
print(myorder.format(quantity, itemno, price))
# I want to pay 49.95 dollars for 3 pieces of item 567.

To make sure a string will display as expected, we can format the result with the format() method.


String format()

The format() method allows you to format selected parts of a string.

Sometimes there are parts of a text that you do not control, maybe they come from a database, or user input?

To control such values, add placeholders (curly brackets {}) in the text, and run the values through the format() method:

Add a placeholder where you want to display the price:

Python
1
2
3
4
5
6
7
age = 25

print("I am " + age + " year's old")
# TypeError: can only concatenate str (not "int") to str

print("I am {} year's old".format(age))
# I am 25 year's old

You can add parameters inside the curly brackets to specify how to convert the value:

Format the price to be displayed as a number with two decimals:

Python
1
2
3
4
5
age = 25

Introduction = "I am {:.2f} year's old"
print(Introduction.format(age))
# I am 25.00 year's old

Check out all formatting types in W3School String format() Reference.


Multiple Values

If you want to use more values, just add more values to the format() method:

Python
1
2
3
4
5
6
7
name = "Zacks"
age = 25
country = "United States"

Introduction = "I am {}, {:.2f} year's old, and live in {}."
print(Introduction.format(name, age, country))
# I am Zacks, 25.00 year's old, and live in United States.

Index Numbers

You can use index numbers (a number inside the curly brackets {0}) to be sure the values are placed in the correct placeholders:

Python
1
2
3
4
5
6
7
name = "Zacks"
age = 25
country = "United States"

Introduction = "I am {1}, {0:.2f} year's old, and live in {2}."
print(Introduction.format(age, name, country))
# I am Zacks, 25.00 year's old, and live in United States.

Also, if you want to refer to the same value more than once, use the index number:

Python
1
2
3
4
5
6
7
name = "Zacks"
age = 25
country = "United States"

Introduction = "I am {1}. {1} is {0:.2f} year's old, and live in {2}."
print(Introduction.format(age, name, country))
# I am Zacks. Zacks is 25.00 year's old, and live in United States.

Named Indexes

You can also use named indexes by entering a name inside the curly brackets {name}, but then you must use names when you pass the parameter values like the following:

Python
1
2
3
Introduction = "I am {name}. {name} is {age:.2f} year's old, and live in {country}."
print(Introduction.format(age = 25, name = "Zacks", country = "United States"))
# I am Zacks. Zacks is 25.00 year's old, and live in United State.
Python
1
2
3
4
5
6
7
name = "Zacks"
age = 25
country = "United States"

Introduction = "I am {name}. {name} is {age:.2f} year's old, and live in {country}."
print(Introduction.format(age, name, country))
# KeyError: 'name'

f-string

[Python String Formatting Best Practices]https://realpython.com/python-string-formatting/

Python 3.6 added a new string formatting approach called formatted string literals or “f-strings”. This new way of formatting strings lets you use embedded Python expressions inside string constants. Here’s a simple example to give you a feel for the feature:

Python
1
2
3
>>> name = 'Zacks'
>>> f'Hello, {name}!'
'Hello, Bob!'

= specifier

Starting from Python 3.8, f-strings support = specifier.

Python
1
2
3
4
5
6
7
8
9
name = 'Zacks'
role = 'Senior Data Engineer'

# old style
print(f'name = {name}, role = {role}')
# using '=' specifier
print(f'{name = }, {role = }')
# remove quotes
print(f'{name = !s}, {role = !s}')
1
2
3
name = Zacks, role = Senior Data Engineer
name = 'Zacks', role = 'Senior Data Engineer'
name = Zacks, role = Senior Data Engineer

inspect.cleandoc

inspect — Inspect live objects

inspect.cleandoc(doc)
Clean up indentation from docstrings that are indented to line up with blocks of code.

All leading whitespace is removed from the first line. Any leading whitespace that can be uniformly removed from the second line onwards is removed. Empty lines at the beginning and end are subsequently removed. Also, all tabs are expanded to spaces.

Python
1
2
3
4
5
6
7
8
9
10
11
12
def func():
name = 'Zacks'
role = 'Senior Data Engineer'

s = f"""
Hello, my name is {name}.
I'm a {role}
"""

print(s)

func()
1
2
3
4

Hello, my name is Zacks.
I'm a Senior Data Engineer

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from inspect import cleandoc

def func():
name = 'Zacks'
role = 'Senior Data Engineer'

s = f"""
Hello, my name is {name}.
I'm a {role}
"""

print(cleandoc(s))

func()
1
2
Hello, my name is Zacks.
I'm a Senior Data Engineer

Escape Character

To insert characters that are illegal in a string, use an escape character.

An escape character is a backslash \ followed by the character you want to insert.

An example of an illegal character is a double quote inside a string that is surrounded by double quotes

Python
1
2
3
txt = "We are the so-called "Vikings" from the north." # Notice you cannot put extra " in a pair of ".

txt = "We are the so-called \"Vikings\" from the north." # Using \ to escape the character
Code Result
\' Single Quote
\\ Backslash
\n New Line
\r Carriage Return
\t Tab
\b Backspace
\f Form Feed
\ooo Octal value
\xhh Hex value

Builtin-Methods

Method name Description
strip() The strip() method removes any whitespace from the beginning or the end
lower The lower() method returns the string in lower case
upper The upper() method returns the string in upper case
replace() The replace() method replaces a string with another string:
spilt The split() method splits the string into substrings if it finds instances of the separator
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
" Hello World!       ".strip()
# 'Hello World!'

" Hello World! ".lower()
# ' hello world! '

" Hello World! ".upper()
# ' HELLO WORLD! '

" Hello World! ".replace('H', 'A')
# ' Aello World! '

" Hello, World!".split(',')
# [' Hello', ' World!']

# None (the default value) means split according to any whitespace
" Hello World!".split()
# ['Hello', 'World!']

# Notice the difference
" Hello World!".split(' ')
# ['', 'Hello', 'World!']

String Methods

Here are other built-in method of string.

Note: All string methods returns new values. They do not change the original string.

Method Description
capitalize() Converts the first character to upper case
casefold() Converts string into lower case
center() Returns a centered string
count() Returns the number of times a specified value occurs in a string
encode() Returns an encoded version of the string
endswith() Returns true if the string ends with the specified value
expandtabs() Sets the tab size of the string
find() Searches the string for a specified value and returns the position of where it was found
format() Formats specified values in a string
format_map() Formats specified values in a string
index() Searches the string for a specified value and returns the position of where it was found
isalnum() Returns True if all characters in the string are alphanumeric
isalpha() Returns True if all characters in the string are in the alphabet
isdecimal() Returns True if all characters in the string are decimals
isdigit() Returns True if all characters in the string are digits
isidentifier() Returns True if the string is an identifier
islower() Returns True if all characters in the string are lower case
isnumeric() Returns True if all characters in the string are numeric
isprintable() Returns True if all characters in the string are printable
isspace() Returns True if all characters in the string are whitespaces
istitle() Returns True if the string follows the rules of a title
isupper() Returns True if all characters in the string are upper case
join() Joins the elements of an iterable to the end of the string
ljust() Returns a left justified version of the string
lower() Converts a string into lower case
lstrip() Returns a left trim version of the string
maketrans() Returns a translation table to be used in translations
partition() Returns a tuple where the string is parted into three parts
replace() Returns a string where a specified value is replaced with a specified value
rfind() Searches the string for a specified value and returns the last position of where it was found
rindex() Searches the string for a specified value and returns the last position of where it was found
rjust() Returns a right justified version of the string
rpartition() Returns a tuple where the string is parted into three parts
rsplit() Splits the string at the specified separator, and returns a list
rstrip() Returns a right trim version of the string
split() Splits the string at the specified separator, and returns a list
splitlines() Splits the string at line breaks and returns a list
startswith() Returns true if the string starts with the specified value
strip() Returns a trimmed version of the string
swapcase() Swaps cases, lower case becomes upper case and vice versa
title() Converts the first character of each word to upper case
translate() Returns a translated string
upper() Converts a string into upper case
zfill() Fills the string with a specified number of 0 values at the beginning

Python Booleans

Booleans represent one of two values: True or False.


Boolean Values

In programming you often need to know if an expression is True or False.

You can evaluate any expression in Python, and get one of two answers, True or False.

When you compare two values, the expression is evaluated and Python returns the Boolean answer.


Evaluate Values and Variables

The bool() function allows you to evaluate any value, and give you True or False in return,


Most Values are True

Almost any value is evaluated to True if it has some sort of content.

Any string is True, except empty strings.

Any number is True, except 0.

Any list, tuple, set, and dictionary are True, except empty ones.


Some Values are False

In fact, there are not many values that evaluates to False, except empty values, such as (), [], {}, "", the number 0, and the value None. And of course the value False evaluates to False.


Functions can Return a Boolean

Python also has many built-in functions that returns a boolean value, like the isinstance() function, which can be used to determine if an object is of a certain data type.

Python
1
2
3
x = 200
print(isinstance(x, int))
# True

Short Circuiting

https://cs88-website.github.io/sp21/lab/lab01/#boolean-operators

What do you think will happen if we type the following into Python?

Python
1
2
1 / 0
# ZeroDivisionError: division by zero

Try it out in Python! You should see a ZeroDivisionError. But what about this expression?

Python
1
2
True or 1 / 0
# True

It evaluates to True because Python’s and and or operators short-circuit. That is, they don’t necessarily evaluate every operand.

And what about this expression?

Python
1
2
1 / 0 or True
# ZeroDivisionError: division by zero

Try it out in Python! You should see a ZeroDivisionError.

And what is short-circuit? In my opinion, from left to right of the expression, which part satisfies True or False will return the result immediately and ignore the rest parts.

Operator Evaluates from left to right until: Example
AND The first “false-y” value False and 1 / 0 evaluates to False
OR The first “truth-y” value True or 1 / 0 evaluates to True

If and and or do not short-circuit, they just return the last value. This means that and and or don’t always return booleans when using truth-y and false-y values.

For example:

Python
1
2
True and 88
# 88

Here’s another little example:

Python
1
2
3
4
5
def divides(x, y):
"""
return True if x divides y
"""
return x and y % x == 0

Python Operators

Operators are used to perform operations on variables and values.

Python divides the operators in the following groups:

  • Arithmetic operators
  • Assignment operators
  • Comparison operators
  • Logical operators
  • Identity operators
  • Membership operators
  • Bitwise operators

Python Arithmetic Operators

Arithmetic operators are used with numeric values to perform common mathematical operations.

Operator Name
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulus
** Exponentiation
// Floor division

Python Assignment Operators

Assignment operators are used to assign values to variables:

Operator Example Same As
= x = 5 x = 5
+= x += 3 x = x + 3
-= x -= 3 x = x - 3
*= x *= 3 x = x * 3
/= x /= 3 x = x / 3
%= x %= 3 x = x % 3
//= x //= 3 x = x // 3
**= x **= 3 x = x ** 3
&= x &= 3 x = x & 3
|= x |= 3 x = x | 3
^= x ^= 3 x = x ^ 3
>>= x >>= 3 x = x >> 3
<<= x <<= 3 x = x << 3

Python Comparison Operators

Comparison operators are used to compare two values.

Operator Name
== Equal
!= Not equal
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to

Python Logical Operators

Logical operators are used to combine conditional statements.

Operator Description Example
and Returns True if both statements are true x < 5 and x < 10
or Returns True if one of the statements is true x < 5 or x < 4
not Reverse the result, returns False if the result is true not(x < 5 and x < 10)

Python Identity Operators

Identity operators are used to compare the objects, not if they are equal, but if they are actually the same object, with the same memory location.

Operator Description Example
is Returns true if both variables are the same object x is y
is not Returns true if both variables are not the same object x is not y
Python
1
2
3
4
5
6
7
8
9
10
11
12
a = [1, 2, 3]
b = a
c = [1, 2, 3]

print(a == b)
# True
print(a is b)
# True
print(a == c)
# True
print(a is c)
# False

Here, although a and c have the same elements, they point to two different objects.


Python Membership Operators

Membership operators are used to test if a sequence is presented in an object.

Operator Description Example
in Returns True if a sequence with the specified value is present in the object x in y
not in Returns True if a sequence with the specified value is not present in the object x not in y

Python Bitwise Operators

Bitwise operators are used to compare (binary) numbers.

Operator Name Description
& AND Sets each bit to 1 if both bits are 1
^ XOR Sets each bit to 1 if only one of two bits is 1
~ NOT Inverts all the bits
<< Zero fill left shift Shift left by pushing zeros in from the right and let the leftmost bits fall off
>> Signed right shift Shift right by pushing copies of the leftmost bit in from the left, and let the rightmost bits fall off
| OR Sets each bit to 1 if one of two bits is 1

Python Collections

There are four collection data types in the Python programming language:

  • List is a sequence which is ordered and changeable. Allows duplicate members.
  • Tuple is a sequence which is ordered and unchangeable. Allows duplicate members.
  • Set is a collection which is unordered and unindexed. No duplicate members.
  • Dictionary is a collection which is unordered, changeable and indexed. No duplicate members.
Ordered Unordered
changeable List Dictionary
unchangeable Tuple

List

A list is a collection which is ordered and changeable. In Python lists are written with square brackets.


Create a list

Python
1
2
3
4
l = [0, 1, 2, "list"]
print(l) # using print l or a single l to output the result.

# [0, 1, 2, 'list']

Access Items

The values in a list could be accessed by indexes. The first value is at index 0; the last value is at index -1; “-“ means accessed the countdown value; “:” means the range of indexes.

Python
1
2
3
4
5
6
7
8
9
10
l = [0, 1, 2, "list"]

l
# [0, 1, 2, 'list']

l[0]
# 0

l[-1]
# 'list'
Python
1
2
3
4
5
6
# List unpacking
l = [1, 2, 3]
a, b, c = l
print(a)
print(b)
print(c)

List Slicing

List slicing must start from left to right factors.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
l = [0, 1, 2, "list"]

l
# [0, 1, 2, 'list']

l[0:3]
# [0, 1, 2]

l[:3]
# [0, 1, 2]

l[1:-1]
# [1, 2]

l[1:]
# [1, 2, 'list']

Change Item Value

Python
1
2
3
4
5
l = [0, 1, 2, "list"]
l[-1] = 4

l
# [0, 1, 2, 4]

You can change plural values in list, even exceed the length of the list.

1
2
3
4
5
l = [0, 1, 2, 3]
l[2:] = 4, 5, 6, 8, 9 ,10

l
# [0, 1, 4, 5, 6, 8, 9, 10]

But you cannot using this method to directly add item.

Python
1
2
3
l = [0, 1, 2, 3]
l[5] = 5
# IndexError: list assignment index out of range

Check if Item Exists

To determine if a specified item is present in a list use the in keyword.

Python
1
2
3
4
5
6
7
l = [0, 1, 2, "list"]

'list' in l
# True

4 in l
# False

List Length

len() is function designed for getting the length of a list.

Python
1
2
3
l = [0, 1, 2, "list"]
len(l)
# 4

Add Items

append() is the function designed for adding one value at the last of the list.

Add item through +.

Python
1
2
3
4
5
l = [0, 1, 2, 3]
l = l + [4]

l
# [0, 1, 2, 3, 4]

Add item through append()

Python
1
2
3
4
5
l = [0, 1, 2, "list"]
l.append(4)

l
# [0, 1, 2, 'list', 4]

Add item from a list.

Python
1
2
3
4
5
l = [0, 1, 2, "list"]
l.append(l[0])

l
# [0, 1, 2, 'list', 0]

To add an item at the specified index, use the insert() method.

Python
1
2
3
4
l = [0, 1, 2, "list"]
l.insert(1, 0)
l
# [0, 0, 1, 2, 'list']

Remove Item

The pop() method removes the specified index, (or the last item if index is not specified).

Python
1
2
3
4
5
6
7
8
9
10
l = [0, 1, 2, "list"]
l.pop() # leave it blank to delete the last value

l
# [0, 1, 2]

l.pop(-1) # specify the value's index you want to delete

l
# [0, 1]

The remove() method removes the specified item.

Python
1
2
3
4
5
l = [0, 1, 2, "list"]
l.remove('list')

l
# [0, 1, 2]

The del keyword removes the specified index.

Python
1
2
3
4
5
6
7
8
9
10
l = [0, 1, 2, "list"]
del l[-1]

l
# [0, 1, 2]

del l

l
# NameError: name 'l' is not defined

The clear() method empties the list.

Python
1
2
3
4
l = [0, 1, 2, "list"]
l.clear()
l
# []

Copy a List

You CANNOT copy a list simply by typing list2 = list1, because: list2 will only be a reference to list1, and changes made in list1 will automatically also be made in list2.

There are ways to make a copy, one way is to use the built-in List method copy().

Copy the list and build a reference with it.

Python
1
2
3
4
5
6
7
8
9
10
11
12
# Create list areas
areas = [11.25, 18.0, 20.0, 10.75, 9.50]

# Create areas_copy
areas_copy = areas

# Change areas_copy
areas_copy[0] = 5.0

# Print areas
print(areas)
# [5.0, 18.0, 20.0, 10.75, 9.5]

Only copy the values of the list.

Python
1
2
3
4
5
6
7
8
9
10
11
12
# Create list areas
areas = [11.25, 18.0, 20.0, 10.75, 9.50]

# Create areas_copy
areas_copy = areas[:]

# Change areas_copy
areas_copy[0] = 5.0

# Print areas
print(areas)
# [11.25, 18.0, 20.0, 10.75, 9.5]

Only copy the values of the list.

Python
1
2
3
4
5
6
7
8
9
10
11
12
# Create list areas
areas = [11.25, 18.0, 20.0, 10.75, 9.50]

# Create areas_copy
areas_copy = areas.copy()

# Change areas_copy
areas_copy[0] = 5.0

# Print areas
print(areas)
# [11.25, 18.0, 20.0, 10.75, 9.5]

Join Two Lists

There are several ways to join, or concatenate, two or more lists in Python.

One of the easiest ways are by using the + operator.

Python
1
2
3
4
5
l1 = [0, 1, 2]
l2 = [4, 5, 6]
l3 = l1 + l2
l3
# [0, 1, 2, 4, 5, 6]

You can use the extend() method, which purpose is to add elements from one list to another list.

Python
1
2
3
4
l = [0, 1, 2, "list"]
l.extend(l)
l
# [0, 1, 2, 'list', 0, 1, 2, 'list']

The list() Constructor

It is also possible to use the list() constructor to make a new list.

Python
1
2
3
l = list(("apple", "banana", "cherry")) # note the double round-brackets
l
# ['apple', 'banana', 'cherry']

Built-in functions

Function name Description
len() return the length of the list
max() return the maximum value of the list
min() return the minimum value of the list
list() change a tuple to list

Built-in methods

Method name Description
append() Adds an element at the end of the list
clear() Removes all the elements from the list
copy() Returns a copy of the list
count() Returns the number of elements with the specified value
extend() Add the elements of a list (or any iterable), to the end of the current list
index() Returns the index of the first element with the specified value
insert() Adds an element at the specified position
pop() Removes the element at the specified position
remove() Removes the item with the specified value
reverse() Reverses the order of the list
sort() Sorts the list

List Comprehensions

Python | Convert list of tuples into list

The general syntax for a list comprehension is

Python
1
[<expression> for <element> in <sequence> if <conditional>]

The syntax is designed to read like English: “Compute the expression for each element in the sequence if the conditional is true.”

Python
1
2
3
4
a = [8, 4, 16, 20]
b = [x/2 for x in a]
print(b)
# [4.0, 2.0, 8.0, 10.0]
Python
1
2
3
4
5
6
7
8
9
# Python code to convert list of tuples into list

# List of tuple initialization
lt = [('Geeks', 2), ('For', 4), ('geek', '6')]

# Using list comprehension
out = [item for t in lt for item in t]
print(out)
# ['Geeks', 2, 'For', 4, 'geek', '6']

Python
1
2
[i**2 for i in [1, 2, 3, 4] if i%2 == 0]
# [4, 16]

is equivalent to

Python
1
2
3
4
5
6
l = []
for i in [1, 2, 3, 4]:
if i % 2 == 0:
lst += [i**2]
l
# [4, 16]

List Comprehensions with If statements

No else:

Python
1
2
[i for i in range(5) if i%2 == 0]
# [0, 2, 4]

Need else:

Python
1
2
[i if i%2 == 0 else None for i in range(5)]
# [0, None, 2, None, 4]

Tuple

A tuple is a collection which is ordered and unchangeable. In Python tuples are written with round brackets.

  • The parentheses are optional when defining tuples, and programmers frequently omit them if parentheses don’t clarify the code.

Create a tuple

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
l = [0, 1, 2]
type(l)
# list

t = (0, 1, 2)
type(t)
# tuple

t = 0, 1, 2
type(t)
# tuple

def func(x, y):
return x, y
results = func(1, 2)
type(results)
# tuple
Python
1
2
3
4
5
6
7
8
9
10
11
t = (0)
type(t)
# int

t = (0, 1)
type(t)
# tuple

t = (0,) # To create a tuple with only one item, you have add a comma after the item, unless Python will not recognize the variable as a tuple.
type(t)
# tuple

Access Tuple Items

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
t = (0, 1, 2, "tuple")

t
# (0, 1, 2, 'list')

t = 0, 1, 2, "tuple"

t
# (0, 1, 2, 'list')

t[0]
# 0

t[-1]
# 'tuple'
Python
1
2
3
4
5
6
# Tuple unpacking
t = 1, 2, 3
a, b, c = t
print(a)
print(b)
print(c)

Check if Item Exists

Python
1
2
3
4
5
6
7
t = 0, 1, 2, "tuple"

'tuple' in t
# True

4 in t
# False

Tuple Length

Python
1
2
3
4
t = 0, 1, 2, "tuple"

len(t)
# 4

Remove Items

Note: You cannot remove items in a tuple.

Tuples are unchangeable, so you cannot remove items from it, but you can delete the tuple completely.

Python
1
2
3
4
t = (0, 1, 2)
del t
t
# NameError: name 't' is not defined

Join Two Tuples

To join two or more tuples you can use the + operator:

Python
1
2
3
4
5
t1 = (0, 1, 2)
t2 = (3, 4, 5)
t3 = t1 + t2
t3
# (0, 1, 2, 3, 4, 5)

Define a changeable tuple

The factors in a tuple is unchangeable but the value in the factor is changeable.

Python
1
2
3
4
5
6
7
8
l = [4, 5]
t = (0, 1, 2, 3, l)
t
# (0, 1, 2, 3, [4, 5])

l.append(6)
t
# (0, 1, 2, 3, [4, 5, 6])

The tuple() Constructor

It is also possible to use the tuple() constructor to make a tuple.

Python
1
2
3
t = tuple(("apple", "banana", "cherry")) # note the double round-brackets
t
# ('apple', 'banana', 'cherry')

Built-in functions

Function name Description
len() return the length of the tuple
max() return the maximum value of the tuple
min() return the minimum value of the tuple
tuple() change a list to tuple

Built-in methods

Function name Description
count() Returns the number of times a specified value occurs in a tuple
index() Searches the tuple for a specified value and returns the position of where it was found

Set

A set is a collection which is unordered and unindexed. In Python sets are written with curly brackets.

  • A set is a data type for mutable unordered collections of unique elements. One application of a set is to quickly remove duplicates from a list.

Create a set

Python
1
2
3
4
5
6
7
8
s = {0, 1, 2}
s
# {0, 1, 2}

l = [0, 1, 1]
s = set(l)
s
# {0, 1}

Access Items

You cannot access items in a set by referring to an index, since sets are unordered the items has no index.

But you can loop through the set items using a for loop, or ask if a specified value is present in a set, by using the in keyword.


Change Items

Once a set is created, you cannot change its items, but you can add new items.

To add one item to a set use the add() method.

To add more than one item to a set use the update() method.

Python
1
2
3
4
5
6
7
8
s = {0, 1, 2}
s.add(4)
s
# {0, 1, 2, 4}

s.update([5, 6, 7])
s
# {0, 1, 2, 4, 5, 6, 7}

Remove Item

To remove an item in a set, use the remove(), or the discard() method.

  • remove() will raise an error if the item is not exist.
  • discard() will NOT raise an error if the item is not exist.

Join Two Sets

There are several ways to join two or more sets in Python.

You can use the union() method that returns a new set containing all items from both sets, or the update() method that inserts all the items from one set into another:

Python
1
2
3
4
5
6
7
8
9
s1 = {0, 1, 2}
s2 = {4, 5, 6}
s3 = s1.union(s2)
s3
# {0, 1, 2, 4, 5, 6}

s1.update(s2)
s1
# {0, 1, 2, 4, 5, 6}

Set Difference

Return the difference of two or more sets as a new set.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
s1 = {0, 1, 2}
s2 = {0, 1, 3}

s1 - s2
# {2}

s2 - s1
# {3}

s1.difference(s2)
# {2}

s2.difference(s1)
# {3}

Set symmetric_difference

Return the symmetric difference of two sets as a new set.

Python
1
2
3
4
5
s1 = {0, 1, 2}
s2 = {0, 1, 3}

s1.symmetric_difference(s2)
# {2, 3}

Set symmetric_difference_update

Update a set with the symmetric difference of itself and another.

Python
1
2
3
4
5
6
s1 = {0, 1, 2}
s2 = {0, 1, 3}

s1.symmetric_difference_update(s2)
s1
# {2, 3}

Set Intersection

Return the intersection of two sets as a new set.

Python
1
2
3
4
5
s1 = {0, 1, 2}
s2 = {0, 1, 3}

s1.intersection(s2)
# {0, 1}

Set Intersection update

Update a set with the intersection of itself and another.

Python
1
2
3
4
5
6
s1 = {0, 1, 2}
s2 = {0, 1, 3}

s1.intersection_update(s2)
s1
# {0, 1}

Check is subset

Report whether another set contains this set.

Python
1
2
3
4
5
6
7
8
s1 = {0, 1, 2}
s2 = {0, 1}

s1.issubset(s2)
# False

s2.issubset(s1)
# True

Check is superset

Report whether this set contains another set.

Python
1
2
3
4
5
6
7
8
s1 = {0, 1, 2}
s2 = {0, 1}

s1.issuperset(s2)
# True

s2.issuperset(s1)
# False

Check is no intersection

Python
1
2
3
4
5
6
7
8
9
s1 = {0, 1, 2}
s2 = {0, 1}
s3 = {3}

s1.isdisjoint(s2)
# False

s1.isdisjoint(s3)
# True

The set() Constructor

It is also possible to use the set() constructor to make a set.

Python
1
2
3
s = set(("apple", "banana", "cherry")) # note the double round-brackets
s
# {'apple', 'banana', 'cherry'}

Built-in method

Method Description
add() Adds an element to the set
clear() Removes all the elements from the set
copy() Returns a copy of the set
difference() Returns a set containing the difference between two or more sets
difference_update() Removes the items in this set that are also included in another, specified set
discard() Remove the specified item
intersection() Returns a set, that is the intersection of two other sets
intersection_update() Removes the items in this set that are not present in other, specified set(s)
isdisjoint() Returns whether two sets have a intersection or not
issubset() Returns whether another set contains this set or not
issuperset() Returns whether this set contains another set or not
pop() Removes an element from the set
remove() Removes the specified element
symmetric_difference() Returns a set with the symmetric differences of two sets
symmetric_difference_update() inserts the symmetric differences from this set and another
union() Return a set containing the union of sets
update() Update the set with the union of this set and others

Dictionary

A dictionary is a collection which is unordered, changeable and indexed. In Python dictionaries are written with curly brackets, and they have keys and values.

  • keys: int, float, or str

Create a dictionary

Python
1
2
3
4
5
6
7
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d
# {'brand': 'Ford', 'model': 'Mustang', 'year': 1964}
Python
1
2
3
4
5
d = {
1989: 64
}
d[1989]
# 64

Access Items

You can access the items of a dictionary by referring to its key name, inside square brackets.

Python
1
2
3
4
5
6
7
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d['brand']
# 'Ford'

There is also a method called get() that will give you the same result:

Python
1
2
3
4
5
6
7
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d.get('brand')
# 'Ford'

However, get() returns None while [] raises KeyError:

Python
1
2
3
4
5
6
7
8
9
10
11
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}

d.get('make')
#

d['make']
# KeyError: 'make'

You can use keys() to print all of the keys of the dictionary.

Python
1
2
3
4
5
6
7
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d.keys()
# dict_keys(['brand', 'model', 'year'])

Advanced get()

Example: Count the book title
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
book_title =  ['great', 'expectations','the', 'adventures', 'of', 'sherlock','holmes','the','great','gatsby','hamlet','adventures','of','huckleberry','fin']

word_counter = {}

# Count the item in book_title
for word in book_title:
if word not in word_counter:
word_counter[word] = 1
else:
word_counter[word] += 1

print(word_counter)
# {'holmes': 1, 'sherlock': 1, 'adventures': 2, 'fin': 1, 'expectations': 1, 'of': 2, 'huckleberry': 1, 'the': 2, 'hamlet': 1, 'great': 2, 'gatsby': 1}
Python
1
2
3
4
5
6
7
8
9
10
book_title =  ['great', 'expectations','the', 'adventures', 'of', 'sherlock','holmes','the','great','gatsby','hamlet','adventures','of','huckleberry','fin']

word_counter = {}

# Count the item in book_title
for word in book_title:
word_counter[word] = word_counter.get(word, 0) + 1

print(word_counter)
# {'adventures': 2, 'the': 2, 'of': 2, 'huckleberry': 1, 'great': 2, 'expectations': 1, 'sherlock': 1, 'hamlet': 1, 'holmes': 1, 'gatsby': 1, 'fin': 1}

Example: Count the fruit

You would like to count the number of fruits in your basket. In order to do this, you have the following dictionary and list of fruits. Use the dictionary and list to count the total number of fruits, but you do not want to count the other items in your basket.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# You would like to count the number of fruits in your basket. 
# In order to do this, you have the following dictionary and list of
# fruits. Use the dictionary and list to count the total number
# of fruits, but you do not want to count the other items in your basket.

result = 0
basket_items = {'apples': 4, 'oranges': 19, 'kites': 3, 'sandwiches': 8}
fruits = ['apples', 'oranges', 'pears', 'peaches', 'grapes', 'bananas']

#Iterate through the dictionary
for fruit in fruits:
result += basket_items.get(fruit, 0)

'''Same
for object, count in basket_items.items():
if object in fruits:
result += count
'''

#if the key is in the list of fruits, add the value (number of fruits) to result

print("There are {} fruits in the basket.".format(result))

Count all items

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# You would like to count the number of fruits in your basket. 
# In order to do this, you have the following dictionary and list of
# fruits. Use the dictionary and list to count the total number
# of fruits and not_fruits.

fruit_count, not_fruit_count = 0, 0
basket_items = {'apples': 4, 'oranges': 19, 'kites': 3, 'sandwiches': 8}
fruits = ['apples', 'oranges', 'pears', 'peaches', 'grapes', 'bananas']

#Iterate through the dictionary

#if the key is in the list of fruits, add to fruit_count.
for key, value in basket_items.items():
if key in fruits:
fruit_count += value
else:
not_fruit_count += value

#if the key is not in the list, then add to the not_fruit_count

print(fruit_count, not_fruit_count)

Example: Oscar

The following questions are based on data on Oscar Award Nominations for Best Director between the years 1931 to 2010. To start you off, we’ve provided a dictionary called “nominated” with the year (as key) and list of directors who were nominated in that year (as value). We’ve provided you with a different dictionary called “winners” with the year (as key) and list of directors who won the award in that year (as value).

Question 1

A. Create a dictionary that includes the count of Oscar nominations for each director in the nominations list.

B. Provide a dictionary with the count of Oscar wins for each director in the winners list.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
nominated = {1931: ['Norman Taurog', 'Wesley Ruggles', 'Clarence Brown', 'Lewis Milestone', 'Josef Von Sternberg'], 1932: ['Frank Borzage', 'King Vidor', 'Josef Von Sternberg'], 1933: ['Frank Lloyd', 'Frank Capra', 'George Cukor'], 1934: ['Frank Capra', 'Victor Schertzinger', 'W. S. Van Dyke'], 1935: ['John Ford', 'Michael Curtiz', 'Henry Hathaway', 'Frank Lloyd'], 1936: ['Frank Capra', 'William Wyler', 'Robert Z. Leonard', 'Gregory La Cava', 'W. S. Van Dyke'], 1937: ['Leo McCarey', 'Sidney Franklin', 'William Dieterle', 'Gregory La Cava', 'William Wellman'], 1938: ['Frank Capra', 'Michael Curtiz', 'Norman Taurog', 'King Vidor', 'Michael Curtiz'], 1939: ['Sam Wood', 'Frank Capra', 'John Ford', 'William Wyler', 'Victor Fleming'], 1940: ['John Ford', 'Sam Wood', 'William Wyler', 'George Cukor', 'Alfred Hitchcock'], 1941: ['John Ford', 'Orson Welles', 'Alexander Hall', 'William Wyler', 'Howard Hawks'], 1942: ['Sam Wood', 'Mervyn LeRoy', 'John Farrow', 'Michael Curtiz', 'William Wyler'], 1943: ['Michael Curtiz', 'Ernst Lubitsch', 'Clarence Brown', 'George Stevens', 'Henry King'], 1944: ['Leo McCarey', 'Billy Wilder', 'Otto Preminger', 'Alfred Hitchcock', 'Henry King'], 1945: ['Billy Wilder', 'Leo McCarey', 'Clarence Brown', 'Jean Renoir', 'Alfred Hitchcock'], 1946: ['David Lean', 'Frank Capra', 'Robert Siodmak', 'Clarence Brown', 'William Wyler'], 1947: ['Elia Kazan', 'Henry Koster', 'Edward Dmytryk', 'George Cukor', 'David Lean'], 1948: ['John Huston', 'Laurence Olivier', 'Jean Negulesco', 'Fred Zinnemann', 'Anatole Litvak'], 1949: ['Joseph L. Mankiewicz', 'Robert Rossen', 'William A. Wellman', 'Carol Reed', 'William Wyler'], 1950: ['Joseph L. Mankiewicz', 'John Huston', 'George Cukor', 'Billy Wilder', 'Carol Reed'], 1951: ['George Stevens', 'John Huston', 'Vincente Minnelli', 'William Wyler', 'Elia Kazan'], 1952: ['John Ford', 'Joseph L. Mankiewicz', 'Cecil B. DeMille', 'Fred Zinnemann', 'John Huston'], 1953: ['Fred Zinnemann', 'Charles Walters', 'William Wyler', 'George Stevens', 'Billy Wilder'], 1954: ['Elia Kazan', 'George Seaton', 'William Wellman', 'Alfred Hitchcock', 'Billy Wilder'], 1955: ['Delbert Mann', 'John Sturges', 'Elia Kazan', 'Joshua Logan', 'David Lean'], 1956: ['George Stevens', 'Michael Anderson', 'William Wyler', 'Walter Lang', 'King Vidor'], 1957: ['David Lean', 'Mark Robson', 'Joshua Logan', 'Sidney Lumet', 'Billy Wilder'], 1958: ['Richard Brooks', 'Stanley Kramer', 'Robert Wise', 'Mark Robson', 'Vincente Minnelli'], 1959: ['George Stevens', 'Fred Zinnemann', 'Jack Clayton', 'Billy Wilder', 'William Wyler'], 1960: ['Billy Wilder', 'Jules Dassin', 'Alfred Hitchcock', 'Jack Cardiff', 'Fred Zinnemann'], 1961: ['J. Lee Thompson', 'Robert Rossen', 'Stanley Kramer', 'Federico Fellini', 'Robert Wise', 'Jerome Robbins'], 1962: ['David Lean', 'Frank Perry', 'Pietro Germi', 'Arthur Penn', 'Robert Mulligan'], 1963: ['Elia Kazan', 'Otto Preminger', 'Federico Fellini', 'Martin Ritt', 'Tony Richardson'], 1964: ['George Cukor', 'Peter Glenville', 'Stanley Kubrick', 'Robert Stevenson', 'Michael Cacoyannis'], 1965: ['William Wyler', 'John Schlesinger', 'David Lean', 'Hiroshi Teshigahara', 'Robert Wise'], 1966: ['Fred Zinnemann', 'Michelangelo Antonioni', 'Claude Lelouch', 'Richard Brooks', 'Mike Nichols'], 1967: ['Arthur Penn', 'Stanley Kramer', 'Richard Brooks', 'Norman Jewison', 'Mike Nichols'], 1968: ['Carol Reed', 'Gillo Pontecorvo', 'Anthony Harvey', 'Franco Zeffirelli', 'Stanley Kubrick'], 1969: ['John Schlesinger', 'Arthur Penn', 'George Roy Hill', 'Sydney Pollack', 'Costa-Gavras'], 1970: ['Franklin J. Schaffner', 'Federico Fellini', 'Arthur Hiller', 'Robert Altman', 'Ken Russell'], 1971: ['Stanley Kubrick', 'Norman Jewison', 'Peter Bogdanovich', 'John Schlesinger', 'William Friedkin'], 1972: ['Bob Fosse', 'John Boorman', 'Jan Troell', 'Francis Ford Coppola', 'Joseph L. Mankiewicz'], 1973: ['George Roy Hill', 'George Lucas', 'Ingmar Bergman', 'William Friedkin', 'Bernardo Bertolucci'], 1974: ['Francis Ford Coppola', 'Roman Polanski', 'Francois Truffaut', 'Bob Fosse', 'John Cassavetes'], 1975: ['Federico Fellini', 'Stanley Kubrick', 'Sidney Lumet', 'Robert Altman', 'Milos Forman'], 1976: ['Alan J. Pakula', 'Ingmar Bergman', 'Sidney Lumet', 'Lina Wertmuller', 'John G. Avildsen'], 1977: ['Steven Spielberg', 'Fred Zinnemann', 'George Lucas', 'Herbert Ross', 'Woody Allen'], 1978: ['Hal Ashby', 'Warren Beatty', 'Buck Henry', 'Woody Allen', 'Alan Parker', 'Michael Cimino'], 1979: ['Bob Fosse', 'Francis Coppola', 'Peter Yates', 'Edouard Molinaro', 'Robert Benton'], 1980: ['David Lynch', 'Martin Scorsese', 'Richard Rush', 'Roman Polanski', 'Robert Redford'], 1981: ['Louis Malle', 'Hugh Hudson', 'Mark Rydell', 'Steven Spielberg', 'Warren Beatty'], 1982: ['Wolfgang Petersen', 'Steven Spielberg', 'Sydney Pollack', 'Sidney Lumet', 'Richard Attenborough'], 1983: ['Peter Yates', 'Ingmar Bergman', 'Mike Nichols', 'Bruce Beresford', 'James L. Brooks'], 1984: ['Woody Allen', 'Roland Joffe', 'David Lean', 'Robert Benton', 'Milos Forman'], 1985: ['Hector Babenco', 'John Huston', 'Akira Kurosawa', 'Peter Weir', 'Sydney Pollack'], 1986: ['David Lynch', 'Woody Allen', 'Roland Joffe', 'James Ivory', 'Oliver Stone'], 1987: ['Bernardo Bertolucci', 'Adrian Lyne', 'John Boorman', 'Norman Jewison', 'Lasse Hallstrom'], 1988: ['Barry Levinson', 'Charles Crichton', 'Martin Scorsese', 'Alan Parker', 'Mike Nichols'], 1989: ['Woody Allen', 'Peter Weir', 'Kenneth Branagh', 'Jim Sheridan', 'Oliver Stone'], 1990: ['Francis Ford Coppola', 'Martin Scorsese', 'Stephen Frears', 'Barbet Schroeder', 'Kevin Costner'], 1991: ['John Singleton', 'Barry Levinson', 'Oliver Stone', 'Ridley Scott', 'Jonathan Demme'], 1992: ['Clint Eastwood', 'Neil Jordan', 'James Ivory', 'Robert Altman', 'Martin Brest'], 1993: ['Jim Sheridan', 'Jane Campion', 'James Ivory', 'Robert Altman', 'Steven Spielberg'], 1994: ['Woody Allen', 'Quentin Tarantino', 'Robert Redford', 'Krzysztof Kieslowski', 'Robert Zemeckis'], 1995: ['Chris Noonan', 'Tim Robbins', 'Mike Figgis', 'Michael Radford', 'Mel Gibson'], 1996: ['Anthony Minghella', 'Joel Coen', 'Milos Forman', 'Mike Leigh', 'Scott Hicks'], 1997: ['Peter Cattaneo', 'Gus Van Sant', 'Curtis Hanson', 'Atom Egoyan', 'James Cameron'], 1998: ['Roberto Benigni', 'John Madden', 'Terrence Malick', 'Peter Weir', 'Steven Spielberg'], 1999: ['Spike Jonze', 'Lasse Hallstrom', 'Michael Mann', 'M. Night Shyamalan', 'Sam Mendes'], 2000: ['Stephen Daldry', 'Ang Lee', 'Steven Soderbergh', 'Ridley Scott', 'Steven Soderbergh'], 2001: ['Ridley Scott', 'Robert Altman', 'Peter Jackson', 'David Lynch', 'Ron Howard'], 2002: ['Rob Marshall', 'Martin Scorsese', 'Stephen Daldry', 'Pedro Almodovar', 'Roman Polanski'], 2003: ['Fernando Meirelles', 'Sofia Coppola', 'Peter Weir', 'Clint Eastwood', 'Peter Jackson'], 2004: ['Martin Scorsese', 'Taylor Hackford', 'Alexander Payne', 'Mike Leigh', 'Clint Eastwood'], 2005: ['Ang Lee', 'Bennett Miller', 'Paul Haggis', 'George Clooney', 'Steven Spielberg'], 2006: ['Alejandro Gonzaalez Inarritu', 'Clint Eastwood', 'Stephen Frears', 'Paul Greengrass', 'Martin Scorsese'], 2007: ['Julian Schnabel', 'Jason Reitman', 'Tony Gilroy', 'Paul Thomas Anderson', 'Joel Coen', 'Ethan Coen'], 2008: ['David Fincher', 'Ron Howard', 'Gus Van Sant', 'Stephen Daldry', 'Danny Boyle'], 2009: ['James Cameron', 'Quentin Tarantino', 'Lee Daniels', 'Jason Reitman', 'Kathryn Bigelow'], 2010: ['Darren Aronofsky', 'David O. Russell', 'David Fincher', 'Ethan Coen', 'Joel Coen', 'Tom Hooper']}
winners = {1931: ['Norman Taurog'], 1932: ['Frank Borzage'], 1933: ['Frank Lloyd'], 1934: ['Frank Capra'], 1935: ['John Ford'], 1936: ['Frank Capra'], 1937: ['Leo McCarey'], 1938: ['Frank Capra'], 1939: ['Victor Fleming'], 1940: ['John Ford'], 1941: ['John Ford'], 1942: ['William Wyler'], 1943: ['Michael Curtiz'], 1944: ['Leo McCarey'], 1945: ['Billy Wilder'], 1946: ['William Wyler'], 1947: ['Elia Kazan'], 1948: ['John Huston'], 1949: ['Joseph L. Mankiewicz'], 1950: ['Joseph L. Mankiewicz'], 1951: ['George Stevens'], 1952: ['John Ford'], 1953: ['Fred Zinnemann'], 1954: ['Elia Kazan'], 1955: ['Delbert Mann'], 1956: ['George Stevens'], 1957: ['David Lean'], 1958: ['Vincente Minnelli'], 1959: ['William Wyler'], 1960: ['Billy Wilder'], 1961: ['Jerome Robbins', 'Robert Wise'], 1962: ['David Lean'], 1963: ['Tony Richardson'], 1964: ['George Cukor'], 1965: ['Robert Wise'], 1966: ['Fred Zinnemann'], 1967: ['Mike Nichols'], 1968: ['Carol Reed'], 1969: ['John Schlesinger'], 1970: ['Franklin J. Schaffner'], 1971: ['William Friedkin'], 1972: ['Bob Fosse'], 1973: ['George Roy Hill'], 1974: ['Francis Ford Coppola'], 1975: ['Milos Forman'], 1976: ['John G. Avildsen'], 1977: ['Woody Allen'], 1978: ['Michael Cimino'], 1979: ['Robert Benton'], 1980: ['Robert Redford'], 1981: ['Warren Beatty'], 1982: ['Richard Attenborough'], 1983: ['James L. Brooks'], 1984: ['Milos Forman'], 1985: ['Sydney Pollack'], 1986: ['Oliver Stone'], 1987: ['Bernardo Bertolucci'], 1988: ['Barry Levinson'], 1989: ['Oliver Stone'], 1990: ['Kevin Costner'], 1991: ['Jonathan Demme'], 1992: ['Clint Eastwood'], 1993: ['Steven Spielberg'], 1994: ['Robert Zemeckis'], 1995: ['Mel Gibson'], 1996: ['Anthony Minghella'], 1997: ['James Cameron'], 1998: ['Steven Spielberg'], 1999: ['Sam Mendes'], 2000: ['Steven Soderbergh'], 2001: ['Ron Howard'], 2002: ['Roman Polanski'], 2003: ['Peter Jackson'], 2004: ['Clint Eastwood'], 2005: ['Ang Lee'], 2006: ['Martin Scorsese'], 2007: ['Ethan Coen', 'Joel Coen'], 2008: ['Danny Boyle'], 2009: ['Kathryn Bigelow'], 2010: ['Tom Hooper']}

### Question 1A: Create dictionary with the count of Oscar nominations for each director
nom_count_dict = {}
# Add your solution code below before line 10. Add more lines for your code as needed.
for year, directors in nominated.items():
for director in directors:
nom_count_dict[director] = nom_count_dict.get(director, 0) + 1


print("nom_count_dict = {}\n".format(nom_count_dict))
###################################################################################################################
###################################################################################################################

### Question 1B: Create dictionary with the count of Oscar wins for each director
win_count_dict = {}
# Add your solution code below before line 20. Add more lines for your code as needed.
for year, directors in winners.items():
for director in directors:
win_count_dict[director] = win_count_dict.get(director, 0) + 1


print("win_count_dict = {}".format(win_count_dict))

Question 2

Provide a list with the name(s) of the director(s) with the most Oscar wins. We are asking for a list because there could be more than 1 director tied for the most Oscar wins.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
winners = {1931: ['Norman Taurog'], 1932: ['Frank Borzage'], 1933: ['Frank Lloyd'], 1934: ['Frank Capra'], 1935: ['John Ford'], 1936: ['Frank Capra'], 1937: ['Leo McCarey'], 1938: ['Frank Capra'], 1939: ['Victor Fleming'], 1940: ['John Ford'], 1941: ['John Ford'], 1942: ['William Wyler'], 1943: ['Michael Curtiz'], 1944: ['Leo McCarey'], 1945: ['Billy Wilder'], 1946: ['William Wyler'], 1947: ['Elia Kazan'], 1948: ['John Huston'], 1949: ['Joseph L. Mankiewicz'], 1950: ['Joseph L. Mankiewicz'], 1951: ['George Stevens'], 1952: ['John Ford'], 1953: ['Fred Zinnemann'], 1954: ['Elia Kazan'], 1955: ['Delbert Mann'], 1956: ['George Stevens'], 1957: ['David Lean'], 1958: ['Vincente Minnelli'], 1959: ['William Wyler'], 1960: ['Billy Wilder'], 1961: ['Jerome Robbins', 'Robert Wise'], 1962: ['David Lean'], 1963: ['Tony Richardson'], 1964: ['George Cukor'], 1965: ['Robert Wise'], 1966: ['Fred Zinnemann'], 1967: ['Mike Nichols'], 1968: ['Carol Reed'], 1969: ['John Schlesinger'], 1970: ['Franklin J. Schaffner'], 1971: ['William Friedkin'], 1972: ['Bob Fosse'], 1973: ['George Roy Hill'], 1974: ['Francis Ford Coppola'], 1975: ['Milos Forman'], 1976: ['John G. Avildsen'], 1977: ['Woody Allen'], 1978: ['Michael Cimino'], 1979: ['Robert Benton'], 1980: ['Robert Redford'], 1981: ['Warren Beatty'], 1982: ['Richard Attenborough'], 1983: ['James L. Brooks'], 1984: ['Milos Forman'], 1985: ['Sydney Pollack'], 1986: ['Oliver Stone'], 1987: ['Bernardo Bertolucci'], 1988: ['Barry Levinson'], 1989: ['Oliver Stone'], 1990: ['Kevin Costner'], 1991: ['Jonathan Demme'], 1992: ['Clint Eastwood'], 1993: ['Steven Spielberg'], 1994: ['Robert Zemeckis'], 1995: ['Mel Gibson'], 1996: ['Anthony Minghella'], 1997: ['James Cameron'], 1998: ['Steven Spielberg'], 1999: ['Sam Mendes'], 2000: ['Steven Soderbergh'], 2001: ['Ron Howard'], 2002: ['Roman Polanski'], 2003: ['Peter Jackson'], 2004: ['Clint Eastwood'], 2005: ['Ang Lee'], 2006: ['Martin Scorsese'], 2007: ['Ethan Coen', 'Joel Coen'], 2008: ['Danny Boyle'], 2009: ['Kathryn Bigelow'], 2010: ['Tom Hooper']}


### For Question 2: Please provide a list with the name(s) of the director(s) with
### the most Oscar wins. The list can hold the names of multiple directors,
### since there can be more than 1 director tied with the most Oscar wins.

win_count_dict = {}
for year, directors in winners.items():
for director in directors:
win_count_dict[director] = win_count_dict.get(director, 0) + 1

highest_count = max(win_count_dict.values())
most_win_director = [key for key, value in win_count_dict.items() if value == highest_count]

print("most_win_director = {}".format(most_win_director))

Change Values

You can change the value of a specific item by referring to its key name.

Python
1
2
3
4
5
6
7
8
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d['year'] = 2020
d
# {'brand': 'Ford', 'model': 'Mustang', 'year': 2020}

You can updates the dictionary with the specified key-value pairs by using update().

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d.update({'brand': 'Ford', 'brand': 'Chevrolet'})
d
# {'brand': 'Chevrolet', 'model': 'Mustang', 'year': 1964}

d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d.update({'brand': 'Ford', 'brand': 'Chevrolet', 'year': 1964, 'year': 2020})
d
# {'brand': 'Chevrolet', 'model': 'Mustang', 'year': 2020}

Loop Through a Dictionary

You can loop through a dictionary by using a for loop.

When looping through a dictionary, the return value are the keys of the dictionary, but there are methods to return the values as well.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}

for x in d: # print keys one by one
print(x)
# brand
# model
# year

for x in d: # print values one by one
print(d[x])
# Ford
# Mustang
# 1964

You can also use the values() function to return values of a dictionary.

Python
1
2
3
4
5
for x in d.values():
print(x)
# Ford
# Mustang
# 1964

Loop through both keys and values, by using the items() function.

Python
1
2
3
4
5
for x, y in d.items():
print(x, y)
# brand Ford
# model Mustang
# Year 1964

Check if Key Exists

To determine if a specified key is present in a dictionary use the in keyword.

Python
1
2
3
4
5
6
7
8
9
10
11
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}

'brand' in d
# True

'Ford' in d
# False

Dictionary Length

As same as List.


Adding Items

Adding an item to the dictionary is done by using a new index key and assigning a value to it.

Python
1
2
3
4
5
6
7
8
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d['color'] = 'red'
d
# {'brand': 'Ford', 'model': 'Mustang', 'year': 1964, 'color': 'red'}

Removing Items

The pop() method removes the item with the specified key name.

Python
1
2
3
4
5
6
7
8
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d.pop('brand')
d
# {'model': 'Mustang', 'year': 1964}

The popitem() method removes the last inserted item (in versions before 3.7, a random item is removed instead)

Python
1
2
3
4
5
6
7
8
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d.popitem()
d
# {'brand': 'Ford', 'model': 'Mustang'}

The del keyword removes the item with the specified key name.

Python
1
2
3
4
5
6
7
8
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
del d['brand']
d
# {'model': 'Mustang', 'year': 1964}

The clear() keyword empties the dictionary.

Python
1
2
3
4
5
6
7
8
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d.clear()
d
# {}

Copy a Dictionary

copy(): As same as list.

Another way to make a copy is to use the built-in method dict().

Python
1
2
3
4
5
6
7
8
d = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
d2 = dict(d)
d2
# {'brand': 'Ford', 'model': 'Mustang', 'year': 1964}

Nested Dictionaries

A dictionary can also contain many dictionaries, this is called nested dictionaries.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
myfamily = {
"child1" : {
"name" : "Emil",
"year" : 2004
},
"child2" : {
"name" : "Tobias",
"year" : 2007
},
"child3" : {
"name" : "Linus",
"year" : 2011
}
}

myfamily
# {'child1': {'name': 'Emil', 'year': 2004},
# 'child2': {'name': 'Tobias', 'year': 2007},
# 'child3': {'name': 'Linus', 'year': 2011}}

Or, if you want to nest three dictionaries that already exists as dictionaries:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
child1 = {
"name" : "Emil",
"year" : 2004
}
child2 = {
"name" : "Tobias",
"year" : 2007
}
child3 = {
"name" : "Linus",
"year" : 2011
}

myfamily = {
"child1" : child1,
"child2" : child2,
"child3" : child3
}

myfamily
# {'child1': {'name': 'Emil', 'year': 2004},
# 'child2': {'name': 'Tobias', 'year': 2007},
# 'child3': {'name': 'Linus', 'year': 2011}}

Or you can let a list in the dict:

Python
1
2
3
4
5
6
7
8
d = {"color": []}
d["color"].append("Red")
d["color"].append("Yellow")

d
# {'color': ['Red', 'Yellow']}
d["color"]
# ['Red', 'Yellow']

If you just add item instead of using append() method, you will change the list to the str.

Python
1
2
3
4
5
6
7
8
9
10
11
d = {"color": []}
d["color"] = "Red"
d
# {'color': 'Red'}

d["color"] = "Yellow"
d
# {'color': 'Yellow'}

d["color"].append("Red")
# AttributeError: 'str' object has no attribute 'append'

Extract value from a nested dictionary:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Create a dict named data; data has one key.
data = {}
data['people'] = []

# Add three values to the key people.
data['people'].append({
'name': 'Scott',
'website': 'stackabuse.com',
'from': 'Nebraska'
})
data['people'].append({
'name': 'Larry',
'website': 'google.com',
'from': 'Michigan'
})
data['people'].append({
'name': 'Tim',
'website': 'apple.com',
'from': 'Alabama'
})

data["people"]
# [{'name': 'Scott', 'website': 'stackabuse.com', 'from': 'Nebraska'},
# {'name': 'Larry', 'website': 'google.com', 'from': 'Michigan'},
# {'name': 'Tim', 'website': 'apple.com', 'from': 'Alabama'}]

data["people"][0]
# {'name': 'Scott', 'website': 'stackabuse.com', 'from': 'Nebraska'}
data["people"][1]
# {'name': 'Larry', 'website': 'google.com', 'from': 'Michigan'}
data["people"][2]
# {'name': 'Tim', 'website': 'apple.com', 'from': 'Alabama'}

data["people"][0]["name"]
# 'Scott'
data["people"][0]["website"]
# 'stackabuse.com'
data["people"][0]["from"]
# 'Nebraska'

Extract value one by one in a nested dictionary:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Create a dict named data; data has one key.
data = {}
data['people'] = []

# Add three values to the key people.
data['people'].append({
'name': 'Scott',
'website': 'stackabuse.com',
'from': 'Nebraska'
})
data['people'].append({
'name': 'Larry',
'website': 'google.com',
'from': 'Michigan'
})
data['people'].append({
'name': 'Tim',
'website': 'apple.com',
'from': 'Alabama'
})

for i in data["people"]:
print(i["name"])
print(i["website"])
print(i["from"])
print("")
"""
Scott
stackabuse.com
Nebraska

Larry
google.com
Michigan

Tim
apple.com
Alabama
"""

The dict() Constructor

It is also possible to use the dict() constructor to make a new dictionary.

Python
1
2
3
4
5
d = dict(brand="Ford", model="Mustang", year=1964)
# note that keywords are not string literals
# note the use of equals rather than colon for the assignment
d
# {'brand': 'Ford', 'model': 'Mustang', 'year': 1964}

Dict Comprehension

Python Dictionary Comprehension Tutorial

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
d = {i: i**2 for i in range(-4, 0)}
d
# {-4: 16, -3: 9, -2: 4, -1: 1}

# Directly call max(dict) returns the max key
max(d)
# -1

# Find the key has max value
max(d, key=d.get)
# -4

# See how dict.get works
d.get(-4)
# 16

# Return the keys if the values < 10 and values are even
[k for (k, v) in d.items() if v < 10 if v%2 == 0]
# [-2]

# Return the keys and values if the values < 10 and values are even
{k:v for (k, v) in d.items() if v < 10 and v%2 == 0}
# {-2: 4}
{k:v for (k, v) in d.items() if v < 10 if v%2 == 0}
# {-2: 4}

# Return the keys and if the values are odd
{k: ('even' if v%2 == 0 else 'odd') for (k, v) in d.items()}
# {-4: 'even', -3: 'odd', -2: 'even', -1: 'odd'}

Built-in methods

Method Description
clear() Removes all the elements from the dictionary
copy() Returns a copy of the dictionary
fromkeys() Returns a dictionary with the specified keys and values
get() Returns the value of the specified key
items() Returns a list containing a tuple for each key value pair
keys() Returns a list containing the dictionary’s keys
pop() Removes the element with the specified key
popitem() Removes the last inserted key-value pair
setdefault() Returns the value of the specified key. If the key does not exist: insert the key, with the specified value
update() Updates the dictionary with the specified key-value pairs
values() Returns a list of all the values in the dictionary

Python Conditions


If … Else


Truth Value Testing

Constant defined to be false:

  • None and False

Zero of any numeric type

  • 0
  • 0.0
  • 0j

Empty sequences and collections

  • ""
  • ()
  • []
  • {}

Python Conditions and If statements

Python supports the usual logical conditions from mathematics:

  • Equals: a == b
  • Not Equals: a != b
  • Less than: a < b
  • Less than or equal to: a <= b
  • Greater than: a > b
  • Greater than or equal to: a >= b

hence conditions can be used in several ways, most commonly in “if statements” and loops.

An “if statement” is written by using the if keyword.

Python
1
2
3
4
5
6
a = 7
b = 5
result = ("{0} is greater than {1}")
if a > b:
print(result.format(a, b))
# 7 is greater than 5

Indentation

Python relies on indentation (whitespace at the beginning of a line) to define scope in the code. Other programming languages often use curly-brackets for this purpose.
Note: Tab and Space are both OK. But Tab is the better choice.

Python
1
2
3
4
5
6
a = 7
b = 5
result = ("{0} is greater than {1}")
if a > b:
print(result.format(a, b))
# IndentationError: expected an indented block

Elif

The elif keyword is pythons way of saying “if the previous conditions were not true, then try this condition”.

Python
1
2
3
4
5
6
7
8
a = 7
b = 10
result = ("{0} is greater than {1}")
if a > b:
print(result.format(a, b))
elif a < b:
print(result.format(b, a))
# 10 is greater than 7

Else

The else keyword catches anything which isn’t caught by the preceding conditions.

Python
1
2
3
4
5
6
7
8
9
10
a = 10
b = 10
result = ("{0} is greater than {1}")
if a > b:
print(result.format(a, b))
elif a < b:
print(result.format(b, a))
else:
print("{0} is equal to {1}".format(a, b))
# 10 is equal to 10
Python
1
2
3
4
5
6
7
8
a = 10
b = 10
result = ("{0} is greater than {1}")
if a > b:
print(result.format(a, b))
else:
print("{0} is not greater than {1}".format(a, b))
# 10 is not greater than 10

And

The and keyword is a logical operator, and is used to combine conditional statements:

Python
1
2
3
4
5
6
a = 10
b = 7
c = 5
if a > b and b > c:
print("{0} is greater than {1} and {1} is greater than {2}".format(a, b ,c))
# 10 is greater than 7 and 7 is greater than 5

Or

The or keyword is a logical operator, and is used to combine conditional statements:

Python
1
2
3
4
5
6
a = 10
b = 5
c = 7
if a > b or b > c:
print("{0} is greater than {1} or {1} is greater than {2}".format(a, b ,c))
# 10 is greater than 5 or 5 is greater than 7

Bad examples

Python
1
2
3
4
weather = "rain"
# Bad example
if weather == "snow" or "rain":
print("Wear boots!")
Python
1
2
3
4
5
6
weather = "rain"
# It is equal to
if weather == "snow":
print("Wear boots!")
elif "rain":
print("Wear boots!")

Nested If

You can have if statements inside if statements, this is called nested if statements.

Python
1
2
3
4
5
6
7
8
9
t = -10
if t < 10:
print("Temperature is {}. It is cold!".format(t))
if t < 0:
print("Temperature is {}. It is very cold!".format(t))
else:
print("Temperature is {}. It is not cold!".format(t))
# Temperature is -10. It is cold!
# Temperature is -10. It is very cold!

Be careful writing expressions that use logical operators

if statements cannot be empty, but if you for some reason have an if statement with no content, put in the pass statement to avoid getting an error.

Python
1
2
3
4
5
6
7
t = 10
if t < 10:
print("Temperature is {}. It is cold!".format(t))
if t < 0:
print("Temperature is {}. It is very cold!".format(t))
else:
pass

Python While Loops

The while Loop

With the while loop we can execute a set of statements as long as a condition is true.
Note: remember to increment i, or else the loop will continue forever.

Python
1
2
3
4
5
6
7
8
9
10
11
i = 1
while i < 6:
print(i)
i += 1
"""
1
2
3
4
5
"""

The break Statement

With the break statement we can stop the loop even if the while condition is true:

Python
1
2
3
4
5
6
7
8
9
10
i = 1
while i < 6:
print(i)
i += 1
if i == 3:
break
"""
1
2
"""

The continue Statement

With the continue statement we can stop the current iteration, and continue with the next:

Python
1
2
3
4
5
6
7
8
9
10
11
12
i = 1
while i < 6:
i += 1
if i == 3:
continue
print(i)
"""
2
4
5
6
"""

The else Statement

With the else statement we can run a block of code once when the condition no longer is true:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
i = 1
while i < 6:
print(i)
i += 1
else:
print("This program is done")

"""
1
2
3
4
5
This program is done
"""

Python For Loops

A for loop is used for iterating over a sequence (that is either a list, a tuple, a dictionary, a set, or a string).

This is less like the for keyword in other programming languages, and works more like an iterator method as found in other object-orientated programming languages.

With the for loop we can execute a set of statements, once for each item in a list, tuple, set etc.

Note: The for loop does not require an indexing variable to set beforehand

Python
1
2
3
4
5
6
7
for i in [0, 1, 2]:
print(i)
"""
0
1
2
"""

Looping Through a String

Even strings are iterable objects, they contain a sequence of characters:

Python
1
2
3
4
5
6
7
8
9
10
11
12
for i in "Fxxk CCP":
print(i)
"""
F
x
x
k

C
C
P
"""

The break Statement

With the break statement we can stop the loop before it has looped through all the items:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
for i in range (0, 3):
if i == 1:
break
print(i)
"""
0
"""

for i in range (0, 3):
if i == 1:
break
else:
print(i)
"""
0
"""

for i in range (0, 3):
print(i)
if i == 1:
break
"""
0
1
"""

The continue Statement

With the continue statement we can stop the current iteration of the loop, and continue with the next:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for i in range (0, 3):
if i == 1:
continue
print(i)
"""
0
2
"""

for i in range (0, 3):
if i == 1:
continue
else:
print(i)
"""
0
2
"""

The pass Statement

for loops cannot be empty, but if you for some reason have a for loop with no content, put in the pass statement to avoid getting an error.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for i in range (0, 3): # Notice this result is different from the continue statement
if i == 1:
pass
print(i)
"""
0
1
2
"""

for i in range (0, 3):
if i == 1:
pass
else:
print(i)
"""
0
2
"""

The range() Function

To loop through a set of code a specified number of times, we can use the range() function,
The range() function returns a sequence of numbers, starting from 0 by default, and increments by 1 (by default), and ends at a specified number.

Note: The range(start=0, stop) function defaults to 0 as a starting value, however it is possible to specify the starting value by adding a parameter: range(2, 6), which means values from 2 to 6 (but not including 6):

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
for i in range (0, 3):
print(i)
"""
0
1
2
"""

for i in range (3):
print(i)
"""
0
1
2
"""

for i in range (2, 6):
print(i)
"""
2
3
4
5
"""

The range(start=0, stop, step=1) function defaults to increment the sequence by 1, however it is possible to specify the increment value by adding a third parameter: range(1, 10, 3):

Python
1
2
list(range(1, 10, 2))
[1, 3, 5, 7, 9]
Python
1
2
3
4
5
help(range)
'''
range(stop) -> range object
range(start, stop[, step]) -> range object
'''

Else in For Loop

The else keyword in a for loop specifies a block of code to be executed when the loop is finished:

Python
1
2
3
4
5
6
7
8
9
10
for i in range(1, 10, 3):
print(i)
else:
print("Finished")
"""
1
4
7
Finished
"""

Nested Loops

A nested loop is a loop inside a loop.

The “inner loop” will be executed one time for each iteration of the “outer loop”:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
adj = ["red", "big", "tasty"]
fruits = ["apple", "banana", "cherry"]

for x in adj:
for y in fruits:
print(x, y)
"""
red apple
red banana
red cherry
big apple
big banana
big cherry
tasty apple
tasty banana
tasty cherry
"""

Python Functions

A function is a block of code which only runs when it is called.

You can pass data, known as parameters, into a function.

A function can return data as a result.


Creating a Function

In Python a function is defined using the def keyword:

Python
1
2
def my_function():
print("Hello from a function")

Calling a Function

To call a function, use the function name followed by parenthesis:

Python
1
2
3
4
5
6
# A function returns a sentence
def my_function():
print("Hello from a function")

my_function()
# Hello from a function.

Arguments

Information can be passed into functions as arguments.

Arguments are specified after the function name, inside the parentheses. You can add as many arguments as you want, just separate them with a comma.

The following example has a function with one argument (fname). When the function is called, we pass along a first name, which is used inside the function to print the full name:

Python
1
2
3
4
5
6
7
8
9
10
# A function prints hello name.
def hello_function(name):
print("Hello " + name)

hello_function("Zacks")
# Hello Zacks
hello_function("Amber")
# Hello Amber
hello_function("33")
# Hello 33

Arguments are often shortened to args in Python documentations.


Parameters or Arguments?

The terms parameter and argument can be used for the same thing: information that are passed into a function.

From a function’s perspective:

  • A parameter is the variable listed inside the parentheses in the function definition.
  • An argument is the value that are sent to the function when it is called.

Required Arguments

By default, a function must be called with the correct number of arguments. Meaning that if your function expects 2 arguments, you have to call the function with 2 arguments, not more, and not less.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# A function prints capitalized name
def name(first_name, last_name):
first_name = first_name.capitalize()
last_name = last_name.capitalize()
print("My name is " + first_name + " " + last_name)

name("Zacks", "Shen")
# My name is Zacks Shen

name("zacks", "SHEN")
# My name is Zacks Shen

name("Zacks")
# TypeError: name() missing 1 required positional argument: 'last_name'

Arguments are often shortened to args in Python documentations.
args are positional arguments.


Arbitrary Arguments, *args

If you do not know how many arguments that will be passed into your function, add a * before the parameter name in the function definition.

This way the function will receive a tuple of arguments, and can access the items accordingly:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
# A function prints capitalized name
def _name(*name):
name = list(name) # Remember 'tuple' object does not support item assignment
index = len(name) # Get the length of 'name' argument
for i in range(index):
name[i] = name[i].capitalize()
print("My name is " + name[0] + " " + name[1])

_name("Zacks", "Shen")
# My name is Zacks Shen

_name("zacks", "SHEN")
# My name is Zacks Shen

Arbitrary Arguments are often shortened to *args in Python documentations.
*args are positional arguments.


Keyword Arguments, kwargs

You can also send arguments with the key = value syntax.

This way the order of the arguments does not matter.

Python
1
2
3
4
5
6
7
8
9
# A function prints capitalized name with a title
def name(first_name, last_name, title):
first_name = first_name.capitalize()
last_name = last_name.capitalize()
title = title.upper()
print("I am " + title + " " + first_name + " " + last_name)

name(title = "mr", last_name = "shen", first_name = "ZACKS")
# I am MR Zacks Shen

The phrase Keyword Arguments are often shortened to kwargs in Python documentations.
kwargs are NOT positional arguments.


Arbitrary Keyword Arguments, **kwargs

If you do not know how many keyword arguments that will be passed into your function, add two asterix: ** before the parameter name in the function definition.

This way the function will receive a dictionary of arguments, and can access the items accordingly:

Python
1
2
3
4
5
6
7
8
9
# A function prints capitalized name with a title
def _name(**name):
name["first_name"] = name["first_name"].capitalize()
name["last_name"] = name["last_name"].capitalize()
name["title"] = name["title"].upper()
print("I am {0} {1} {2}".format(name["title"], name["first_name"], name["last_name"]))

_name(title = "mr", last_name = "shen", first_name = "ZACKS")
# I am MR Zacks Shen

Arbitrary Keyword Arguments are often shortened to *kwargs* in Python documentations.
*
kwargs* are NOT positional arguments


Default Parameter Value

If we call the function without argument, it uses the default value:

Python
1
2
3
4
5
6
7
8
9
10
11
12
# A function prints capitalized name with a title and country
def _name(country = "United States", **name): # Remember arg should put before **kwarg
name["first_name"] = name["first_name"].capitalize()
name["last_name"] = name["last_name"].capitalize()
name["title"] = name["title"].upper()
print("I am {0} {1} {2}, and I come from {3}".format(name["title"], name["first_name"], name["last_name"], country))

_name(title = "mr", last_name = "shen", first_name = "ZACKS")
# I am MR Zacks Shen, and I come from United States

_name(title = "mr", last_name = "shen", first_name = "ZACKS", country = "Iceland")
# I am MR Zacks Shen, and I come from Iceland

Keyword-only Arguments

If we use keyword arguments, we cannot restrain what the user input.

Take the example from Default Parameter Value:
This function accept the unexpected parameter (gender).

Python
1
2
3
4
5
6
7
8
9
10
11
12
# A function prints capitalized name with a title and country
def _name(country = "United States", **name): # Remember arg should put before **kwarg
name["first_name"] = name["first_name"].capitalize()
name["last_name"] = name["last_name"].capitalize()
name["title"] = name["title"].upper()
print("I am {0} {1} {2}, and I come from {3}".format(name["title"], name["first_name"], name["last_name"], country))

_name(title = "mr", last_name = "shen", first_name = "ZACKS")
# I am MR Zacks Shen, and I come from United States

_name(title = "mr", last_name = "shen", first_name = "ZACKS", country = "Iceland", gender = "man")
# I am MR Zacks Shen, and I come from Iceland.

We successfully import gener = "man" to the function even it will not be executed. But it is still dangerous.

A keyword-only argument could help us restraining user input.
We can use * to split the arguments. The arguments after * are keyword-only arguments, which could have a default value.

This function prevents from the unexpected parameter (gender).

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# A function prints capitalized name with a title and country
def name(first_name, last_name, *, title, country = "United States"):
first_name = first_name.capitalize()
last_name = last_name.capitalize()
title = title.upper()
print("I am {0} {1} {2}, and I come from {3}".format(title, first_name, last_name, country))

name(title = "mr", last_name = "shen", first_name = "ZACKS")
# I am MR Zacks Shen, and I come from United States

name(title = "mr", last_name = "shen", first_name = "ZACKS", country = "Iceland")
# I am MR Zacks Shen, and I come from Iceland

name(title = "mr", last_name = "shen", first_name = "ZACKS", gender = "Man")
# TypeError: name() got an unexpected keyword argument 'gender'

You can Also use *args to split the arguments:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# A function prints capitalized name with a title and country
def name(first_name, last_name, *base_information, country = "United States"):
first_name = first_name.capitalize()
last_name = last_name.capitalize()
print("I am {0} {1} {2}, a {3}, and I come from {4}".format(base_information[0].upper(), first_name, last_name, base_information[1], country))

name("Zacks", "shen", "mr", "man")
# I am MR Zacks Shen, and I come from United States

name("Zacks", "shen", "mr", "man", country = "Iceland")
# I am MR Zacks Shen, a man, and I come from Iceland

name(last_name = "shen", first_name = "Zacks", "mr", "man", country = "Iceland")
# SyntaxError: positional argument follows keyword argument
# Remember keyword argument must follows positional argument. Because I define last_name = "shen", which means the positional argument has been considered as keyword argument.

Order of Arguments

Warning!!!
Basically, you must define a function in the following way to avoid SyntaxError: positional argument follows keyword argumen:

Python
1
2
def function_name(positional arguments, keyword arguments):
pass

And the detailed order is:

  1. Positional arguments, arg
  2. Default arguments
  3. Arbitrary Arguments, *arg
  4. Keyword-only arguments
  5. Keyword arguments, kwargs
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Notice in this example, country = "United States" is NOT a default argument; it is a Keyword-only arguments since it follows the *arg.
# A function prints capitalized name with a title and country
def name(first_name, last_name, *base_information, country = "United States"):
first_name = first_name.capitalize()
last_name = last_name.capitalize()
print("I am {0} {1} {2}, a {3}, and I come from {4}".format(base_information[0].upper(), first_name, last_name, base_information[1], country))

name("Zacks", "shen", "mr", "man")
# I am MR Zacks Shen, and I come from United States

name("Zacks", "shen", "mr", "man", country = "Iceland")
# I am MR Zacks Shen, a man, and I come from Iceland

name(last_name = "shen", first_name = "Zacks", "mr", "man", country = "Iceland")
# SyntaxError: positional argument follows keyword argument
# Remember keyword argument must follows positional argument. Because I define last_name = "shen", which means the positional argument has been considered as keyword argument.

Return Values

To let a function return a value, use the return statement:

Python
1
2
3
4
5
6
# A function returns your bmi
def bmi_calculate(h, w):
return w/(h*h)

bmi_calculate(1.8, 70)
# 21.604938271604937

Return is one of the most important concepts! A deep learning could help us understand it

Here is a for statement to print a series numbers in a range:

Python
1
2
3
4
5
6
7
for i in range(3):
print(i)
"""
0
1
2
"""

Let’s do the same thing in a function, then call it:

Python
1
2
3
4
5
6
7
8
9
10
11
# A function prints the values in a range one by one.
def tmp():
for i in range(3):
print(i)

tmp()
"""
0
1
2
"""

You may understand that sometimes print() and return() all print the result on your screen:

Python
1
2
3
4
5
6
# A function RETURNS your bmi
def bmi_calculate_1(h, w):
return w/(h*h)

bmi_calculate_1(1.8, 70)
# 21.604938271604937
Python
1
2
3
4
5
6
# A function PRINTS your bmi
def bmi_calculate_2(h, w):
print(w/(h*h))

bmi_calculate_2(1.8, 70)
# 21.604938271604937

However, if try to do the same thing in return.

Python
1
2
3
4
5
6
7
8
9
10
11
# A function PRINTS the values in a range one by one.
def tmp_1():
for i in range(3):
print(i)

tmp_1()
"""
0
1
2
"""
Python
1
2
3
4
5
6
7
8
9
# A function try to RETURN the values in a range one by one, but it doesn't work.
def tmp_2():
for i in range(3):
return(i)

tmp_2()
"""
0
"""

This is weird, right? Why the function only print 0 on the screen? Because return only runs once in a function! And everything after return will be ignored!

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def hello_1():
print("Hello")
print("World")

hello_1()
# Hello
# World

def hello_2():
return("Hello")
return("World") # Will be ignored!

hello_2()
# 'Hello'

def hello_3():
return("Hello")
print("World") # Will be ignored!

hello_3()
# 'Hello'

def hello_4():
print("Hello")
return("World") # Will not be ignored!

hello_4()
# Hello
# 'World'

From the official definition:
return may only occur syntactically nested in a function definition, not within a nested class definition.

If an expression list is present, it is evaluated, else None is substituted.

return leaves the current function call with the expression list (or None) as return value.

When return passes control out of a try statement with a finally clause, that finally clause is executed before really leaving the function.


The pass Statement

function definitions cannot be empty, but if you for some reason have a function definition with no content, put in the pass statement to avoid getting an error.

Python
1
2
3
4
5
def my_function():
# SyntaxError: unexpected EOF while parsing

def my_function():
pass

Recursion

Python also accepts function recursion, which means a defined function can call itself.

Recursion is a common mathematical and programming concept. It means that a function calls itself. This has the benefit of meaning that you can loop through data to reach a result.

The developer should be very careful with recursion as it can be quite easy to slip into writing a function which never terminates, or one that uses excess amounts of memory or processor power. However, when written correctly recursion can be a very efficient and mathematically-elegant approach to programming.

To a new developer it can take some time to work out how exactly this works, best way to find out is by testing and modifying it.


SUM example:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# For loop:
def sum(n): s=0
for i in range(0,n+1):
s=s+i
return s

# While loop:
def sum(n):
s=0
i=0
while i<n:
i=i+1
s=s+i
return s

# Recursion:
def sum(n):
if n == 0:
return 0
return n + sum(n-1)

# A formula as another solution
def sum(n):
return (n * (n + 1)) / 2

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# A function returns exponentiation
def exp(b, n):
if n > 0:
return b * exp(b, n - 1)
else:
return 1
# when n = 0, function returns exp(b, 0) -> 1
# when n = 1, function returns b * exp(b, n - 1) -> b * 1
# when n = 2, function returns b * exp(b , n - 1) * exp(b , n - 2) -> b * b * 1

exp(2, 0)
# 1

exp(2, 1)
# 2

exp(2, 10)
# 1024

Notice the following two functions are not the same!

Python
1
2
3
4
5
def sum_of_squares(n): 
if n < 1:
return 0
else:
return sum_of_squares(n-1) + n**2
Python
1
2
3
4
5
def sum_of_squares(n): 
if n < 1:
return 0
else:
return n**2 + sum_of_squares(n-1)

Example

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
def countdown(n):
if n == 0:
print('Blastoff!')
else:
print(n)
countdown(n - 1)

countdown(2)
'''
2
1
Blastoff!
'''
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def countdown(n):
if n == 0:
print('Blastoff!')
else:
# What happens if we swap the order?
print('Before: ' + str(n))
countdown(n - 1)
print('After: ' + str(n))

countdown(2)
'''
Before: 2
Before: 1
Blastoff!
After: 1
After: 2
'''

Why Recursion?

It’s tremendously useful when the problem is self-similar.
It’s no more powerful than iteration, but often leads to more concise & better code.
It’s more mathematical.
It’s embodies the beauty and joy of computing.


Example: Exponential operation

In Python, you can execute Exponential operation in a easy way:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def iter_exp(x, n):
result = 1
for i in range(n):
result *= x
return result

iter_exp(2, 0)
# 1

iter_exp(2, 1)
# 2

iter_exp(2, 10)
# 1024

In chapter Recursion, we have learned another function to return an exponential operation. However, this one mey consume less computing resource since it invoke function less times.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# A function returns exponentiation
def exp(b, n):
if n > 0:
return b * exp(b, n - 1)
else:
return 1
# when n = 0, function returns exp(b, 0) -> 1
# when n = 1, function returns b * exp(b, n - 1) -> b * 1
# when n = 2, function returns b * exp(b , n - 1) * exp(b , n - 2) -> b * b * 1

exp(2, 0)
# 1

exp(2, 1)
# 2

exp(2, 10)
# 1024

Example: Factorials

Python
1
2
3
4
5
6
7
8
def iter_fact(n):
result = 1
for i in range(1, n + 1):
result *= i
return result

fact(5)
# 120
Python
1
2
3
4
5
6
7
def fact(n):
if n < 2:
return 1
return n * fact(n -1)

fact(5)
# 120

Example: Fibonacci numbers

In mathematics, the Fibonacci numbers, commonly denoted Fn, form a sequence, called the Fibonacci sequence, such that each number is the sum of the two preceding ones, starting from 0 and 1. That is,

$${\displaystyle F_{0}=0,\quad F_{1}=1,}$$
and

$${\displaystyle F_{n}=F_{n-1}+F_{n-2},}$$
for $n > 1$.

The beginning of the sequence is thus:

$${\displaystyle 0,;1,;1,;2,;3,;5,;8,;13,;21,;34,;55,;89,;144,;\ldots }$$

Python
1
2
3
4
5
def iter_fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
Python
1
2
3
4
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)


Example: Reverse a string

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def reverse(s):
"""
>>> reverse('hello')
'olleh'
>>> reverse(reverse('hello'))
'hello'
"""
if not s: # for empty string '', not '' is True. The last loop will return ''
return ''
return s[len(s) - 1] + reverse(s[:len(s) - 1])

# Simulate the last loop
s = "Hello"
if not s[:0]:
print(1)
else:
print(2)

Example: Minimum Number

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
def first(s):
"""Return the first element in a sequence."""
return s[0]
def rest(s):
"""Return all elements in a sequence after the first"""
return s[1:]

def min_r(s):
"""Return minimum value in a sequence."""
if len(s) == 1:
return first(s)
else:
return min(first(s), min_r(rest(s)))

Example: Quicksort

  • A fairly simple to sorting algorithm
  • Goal: Sort the list by breaking it into partially sorted parts – Pick a “pivot”, a starting item to split the list
    – Remove the pivot from your list
    – Split the list into 2 parts, a smaller part and a bigger part
    – Then recursively sort the smaller and bigger parts
    – Combine everything together: the smaller list, the pivot, then the bigger list

Example

Quick Sort

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
def split(x, s):
return [i for i in s if i <= x], [i for i in s if i > x]

def quicksort(s):
"""Sort a sequence - split it by the first element, sort both parts and put them back together."""
if not s:
return []
else:
pivot = s[0]
smaller, bigger = split(pivot, s[1:])
return quicksort(smaller) + [pivot] + quicksort(bigger)

quicksort(([3,3,1,4,5,4,3,2,1,17]))


Example: Filter

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def iter_filter(f, seq):
"""Filter a sequence to only contain values allowed by filter.

>>> def is_even(x):
... return x % 2 == 0
>>> def divisible_by5(x):
... return x % 5 == 0
>>> iter_filter(is_even, [1,2,3,4])
[2, 4]
>>> iter_filter(divisible_by5, [1, 4, 9, 16, 25, 100])
[25, 100]
"""
# Iteration
return [i for i in seq if f(i)]
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def filter(f, seq):
"""Filter a sequence to only contain values allowed by filter.

>>> def is_even(x):
... return x % 2 == 0
>>> def divisible_by5(x):
... return x % 5 == 0
>>> filter(is_even, [1,2,3,4])
[2, 4]
>>> filter(divisible_by5, [1, 4, 9, 16, 25, 100])
[25, 100]
"""
# Recursion
if not seq:
return []
elif f(seq[0]):
return [seq[0]] + filter(f, seq[1:])
else:
return filter(f, seq[1:])

Example: Sum Difference

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def iter_sum_diffs(n):
""" Return the sum of the differences between adjacent digits in the number n.

>>> iter_sum_diffs(8)
0
>>> iter_sum_diffs(154) # 4 + 1 = 5
5
>>> iter_sum_diffs(12321) # 1 + 1 + 1 + 1
4
>>> iter_sum_diffs(7351) # 4 + 2 + 4
10
"""
# Iteration
# Get the digit of n
result = []
while n > 10:
result.append(abs(n%10 - n//10%10))
n = n // 10
return sum(result)
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def sum_diffs(n):
""" Return the sum of the differences between adjacent digits in the number n.

>>> sum_diffs(8)
0
>>> sum_diffs(154) # 4 + 1 = 5
5
>>> sum_diffs(12321) # 1 + 1 + 1 + 1
4
>>> sum_diffs(7351) # 4 + 2 + 4
10
"""
# Recursion
if n < 10:
return 0
else:
return abs(n%10 - n//10%10) + sum_diffs(n//10)

Example: Insect Combinatorics

Consider an insect in an M by N grid. The insect starts at the bottom left corner, (0, 0), and wants to end up at the top right corner, (M-1, N-1). The insect is only capable of moving right or up. Write a function paths that takes a grid length and width and returns the number of different paths the insect can take from the start to the goal. (There is a closed-form solution to this problem, but try to answer it procedurally using recursion.)

For example, the 2 by 2 grid has a total of two ways for the insect to move from the start to the goal. For the 3 by 3 grid, the insect has 6 different paths (only 3 are shown above).


Solution Recursion

62. Unique Paths

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def paths(m, n):
"""Return the number of paths from one corner of an
M by N grid to the opposite corner.

>>> paths(2, 2)
2
>>> paths(5, 7)
210
>>> paths(117, 1)
1
>>> paths(1, 157)
1
"""
# Recursion
if m == 1 or n == 1:
return 1

return paths(m - 1, n) + paths(m, n - 1)

Solution Math Combination

Combinations and Permutations

The question is equal to how many combinations of up, right, where the number of up = m-1 and the number of right = n-1

Permutations
There are basically two types of permutation:

  • Repetition is Allowed: such as the lock above. It could be “333”.
  • No Repetition: for example the first three people in a running race. You can’t be first and second.

Combinations
There are also two types of combinations (remember the order does not matter now):

  • Repetition is Allowed: such as coins in your pocket (5,5,5,10,10)
  • No Repetition: such as lottery numbers (2,14,15,27,30,33)

For example,

  1. paths(2, 2)
  2. m-1, n-1 = 1, 1
  3. 1 right & 1 up has TWO combinations: up, right; right up
  4. The math formula is: $C(n, k) = C(4, 2) = \frac{4!}{2!}$
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from math import factorial

def math_paths(m, n):
"""Return the number of paths from one corner of an
M by N grid to the opposite corner.

>>> math_paths(2, 2)
2
>>> math_paths(5, 7)
210
>>> math_paths(117, 1)
1
>>> math_paths(1, 157)
1
"""
"*** YOUR CODE HERE ***"
# Math
goal = (m-1) + (n-1)
return int(factorial(goal)/(factorial(m-1) * factorial(n-1)))

Example: Reduce

Write the recursive version of the function reduce which takes

  • reducer - a two-argument function that reduces elements to a single value
  • seq - a sequence of values
  • base - the starting value in the reduction. This is usually the identity of the reducer
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def iter_reduce(reducer, seq, base):
"""Reduce a sequence under a two-argument function starting from a base value.

>>> def add(x, y):
... return x + y
>>> def mul(x, y):
... return x*y
>>> iter_reduce(add, [1,2,3,4], 0)
10
>>> iter_reduce(mul, [1,2,3,4], 0)
0
>>> iter_reduce(mul, [1,2,3,4], 1)
24
"""
# Iteration
if reducer == add:
result = 0
for i in seq:
result += reducer(i, base)
elif reducer == mul:
result = 1
for i in seq:
result *= reducer(i, base)
return result
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def reduce(reducer, seq, base):
"""Reduce a sequence under a two-argument function starting from a base value.

>>> def add(x, y):
... return x + y
>>> def mul(x, y):
... return x*y
>>> reduce(add, [1,2,3,4], 0)
10
>>> reduce(mul, [1,2,3,4], 0)
0
>>> reduce(mul, [1,2,3,4], 1)
24
"""
# Recursion
if not seq:
return base
return reducer(reducer(seq[0], base), reduce(reducer, seq[1:], base))

Example: Remove Last from Sequence

remove_last creates a new list identical to the input list s but with the last element in the sequence that is equal to x removed.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def remove_last(x, s):
"""Create a new list that is identical to s but with the last
element from the list that is equal to x removed.

>>> remove_last(1,[])
[]
>>> remove_last(1,[1])
[]
>>> remove_last(1,[1,1])
[1]
>>> remove_last(1,[2,1])
[2]
>>> remove_last(1,[3,1,2])
[3, 2]
>>> remove_last(1,[3,1,2,1])
[3, 1, 2]
>>> remove_last(5, [3, 5, 2, 5, 11])
[3, 5, 2, 11]
"""
# Non-recursion
result = list(reversed(s))
if x in result:
result.remove(x)
result.reverse()
return result
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def remove_last(x, s):
"""Create a new list that is identical to s but with the last
element from the list that is equal to x removed.

>>> remove_last(1,[])
[]
>>> remove_last(1,[1])
[]
>>> remove_last(1,[1,1])
[1]
>>> remove_last(1,[2,1])
[2]
>>> remove_last(1,[3,1,2])
[3, 2]
>>> remove_last(1,[3,1,2,1])
[3, 1, 2]
>>> remove_last(5, [3, 5, 2, 5, 11])
[3, 5, 2, 11]
"""
# Recursion
if not s:
return []
# If the 1st item of s == x, and s only has one x. Skip this round.
elif (s.count(x) == 1) & (s[0] == x):
return [] + remove_last(x, s[1:])
else:
return [s[0]] + remove_last(x, s[1:])

Example: Create Number from Lists

Write a recursive function create_num_from_lsts that creates a number with the elements from lst1 and lst2 as digits in that order.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def iter_create_num_from_lsts(lst1, lst2):
""" Create a number with the elements from lst1 and lst2 as digits in that order.

>>> iter_create_num_from_lsts([1, 2, 3], [4, 5, 6])
123456
>>> iter_create_num_from_lsts([5, 4, 2, 4], [1, 7])
542417
>>> iter_create_num_from_lsts([3], [9, 8])
398
"""
# Iteration
result = 0
digit_times = 1
lst = lst1 + lst2
lst.reverse()
for i in lst:
result += i * digit_times
digit_times *= 10
return result
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def create_num_from_lsts(lst1, lst2):
""" Create a number with the elements from lst1 and lst2 as digits in that order.

>>> create_num_from_lsts([1, 2, 3], [4, 5, 6])
123456
>>> create_num_from_lsts([5, 4, 2, 4], [1, 7])
542417
>>> create_num_from_lsts([3], [9, 8])
398
"""
# Recursion
lst = lst1 + lst2
if not lst:
return 0
# Regardless what items in lst1, just make it empty
return 10**(len(lst) -1) * (lst)[0] + create_num_from_lsts([], lst[1:])

Example: Coin Change 2

518. Coin Change 2

A set of coins makes change for n if the sum of the values of the coins is n. For example, if you have 1-cent, 2-cent and 4-cent coins, the following sets make change for 7:

  • 7 1-cent coins
  • 5 1-cent, 1 2-cent coins
  • 3 1-cent, 2 2-cent coins
  • 3 1-cent, 1 4-cent coins
  • 1 1-cent, 3 2-cent coins
  • 1 1-cent, 1 2-cent, 1 4-cent coins

Thus, there are 6 ways to make change for 7. Write a function count_change that takes a positive integer n and a list of the coin denominations and returns the number of ways to make change for n using these coins (Hint: You will need to use tree recursion):

Coin/Amount 0 1 2 3 4 5 6 7 8 9 10
1 0 1 1 1 1 1 1 1 1 1 1
2 0 0 1 0 1 0 1 0 1 0 1
5 0 0 0 0 0 1 0 0 0 0 1

Remove 1, because any amount has 1 solution for coin = 1.

for example:
amount = 2

  • 1: 1 + 1
  • 2: 2

amount = 3

  • 1: 1 + 1 + 1
  • 1 & 2: 1 + 2

amount = 4

  • 1: 1 + 1 + 1 + 1
  • 2: 2 + 2
  • 1 & 2: 1 + 1 + 2

amount = 5

  • 1: 1 + 1 + 1 + 1 + 1
  • 5: 5
  • 1 & 2:
    • 1 + 2 + 2
    • 1 + 1 + 1 + 2

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def iter_count_change(amount, denominations):
"""Returns the number of ways to make change for amount.

>>> denominations = [50, 25, 10, 5, 1]
>>> iter_count_change(7, denominations)
2
>>> iter_count_change(100, denominations)
292
>>> denominations = [16, 8, 4, 2, 1]
>>> iter_count_change(7, denominations)
6
>>> iter_count_change(10, denominations)
14
>>> iter_count_change(20, denominations)
60
"""
"*** YOUR CODE HERE ***"
# Iteration: https://leetcode.com/problems/coin-change-2/solution/
dp = [0] * (amount + 1)
dp[0] = 1

for coin in denominations:
for x in range(coin, amount + 1):
dp[x] += dp[x - coin]
return dp[amount]
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def count_change(amount, denominations):
"""Returns the number of ways to make change for amount.

>>> denominations = [50, 25, 10, 5, 1]
>>> count_change(7, denominations)
2
>>> count_change(100, denominations)
292
>>> denominations = [16, 8, 4, 2, 1]
>>> count_change(7, denominations)
6
>>> count_change(10, denominations)
14
>>> count_change(20, denominations)
60
"""
# Recursion
#If we found a way to create the desired amount
if amount == 0:
return 1

#If we went over our amount or we have no more coins left
if amount < 0 or len(denominations) == 0:
return 0

#Our solutions can be divided into two sets,
# 1) Solutions that contain the coin at the end of the coins array
# 2) Solutions that don't contain that coin
return count_change(amount - denominations[-1], denominations) + count_change(amount, denominations[:-1])

Python Lambda

A lambda function is a small anonymous function.

A lambda function can take any number of arguments, but can only have one expression.


Syntax

Python
1
lambda [argument]: [expression]

The expression is executed and the result is returned:

Python
1
2
3
x = lambda a : a + 10
print(x(5))
# 15

Lambda functions can take any number of arguments:

Python
1
2
3
x = lambda a, b : a * b
print(x(2, 3))
# 6

A lambda expression by itself is not very interesting. As with any objects such as numbers, booleans, strings, we usually:

  • assign lambda to variables (foo = lambda x: x)
  • pass them in to other functions (bar(lambda x: x))
  • return them as the results of other functions (return lambda x: x)
  • return them as the results of other lambdas (lambda x: lambda y: x + y)

In the final example above, the outer lambda (lambda x) takes in a value x, and it returns another lambda (lambda y) that takes an argument y and returns x+y.


Difference between lambda and def

While both lambda and def statements are related to functions, there are some differences.

lambda def
Type lambda is an expression def is a statement
Description Evaluating a lambda expression does not create or modify any variables. Lambda expressions just create new function objects. Executing a def statement will create a new function object and bind it to a variable in the current environment.
Example
lambda x: x *x
           
def square(x):
return x* x

If..else in Lambda

Python
1
lambda x: True if x % 2 == 0 else False

Why Use Lambda Functions?

The power of lambda is better shown when you use them as an anonymous function inside another function.

Say you have a function definition that takes one argument, and that argument will be multiplied with an unknown number:

Python
1
2
def myfunc(n):
return lambda a : a * n

Use that function definition to make a function that always doubles the number you send in:

Python
1
2
3
4
5
6
7
def myfunc(n):
return lambda a : a * n

mydoubler = myfunc(2)

print(mydoubler(11))
# 22

Use lambda functions when an anonymous function is required for a short period of time.


Examples

Python
1
2
3
4
5
6
b = lambda x: lambda: x  # Lambdas can return other lambdas!
c = b(88)
c
# <function __main__.<lambda>.<locals>.<lambda>()>
c()
# 88
Python
1
2
3
4
5
d = lambda f: f(4)  # They can have functions as arguments as well.
def square(x):
return x * x
d(square)
# 16
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
z = 3
e = lambda x: lambda y: lambda: x + y + z
''' The above code is equal to:
z = 3
def func1(x):
def func2(y):
def func3():
return x + y + z
return func3
return func2

f = func1(0)(1)()
f
# 4
'''
e(0)(1)()
# 4
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
higher_order_lambda = lambda f: lambda x: f(x)
''' The above code is equal to:
def higher_order_lambda(f):
def func(x):
return f(x)
return func
'''
g = lambda x: x * x
''' The above code is equal to:
def g(x):
return x * x
'''
higher_order_lambda(2)(g) # Which argument belongs to which function call?
# TypeError: 'int' object is not callable

higher_order_lambda(g)(2)
# 4
Python
1
2
3
4
5
6
7
8
9
call_thrice = lambda f: lambda x: f(f(f(x)))
''' The above code is equal to:
def call_thrice(f):
def func(x):
return f(f(f(x)))
return func
'''
call_thrice(lambda y: y + 1)(0)
# 3
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
print_lambda = lambda z: print(z)  # When is the return expression of a lambda expression executed?
''' The above code is equal to:
def print_lambda(z):
print(z)
'''
print_lambda
# <function __main__.<lambda>(z)>

one_thousand = print_lambda(1000)
# 1000

one_thousand # Because print does not return anything
#

type(one_thousand) # Because print does not return anything
# NoneType

Python Classes and Object


Python Classes/Objects

Python is an object oriented programming language.

Almost everything in Python is an object, with its properties and methods.

A Class is like an object constructor, or a “blueprint” for creating objects.

Create a Class
To create a class, use the keyword class:

Python
1
2
3
4
# Create a class named MyClass, with a property named x:
class MyClass:
x = 5
y = 6

Create Object
Now we can use the class named myClass to create objects:

Python
1
2
3
4
5
6
# Create an object named p1, and print the value of x:
p1 = MyClass()
print(p1.x)
# 5
print(p1.y)
# 6

The init() Function

The examples above are classes and objects in their simplest form, and are not really useful in real life applications.

To understand the meaning of classes we have to understand the built-in __init__() function.

All classes have a function called __init__(), which is always executed when the class is being initiated.

Use the __init__() function to assign values to object properties, or other operations that are necessary to do when the object is being created:

Create a class named Person, use the init() function to assign values for name and age:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

# Assigning value trough __init__
Person("Zacks", 25)
# <__main__.Person at 0x10e7afed0>
Person("Zacks", 25)
# <__main__.Person at 0x10e76b550>
# Everytime we run the class, Python will assign a location of RAM to store the class with values.

# Invoke the value
Person("Zacks", 25).name
# 'Zacks'
Person("Zacks", 25).age
# 25

# Assigning Class with values to variable
p1 = Person("Zacks", 25)

p1.name # p1.name <- self.name
# Zacks
p1.age # p1.age <- self.age
# 25
p1
# <__main__.Person object at 0x1113db250>

p2 = Person()
# TypeError: __init__() missing 2 required positional arguments: 'name' and 'age'

Note: The __init__() function is called automatically every time the class is being used to create a new object.


Object Methods

Objects can also contain methods. Methods in objects are functions that belong to the object.

Let us create a method in the Person class:

Insert a function that prints a greeting, and execute it on the p1 object:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def myfunc(self):
print("Hello my name is " + self.name)

p1 = Person("Zacks", 25)

p1.myfunc()
# Hello my name is Zacks
print(p1.name)
# Zacks
print(p1.age)
# 25
print(p1)
# <__main__.Person object at 0x1113db820>

Note: The self parameter is a reference to the current instance of the class, and is used to access variables that belong to the class.

Notice the difference

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def myfunc(self):
return("Hello my name is " + self.name)

p1 = Person("Zacks", 25)

p1.myfunc()
# 'Hello my name is Zacks'
print(p1.myfunc)
# <bound method Person.myfunc of <__main__.Person object at 0x10e7af650>>

The self Parameter

The self parameter is a reference to the current instance of the class, and is used to access variables that belongs to the class.

It does not have to be named self , you can call it whatever you like, but it has to be the first parameter of any function in the class:

Use the words tmp and abc instead of self:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Person:
def __init__(tmp, name, age):
tmp.name = name
tmp.age = age

def myfunc(abc):
print("Hello my name is " + abc.name)

p1 = Person("Zacks", 25)
p1.myfunc()
# Hello my name is Zacks

print(p1.name)
# Zacks
print(p1.age)
# 25
print(p1)
# <__main__.Person object at 0x1124a4220>

Modify Object Properties

You can modify properties on objects like this:

Python
1
2
3
p1.age = 18
print(p1.age)
# 18

Delete Object Properties

You can delete properties on objects by using the del keyword:

Python
1
2
3
4
5
del p1.age
print(p1.age)
# AttributeError: 'Person' object has no attribute 'age'
print(p1.name)
# Zacks

Delete Objects

You can delete objects by using the del keyword:

Python
1
2
3
del p1
print(p1)
# NameError: name 'p1' is not defined

The pass Statement

class definitions cannot be empty, but if you for some reason have a class definition with no content, put in the pass statement to avoid getting an error.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def myfunc(self):
return("Hello my name is " + self.name)

def unfinished_func(self):
# ^
# SyntaxError: unexpected EOF while parsing

class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def myfunc(self):
return("Hello my name is " + self.name)

def unfinished_func(self):
pass

p1 = Person("Zacks", 25)
p1.unfinished_func()
# AttributeError: 'Person' object has no attribute 'unfinished_func'

Built-in Proerties

3. Data model

Magic Methods start and end with “double underscores” __

  • __init__: Called when making a new instance
  • __add__: + operator
  • __sub__: - operator
  • __getitem__: [] operator
  • __str__: Called when we call print()
  • __repr__: Called in the interpreter

init example

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class BaseAccount:
# Return None
def __init__(self, name, initial_deposit):
self.name = name
self.balance = initial_deposit

def account_name(self):
return self.name

def account_balance(self):
return self.balance

def withdraw(self, amount):
self.balance -= amount
return self.balance

repr and str example

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class BaseAccount:
# Return None
def __init__(self, name, initial_deposit):
self.name = name
self.balance = initial_deposit

def account_name(self):
return self.name

def account_balance(self):
return self.balance

def withdraw(self, amount):
self.balance -= amount
return self.balance

def deposit(self, amount):
self.balance += amount
return self.balance

def __repr__(self):
# Goal: unambiguous
return '< ' + str(self._acct_no) + '[' + str(self._name) + '] >'

def __str__(self):
# Goal readable
return 'Account: ' + str(self._acct_no) + '[' + str(self._name) + ']'

def show_accounts():
for account in BaseAccount.accounts:
print(account)

Why do we need a class/object?

Imagine you are planning to make a program that returns weather of users’ specified location every day. Your first idea is creating a function, I guess:

Weather Program.py 1.0

Python
1
2
3
4
5
6
7
8
# Provide weather information based on location
def Weather(location):
weather = "Sunny" # Assume you have gotten the weather from somewhere.
Summary = "{0}: Today is {1}".format(location, weather)
return(Summary)

Weather("Boston")
# 'Boston: Today is Sunny'

One day you want to add a function to provide more information, for example, humidity. You may consider change your old function:

Weather Program.py 1.1

Python
1
2
3
4
5
6
7
8
9
# Provide weather information based on location
def Weather(location):
weather = "Sunny" # Assume you have gotten the weather from somewhere.
humidity = "20%" # Assume you have gotten the humidity from somewhere.
Summary = "{0}: Today is {1}, and humidity is {2}".format(location, weather, humidity)
return(Summary)

Weather("Boston")
# 'Boston: Today is Sunny, and humidity is 20%'

What if you need more functions? For example, the chance of rain? And how to show weather in 5 days? You’d better design a good structure for your program for future updating. Class is the best way to do this.

Let’s reproduce the basic function first:

Weather Program.py 2.0

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Weather:
def __init__(self, location):
self.location = location

def Location(self):
print("Location: " + self.location)

def Weather(self):
self.weather = "Sunny"

print("Weather: " + self.weather)

def Summary(self): # Invoke all functions above
self.Location()
self.Weather()

location = Weather("Boston")
location.Summary()
# Location: Boston
# Weather: Sunny

Notice we did a very important step is def Summary(self), which is the function to invoke all functions above in self.myFunction() way. It means we separate every function in different areas. And we can update them respectively.

Then we can try to add new functions:

Weather Program.py 2.1

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Weather:
def __init__(self, location):
self.location = location

def Location(self):
print("Location: " + self.location)

def Weather(self):
self.weather = "Sunny"

print("Weather: " + self.weather)

def Humidity(self):
self.humidity = "20%"

print("Humidity: " + self.humidity)

def Rain(self):
self.rain = "10%"

print("Chance of Rain: " + self.rain)

def Summary(self): # Invoke all functions above
self.Location()
self.Weather()
self.Humidity()
self.Rain()

location = Weather("Boston")
location.Summary()
# Location: Boston
# Weather: Sunny
# Humidity: 20%
# Chance of Rain: 10%

Every time we add new functions, we only need to add a def myFunction():, which are more readable and intuitive. Let’s try to show the weather information for 5 days. Notice how I can pass the parameter inner the class.

Weather Program.py 3.0

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import datetime

class Weather:
def __init__(self, location):
self.location = location

def Date(self, date = 0):
self.date = datetime.date.today() + datetime.timedelta(days = date)
print("Date: " + self.date.isoformat())

def Location(self):
print("Location: " + self.location)

def Weather(self):
self.weather = "Sunny"
print("Weather: " + self.weather)

def Humidity(self):
self.humidity = "20%"
print("Humidity: " + self.humidity)

def Rain(self):
self.rain = "10%"
print("Chance of Rain: " + self.rain)

def Summary(self): # Invoke all functions above
for i in range (6):
self.Date(i)
self.Location()
self.Weather()
self.Humidity()
self.Rain()
print("")

location = Weather("Boston")
location.Summary()

"""
Date: 2020-02-26
Location: Boston
Weather: Sunny
Humidity: 20%
Chance of Rain: 10%

Date: 2020-02-27
Location: Boston
Weather: Sunny
Humidity: 20%
Chance of Rain: 10%

Date: 2020-02-28
Location: Boston
Weather: Sunny
Humidity: 20%
Chance of Rain: 10%

Date: 2020-02-29
Location: Boston
Weather: Sunny
Humidity: 20%
Chance of Rain: 10%

Date: 2020-03-01
Location: Boston
Weather: Sunny
Humidity: 20%
Chance of Rain: 10%
"""

Finally, let’s make it to become a real Weather program!

Weather API Reference
API Source

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
################################################################################

# Title: Weather.py #
# File: /Users/zacks/Desktop/Code/Python/Projects/Weather.py #
# Project: /Users/zacks/Desktop/Code/Python/Projects #
# Created Date: 2020-02-26 #
# ----- #
# Author: Zacks Shen #
# Blog: https://zacks.one #
# Email: <zacks.shen@gmail.com> #
# Github: https://github.com/ZacksAmber #
# ----- #
# Last Modified: 2020-02-26 8:32:04 am #
# Modified By: Zacks Shen <zacks.shen@gmail.com> #
# ----- #
# Copyright (c) 2020 Zacks Shen #
################################################################################

import datetime
import requests, json

class Weather:
def __init__(self, location):
self.location = location

def API(self):
# Enter your API key here
api_key = "af239eac3d426ff8aa48238038f3e701"

# base_url variable to store url
base_url = "http://api.openweathermap.org/data/2.5/forecast"

# complete_url variable to store
# complete url address
complete_url = base_url + "?q=" + self.location + "&appid=" + api_key

# get method of requests module
# return response object
response = requests.get(complete_url)

# json method of response object
# convert json format data into
# python format data
self.x = response.json()

def Date(self, date = 0):
self.date = datetime.date.today() + datetime.timedelta(days = date)
print("Date: " + self.date.isoformat())

def Location(self):
print("Location: " + self.location)

def Temperature(self, date = 0):
# - kelvin unit (273.15)
self.temp = int(self.x['list'][date]['main']['temp'] - 273.15)
self.temp_min = int(self.x['list'][date]['main']['temp_min'] - 273.15)
self.temp_max = int(self.x['list'][date]['main']['temp_max'] - 273.15)

print("Temperature: " + str(self.temp) + "°C")
print("Min temperature: " + str(self.temp_min) + "°C")
print("Max temperature: " + str(self.temp_max) + "°C")
def Weather(self, date = 0):
self.weather = self.x['list'][date]['weather'][0]['main']

print("Weather: " + self.weather)

def Humidity(self, date = 0):
self.humidity = self.x['list'][date]['main']['humidity']

print("Humidity: " + str(self.humidity) + "%")

""" Give up because miss information
def Rain(self, date = 0):
self.rain = self.x['list'][date]['rain']['3h']

print("Chance of Rain: " + self.rain)
"""

def Summary(self): # Invoke all functions above
self.API()

for i in range (6):
self.Date(i)
self.Location()
self.Weather(i)
self.Temperature(i)
self.Humidity(i)
# self.Rain(i)
print("")

print("Sample Location: boston")
print("Sample Location: boston, us")
print("Sample Location: boston, ma, us")
print("")
location = Weather(input("Input Your Location: "))
print("")
location.Summary()

I use an open source weather API to gather the weather information. Then I will recieve a request like this:

Demo request

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
print(x['list'][0])

"""
{'dt': 1582729200,
'main': {'temp': 279.16,
'feels_like': 276.41,
'temp_min': 279.1,
'temp_max': 279.16,
'pressure': 1016,
'sea_level': 1016,
'grnd_level': 1013,
'humidity': 85,
'temp_kf': 0.06},
'weather': [{'id': 804,
'main': 'Clouds',
'description': 'overcast clouds',
'icon': '04d'}],
'clouds': {'all': 100},
'wind': {'speed': 1.96, 'deg': 55},
'sys': {'pod': 'd'},
'dt_txt': '2020-02-26 15:00:00'}
"""

This is a nested dict variable that transformed from a JSON file. The only thing I need to do is extract the information I need then transfer them to a readable style.


Update:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import requests
import json
import numpy as np

from datetime import date, datetime, timezone
from itertools import accumulate
from inspect import cleandoc

class Weather:
""" Returns the weather forecasting in the next few days.
"""
def __init__(self, location):
"""__init__ pass location for weather forecasting.

Args:
location (string): your city.

Example:
weather = Weather('boston')
weather.response # review the response in JSON format
weather.data # review all weather data in JSON format
"""
self.location = location
self.response = self._api()
self.data = self.response['list']

def _api(self):
# enter your API key here
api_key = "af239eac3d426ff8aa48238038f3e701"

# base_url
base_url = "http://api.openweathermap.org/data/2.5/forecast"

# complete_url
complete_url = base_url + "?q=" + self.location + "&appid=" + api_key

# call weather api of https://openweathermap.org/api
response = requests.get(complete_url)

# convert reponse to JSON format
return response.json()

def dates(self):
"""dates returns the counterpart indexes in self.weather_data['list'] of each date.

Returns:
dict: {date: [start_index, end_index]}

Example:
weather.days()
"""
# count the number of timestmaps for each date
dates = {}

for i in self.data:
# get date from each piece of data
date = datetime.fromtimestamp(i['dt'], tz=timezone.utc).date().isoformat()
# dates[date] = dates.get(date, []) + [i['dt']] # add timestamp to date
dates[date] = dates.get(date, 0) + 1 # count number of timestamps of date

# extract the start index and end index of each date
ends = list(accumulate(dates.values()))
starts = list(accumulate(dates.values()))
starts.pop() # remove the last item
starts = [0] + starts
t_range = list(zip(starts, ends))

# rewrite days to store the counterpart indexes in self.weather_data['list'] of each date
i = 0
for date in dates:
dates[date] = t_range[i]
i += 1

return dates

def temperature(self, date):
temperatures = []
start, end = self.dates()[date]

for i in self.data[start:end]:
# - kelvin unit (273.15)
temp_min = i['main']['temp_min']
temp_max = i['main']['temp_max']
temperatures.append(round(temp_min - 273.15))
temperatures.append(round(temp_max - 273.15))

return min(temperatures), max(temperatures)

def humidity(self, date):
humidities = []
start, end = self.dates()[date]

for i in self.data[start:end]:
humidities.append(i['main']['humidity'])

return min(humidities), max(humidities)

def today(self):
today = date.today().isoformat()
temp_min, temp_max = self.temperature(today)
humi_min, humi_max = self.humidity(today)

report = f"""
Today's weather:
- Temperature is from {temp_min}°C to {temp_max}°C
- Humidity is from {humi_min}% to {humi_max}%
"""

print(cleandoc(report)) # Clean up indentation from docstrings that are indented to line up with blocks of code.

Add function to class after its definitation

Python
1
2
3
4
5
6
class Calculator:
def __init__(self):
pass

def mean(self, lst):
return sum(lst) / len(lst)
Python
1
2
calculator = Calculator()
l = [1, 2, 3]
Python
1
2
calculator.mean(l)
# 2.0

Add a new function double to Calculator

Python
1
2
3
4
5
def double(self, lst):
return [i * 2 for i in lst]

# This is the way to add a function to a class after it has been defined
Calculator.double = double
Python
1
2
calculator.double(l)
# [2, 4, 6]
Python
1
dir(calculator)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'double',
'mean']

Class Examples


Car

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Car
class Car(object):
num_wheels = 4
gas = 30
headlights = 2
size = 'Tiny'

def __init__(self, make, model):
self.make = make
self.model = model
self.color = 'No color yet. You need to paint me.'
self.wheels = Car.num_wheels
self.gas = Car.gas

def paint(self, color):
self.color = color
return self.make + ' ' + self.model + ' is now ' + color

def drive(self):
if self.wheels < Car.num_wheels or self.gas <= 0:
return 'Cannot drive!'
self.gas -= 10
return self.make + ' ' + self.model + ' goes vroom!'

def pop_tire(self):
if self.wheels > 0:
self.wheels -= 1

def fill_gas(self):
self.gas += 20
return 'Gas level: ' + str(self.gas)

keyboard

We’d like to create a Keyboard class that takes in an arbitrary number of Buttons and stores these Buttons in a dictionary. The keys in the dictionary will be ints that represent the position on the Keyboard, and the values will be the respective Button. Fill out the methods in the Keyboard class according to each description, using the doctests as a reference for the behavior of a Keyboard.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# Keyboard

class Keyboard:
"""A Keyboard takes in a list of buttons, and has a
dictionary of positions as keys, and Buttons as values.

>>> b1 = Button("button1", "H")
>>> b2 = Button("button2", "I")
>>> k = Keyboard([b1, b2])
>>> "button1" in k.buttons.keys() # Make sure to add the button to dictionary
True
>>> k.buttons["button1"].letter
'H'
>>> k.buttons["button1"].name
'button1'
>>> k.press("button1")
'H'
>>> k.press("button100")
''
>>> b1.pressed
1
>>> b2.pressed
0
>>> k.typing(["button1", "button2"])
'HI'
>>> k.typing(["button2", "button1"])
'IH'
>>> b1.pressed # make sure typing calls press!
3
>>> b2.pressed
2
"""

def __init__(self, buttons):
self.buttons = {}
"*** YOUR CODE HERE ***"
# Add objects from buttons to self.buttons
for i in buttons:
self.buttons[i.name] = i

def press(self, name):
"""Takes in a position of the button pressed, and
returns that button's output. Return an empty string
if the button does not exist. You can access the keys
of a dictionary d with d.keys(). """
"*** YOUR CODE HERE ***"
if name in self.buttons.keys():
self.buttons[name].pressed += 1
return self.buttons[name].letter
else:
return ''

def typing(self, typing_input):
"""Takes in a list of buttons to be pressed, and
returns the total output. Make sure to call self.press"""
"*** YOUR CODE HERE ***"
typing_output = ''
for i in typing_input:
typing_output += self.press(i)
return typing_output

class Button:
def __init__(self, name, letter):
self.name = name
self.letter = letter
self.pressed = 0

T88ble

In this lab, you will implement a version of the Table object from Data 8, that we are calling T88ble, appropriately pronounced T-88-bel. We aren’t going to make you implement every single function, but we have table.select()ed the functions table.where(difficulty, are.below(insane)) and table.where(concepts, are.equal_to(relevant)).

Notice that we are representing tables here as a list of rows.

Complete the num_rows, num_cols, and labels functions according to the docstrings.

Complete the column, select, and with_column functions according to the docstrings.

You might find the list.index(value) function to be particularly useful for this problem.

Complete the where function according to the docstring.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# T88ble

simple_table_rows = [['chocolate',2], ['vanilla', 1]]
simple_table_labels = ['Flavor', 'Price']
longer_table_rows = [[1990, 1, 1.5, 12, 7], [2000, 2, 2.5, 25, 10], [2010, 5, 4, 70, 36]]
longer_table_labels = ['Year', 'Bread price', 'Eggs price', 'Average tank of gas', 'Rent per day']

class T88ble():
"""
T88ble is an object similar to the Data 8 Table object.
Here the internal representation is a list of rows.
"""
def __init__(self, rows=[], labels=[]):
self.rows = rows
self.column_labels = labels
#DO NOT CHANGE THE __repr__ functions
def __repr__(self):
result = ""
result += str(self.column_labels) + "\n"
for row in self.rows:
result += str(row) + "\n"
return result
def num_rows(self):
"""
Compute the number of rows in a table.

>>> simple_table = T88ble(simple_table_rows, simple_table_labels)
>>> simple_table.num_rows()
2
>>> longer_table = T88ble(longer_table_rows, longer_table_labels)
>>> longer_table.num_rows()
3
"""
"*** YOUR CODE HERE ***"
return len(self.rows)


def num_cols(self):
"""
Compute the number of cols in a table.

>>> simple_table = T88ble(simple_table_rows, simple_table_labels)
>>> simple_table.num_cols()
2
>>> longer_table = T88ble(longer_table_rows, longer_table_labels)
>>> longer_table.num_cols()
5
"""
"*** YOUR CODE HERE ***"
return len(self.column_labels)


def labels(self):
"""
Lists the column labels in a table.

>>> simple_table = T88ble(simple_table_rows, simple_table_labels)
>>> simple_table.labels()
['Flavor', 'Price']
>>> longer_table = T88ble(longer_table_rows, longer_table_labels)
>>> labels = longer_table.labels() # Make sure to return and not print
>>> labels
['Year', 'Bread price', 'Eggs price', 'Average tank of gas', 'Rent per day']
"""
"*** YOUR CODE HERE ***"
return self.column_labels


def column(self, label):
"""
Returns the values of the column represented by label.

>>> simple_table = T88ble(simple_table_rows, simple_table_labels)
>>> simple_table.column("Flavor")
['chocolate', 'vanilla']
>>> longer_table = T88ble(longer_table_rows, longer_table_labels)
>>> column = longer_table.column("Eggs price")
>>> column # Make sure to return and not print
[1.5, 2.5, 4]
>>> longer_table # Make sure not to mutate the original table
['Year', 'Bread price', 'Eggs price', 'Average tank of gas', 'Rent per day']
[1990, 1, 1.5, 12, 7]
[2000, 2, 2.5, 25, 10]
[2010, 5, 4, 70, 36]
"""
"*** YOUR CODE HERE ***"
index = self.column_labels.index(label)
return [i[index] for i in self.rows]


def with_column(self, label, values):
"""
Returns a new table with an additional or replaced column.
label is a string for the name of a column, values is an list

>>> longer_table = T88ble(longer_table_rows, longer_table_labels)
>>> new_table = longer_table.with_column('Inflation rate', [i for i in range(longer_table.num_rows())])
>>> new_table
['Year', 'Bread price', 'Eggs price', 'Average tank of gas', 'Rent per day', 'Inflation rate']
[1990, 1, 1.5, 12, 7, 0]
[2000, 2, 2.5, 25, 10, 1]
[2010, 5, 4, 70, 36, 2]
>>> longer_table # Make sure not to mutate the original table
['Year', 'Bread price', 'Eggs price', 'Average tank of gas', 'Rent per day']
[1990, 1, 1.5, 12, 7]
[2000, 2, 2.5, 25, 10]
[2010, 5, 4, 70, 36]
"""
"*** YOUR CODE HERE ***"
'''
# Answer
new_table = T88ble([[1990, 1, 1.5, 12, 7, 0], [2000, 2, 2.5, 25, 10, 1], [2010, 5, 4, 70, 36, 2]], ['Year', 'Bread price', 'Eggs price', 'Average tank of gas', 'Rent per day', 'Inflation rate'])
return new_table
'''
import copy

new_rows = copy.deepcopy(self.rows)
for i in range(len(values)):
new_rows[i].append(values[i])

new_column_labels = self.column_labels.copy()
new_column_labels.append(label)

new_table = T88ble(new_rows, new_column_labels)
return new_table


def select(self, labels):
"""
Create a copy of a table with only some of the columns,
reffered to by the list of labels.

>>> simple_table = T88ble(simple_table_rows, simple_table_labels)
>>> simple_table.select(["Flavor"])
['Flavor']
['chocolate']
['vanilla']
>>> simple_table
['Flavor', 'Price']
['chocolate', 2]
['vanilla', 1]
>>> longer_table = T88ble(longer_table_rows, longer_table_labels)
>>> selected = longer_table.select(['Year', 'Average tank of gas'])
>>> selected # Make sure to return and not print
['Year', 'Average tank of gas']
[1990, 12]
[2000, 25]
[2010, 70]
>>> longer_table
['Year', 'Bread price', 'Eggs price', 'Average tank of gas', 'Rent per day']
[1990, 1, 1.5, 12, 7]
[2000, 2, 2.5, 25, 10]
[2010, 5, 4, 70, 36]
"""
"*** YOUR CODE HERE ***"
# Indexes are the labels' indexes in self.column_labels
indexes = [self.column_labels.index(i) for i in labels]
new_rows = []

# Extract each item from the index of each row
for i in self.rows:
new_rows.append([i[index] for index in indexes])

new_table = T88ble(new_rows, labels)
return new_table


def where(self, label, filter_fn):
"""
Create a copy of a table with only the rows that match a filter function.

>>> def above(x):
... return lambda y: y > x
...
>>> longer_table = T88ble(longer_table_rows, longer_table_labels)
>>> filtered = longer_table.where('Eggs price', above(2))
>>> filtered
['Year', 'Bread price', 'Eggs price', 'Average tank of gas', 'Rent per day']
[2000, 2, 2.5, 25, 10]
[2010, 5, 4, 70, 36]
>>> longer_table
['Year', 'Bread price', 'Eggs price', 'Average tank of gas', 'Rent per day']
[1990, 1, 1.5, 12, 7]
[2000, 2, 2.5, 25, 10]
[2010, 5, 4, 70, 36]
"""
"*** YOUR CODE HERE ***"
index = self.column_labels.index(label)
new_rows = []

for i in self.rows:
if filter_fn(i[index]):
new_rows.append(i)

new_table = T88ble(new_rows, self.column_labels)
return new_table

Person

Modify the following Person class to add a repeat method, which repeats the last thing said. If nothing has been said yet, you can have repeat return a string of your choosing. See the doctests for an example of its use.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 00P

class Person(object):
"""Person class.

>>> steven = Person("Steven")
>>> steven.say("Hello")
'Hello'
>>> steven.repeat()
'Hello'
>>> steven.greet()
'Hello, my name is Steven'
>>> steven.repeat()
'Hello, my name is Steven'
>>> steven.ask("preserve abstraction barriers")
'Would you please preserve abstraction barriers'
>>> steven.repeat()
'Would you please preserve abstraction barriers'
"""
def __init__(self, name):
self.name = name
"*** YOUR CODE HERE ***"

def say(self, stuff):
"*** YOUR CODE HERE ***"
# Define variable self.stuffs to store every stuff.
self.stuffs = []
self.stuffs.append(stuff)
return stuff

def ask(self, stuff):
return self.say("Would you please " + stuff)

def greet(self):
return self.say("Hello, my name is " + self.name)

def repeat(self):
"*** YOUR CODE HERE ***"
return self.stuffs[-1]

Account

There are several things wrong with the following code! Debug the Account class to satisfy the docstring.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Account(object):
"""A bank account that allows deposits and withdrawals.

>>> sophia_account = Account('Sophia')
>>> sophia_account.deposit(1000000) # depositing my paycheck for the week
1000000
>>> sophia_account.transactions
[('deposit', 1000000)]
>>> sophia_account.withdraw(100) # buying dinner
999900
>>> sophia_account.transactions
[('deposit', 1000000), ('withdraw', 100)]
"""

interest = 0.02
balance = 1000

def __init__(self, account_holder):
self.balance = 0
self.holder = account_holder
self.transactions = []

def deposit(self, amount):
"""Increase the account balance by amount and return the
new balance.
"""
self.transactions.append(('deposit', amount))
# Wrong code: Account.balance = self.balance + amount
self.balance += amount
return self.balance

def withdraw(self, amount):
"""Decrease the account balance by amount and return the
new balance.
"""
self.transactions.append(('withdraw', amount))
if amount > self.balance:
return 'Insufficient funds'
# Wrong code: self.balance = Account.balance - amount
self.balance -= amount
# Wrong code: return Account.balance
return self.balance

Vending Machine

Create a class called VendingMachine that represents a vending machine for some product. A VendingMachine object returns strings describing its interactions. See the doctest below for examples:

Here’s a quick explanation of some of the functions you need to implement.

  • restock should update the stock and return the current stock.
  • deposit should add money to the balance and return the current balance, unless the stock is zero, then it should inform the user the stock is zero and return the money.
  • vend should either tell you how much more money needs to be deposited to buy a product, or sell you a product and return the change, or let you know the machine is out of stock.

Make sure your outputs match the doctest exactly!

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class VendingMachine:
"""A vending machine that vends some product for some price.

>>> v = VendingMachine('candy', 10)
>>> v.vend()
'Machine is out of stock.'
>>> v.restock(2)
'Current candy stock: 2'
>>> v.vend()
'You must deposit $10 more.'
>>> v.deposit(7)
'Current balance: $7'
>>> v.vend()
'You must deposit $3 more.'
>>> v.deposit(5)
'Current balance: $12'
>>> v.vend()
'Here is your candy and $2 change.'
>>> v.deposit(10)
'Current balance: $10'
>>> v.vend()
'Here is your candy.'
>>> v.deposit(15)
'Machine is out of stock. Here is your $15.'
"""
def __init__(self, product, price):
self.product = product
self.price = price
self.stock = 0
self.balance = 0

"*** YOUR CODE HERE ***"
def restock(self, amount: int):
self.stock += amount
# return 'Current candy stock: {stock}'.format(stock=str(self.stock))
# f-string required Python version >= 3.6
return f'Current candy stock: {self.stock}'

def deposit(self, deposit: float):
self.balance += deposit
if self.stock == 0:
return self.vend()
return f'Current balance: ${self.balance}'

def vend(self):
# Transcation failed due to insufficient stock
if self.stock == 0:
if self.balance == 0:
return 'Machine is out of stock.'
else:
change = self.balance
# return change and clear self.balance
self.balance = 0
return f'Machine is out of stock. Here is your ${change}.'
# Transcation failed due to insufficient fund
elif self.balance < self.price:
insufficient_fund = self.price - self.balance
return f'You must deposit ${insufficient_fund} more.'
# Transcation successful.
else:
# Modify self.stock
self.stock -= 1
# return change and clear self.balance
change = self.balance - self.price
self.balance = 0
if change == 0:
return f'Here is your {self.product}.'
else:
return f'Here is your {self.product} and ${change} change.'

Arr88

In lab you created the T88ble, now you will create arr88, which are similar to numpy arrays from Data 8.

Complete the __len__, and item functions according to the docstrings.

__len__ is a special attribute, like __init__ that allows us to call len on our Arr88s to get their length!

Complete the __add__, __mul__, and negate functions according to the docstrings.

Keep an eye out for which functions mutate the Arr88 and which don’t!

__add__ and __mul__ are also special attributes, like __init__ and __len__, that allow us to use + and * on our Arr88s to add/multiply them componentwise!

Complete the apply function that returns a new list with the function applied to every element.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
class Arr88():
"""
Arr88 is an object similar to Data 8 numpy arrays.
Here the internel representation is a list
"""
def __init__(self, values):
# Check that all values are the same type, else it errors
if len(values) > 1:
assert all([type(values[0]) == type(values[i]) for i in range(len(values))]), "Arr88 must be of homogeneous type"
self._values = values

# DO NOT CHANGE THE __repr__
# This displays the Arr88 nicely in the terminal
def __repr__(self):
return "Arr88(" + str(self._values) + ')'

def __len__(self):
""" Return the length of the Arr88

>>> arr88 = Arr88([1, 2, 3])
>>> len(arr88)
3
>>> arr88 = Arr88([1, 2, 3, 4])
>>> len(arr88)
4
"""
"*** YOUR CODE HERE ***"
return len(self._values)

def item(self, i):
"""
Get the item of the Arr88 at index i
>>> arr88 = Arr88([1, 2, 3])
>>> arr88.item(1)
2
>>> arr88.item(0)
1
"""
"*** YOUR CODE HERE ***"
return self._values[i]

def __add__(self, arr88):
""" Add two Arr88s of the same length element by element

>>> arr88a = Arr88([1, 2, 3])
>>> arr88b = Arr88([4, 5, 6])
>>> arr88a + arr88b
Arr88([5, 7, 9])
>>> arr88a # We aren't mutating arr88a
Arr88([1, 2, 3])
>>> arr88a = Arr88(['He', 'Wor', '!'])
>>> arr88b = Arr88(['llo', 'ld', ''])
>>> arr88c = arr88a + arr88b
>>> arr88c
Arr88(['Hello', 'World', '!'])
"""
# Checks that the lengths are the same
assert len(self) == len(arr88), "Arr88's of different len"
"*** YOUR CODE HERE ***"
import copy
# list
array1 = copy.deepcopy(self._values)
# list
array2 = copy.deepcopy(arr88._values)
new_array = []
for i in zip(array1, array2):
new_array.append(i[0] + i[1])
return Arr88(new_array)


def __mul__(self, arr88):
""" Multiply two Arr88s of the same length componentwise

>>> arr88a = Arr88([1, 2, 3])
>>> arr88b = Arr88([4, 5, 6])
>>> arr88a * arr88b
Arr88([4, 10, 18])
>>> arr88a # We aren't mutating arr88a
Arr88([1, 2, 3])
>>> arr88a = Arr88(['Na', 'Batman', '!'])
>>> arr88b = Arr88([10, 1, 5])
>>> arr88c = arr88a * arr88b
>>> arr88c
Arr88(['NaNaNaNaNaNaNaNaNaNa', 'Batman', '!!!!!'])
"""
# Checks that the lengths are the same
assert len(self) == len(arr88), "Arr88's of different len"
"*** YOUR CODE HERE ***"
import copy
# list
array1 = copy.deepcopy(self._values)
# list
array2 = copy.deepcopy(arr88._values)
new_array = []
for i in zip(array1, array2):
new_array.append(i[0] * i[1])
return Arr88(new_array)

def negate(self):
"""Negate an Arr88 with mutation

>>> arr88a = Arr88([1, 2, 3])
>>> arr88b = Arr88([4.0, -5.5, 0.0])
>>> arr88a.negate()
>>> arr88a
Arr88([-1, -2, -3])
>>> arr88b.negate()
>>> arr88b
Arr88([-4.0, 5.5, -0.0])
"""
"*** YOUR CODE HERE ***"
for i in range(len(self._values)):
self._values[i] = -self._values[i]

def apply(self, func):
""" Apply a function to an Arr88

>>> arr88a = Arr88([1, 2, 3])
>>> arr88a.apply(lambda x : x * x)
Arr88([1, 4, 9])
>>> arr88a # We aren't mutating arr88a
Arr88([1, 2, 3])
>>> arr88b = Arr88([lambda x: x, lambda x: x + 1, lambda x: x + 2])
>>> arr88c = arr88b.apply(lambda f: f(1))
>>> arr88c
Arr88([1, 2, 3])
"""
"*** YOUR CODE HERE ***"
import copy
new_array = copy.deepcopy(self._values)
return Arr88(list(map(func, new_array)))

Python Inheritance

Introduction

Inheritance allows us to define a class that inherits all the methods and properties from another class.

Parent class is the class being inherited from, also called base class.

Child class is the class that inherits from another class, also called derived class.


Create a Parent Class

Any class can be a parent class, so the syntax is the same as creating any other class:

Create a class named Person, with firstname and lastname properties, and afullname` method:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14

class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname

def fullname(self):
print("Hello, I'm {0} {1}".format(self.firstname, self.lastname))

#Use the Person class to create an object, and then execute the fullname method:

x = Person("Zacks", "Shen")
x.fullname()
# Hello, I'm Zacks Shen

Create a Child Class

To create a class that inherits the functionality from another class, send the parent class as a parameter when creating the child class:

Create a class named Student, which will inherit the properties and methods from the Person class:

Python
1
2
3
4
5
6
7
8
9
10
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname

def fullname(self):
print("Hello, I'm {0} {1}".format(self.firstname, self.lastname))

class Student(Person):
pass

Note: Use the pass keyword when you do not want to add any other properties or methods to the class.

Now the Student class has the same properties and methods as the Person class.

Use the Student class to create an object, and then execute the fullname method:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname

def fullname(self):
print("Hello, I'm {0} {1}".format(self.firstname, self.lastname))

class Student(Person):
pass

y = Student("Amber", "Lyu")

y.fullname()
# Hello, I'm Amber Lyu
print(y.firstname)
# Amber
print(y.lastname)
# Lyu

Add the init() Function

So far we have created a child class that inherits the properties and methods from its parent.

We want to add the __init__() function to the child class (instead of the pass keyword).

Note: The __init__() function is called automatically every time the class is being used to create a new object.

Add the __init__() function to the Student class:

Python
1
2
3
class Student(Person):
def __init__(self, fname, lname):
#add properties etc.

When you add the __init__() function, the child class will no longer inherit the parent’s __init__() function.

Note: The child’s __init__() function overrides the inheritance of the parent’s __init__() function.

To keep the inheritance of the parent’s __init__() function, add a call to the parent’s __init__() function:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname

def fullname(self):
print("Hello, I'm {0} {1}".format(self.firstname, self.lastname))

class Student(Person):
def __init__(self, fname, lname, age):
Person.__init__(self, fname, lname)
self.age = age

y = Student("Amber", "Lyu", 18)

print(y.age)
# 18
y.fullname()
# Hello, I'm Amber Lyu
print(y.firstname)
# Amber
print(y.lastname)
# Lyu

If you did not inherit the Parent’s __init__

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname

def fullname(self):
print("Hello, I'm {0} {1}".format(self.firstname, self.lastname))

class Student(Person):
def __init__(self, fname, lname, age):
self.age = age

y = Student("Amber", "Lyu", 18)

print(y.age)
# 18
y.fullname()
# AttributeError: 'Student' object has no attribute 'firstname'
print(y.firstname)
# AttributeError: 'Student' object has no attribute 'firstname'
print(y.lastname)
# AttributeError: 'Student' object has no attribute 'firstname'

Now we have successfully added the __init__() function, and kept the inheritance of the parent class, and we are ready to add functionality in the __init__() function.


Use the super() Function

Python also has a super() function that will make the child class inherit all the methods and properties from its parent:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname

def fullname(self):
print("Hello, I'm {0} {1}".format(self.firstname, self.lastname))

class Student(Person):
def __init__(self, fname, lname):
super().__init__(fname, lname) # Notice no self attribute

y = Student("Amber", "Lyu")

y.fullname()
# Hello, I'm Amber Lyu
print(y.firstname)
# Amber
print(y.lastname)
# Lyu
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname

def fullname(self):
print("Hello, I'm {0} {1}".format(self.firstname, self.lastname))

class Student(Person):
def __init__(self, fname, lname):
Person.__init__(self, fname, lname)

y = Student("Amber", "Lyu")

y.fullname()
# Hello, I'm Amber Lyu
print(y.firstname)
# Amber
print(y.lastname)
# Lyu

By using the super() function, you do not have to use the name of the parent element, it will automatically inherit the methods and properties from its parent.


Add Properties

Add a property called age to the Student class’s __init__():

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname

def fullname(self):
print("Hello, I'm {0} {1}".format(self.firstname, self.lastname))

class Student(Person):
def __init__(self, fname, lname, age):
Person.__init__(self, fname, lname)
self.age = age

y = Student(age = 18, lname = "lyu", fname = "Amber")
print(y.age)
# 18
y.fullname()
# Hello, I'm Amber lyu

Add Methods

Add a method called welcome to the Student class:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname

def fullname(self):
print("Hello, I'm {0} {1}".format(self.firstname, self.lastname))

class Student(Person):
def __init__(self, fname, lname, age):
Person.__init__(self, fname, lname)
self.age = age

def welcome(self):
print("Welcome", self.firstname, self.lastname, ",", self.age, "years old,", "to the class.")

y = Student(age = 18, lname = "lyu", fname = "Amber")
y.welcome()
# Welcome Amber lyu , 18 years old, to the class.

If you add a method in the child class with the same name as a function in the parent class, the inheritance of the parent method will be overridden.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname

def fullname(self):
print("Hello, I'm {0} {1}".format(self.firstname, self.lastname))

class Student(Person):
def __init__(self, fname, lname, age):
Person.__init__(self, fname, lname)
self.age = age

def fullname(self):
print("You did not invoke the parent class")

y = Student("Amber", "Lyu", 18)

print(y.age)
# 18
y.fullname()
# You did not invoke the parent class
print(y.firstname)
# Amber
print(y.lastname)
# Lyu

Examples

Mint

Complete the Mint and Coin classes so that the coins created by a mint have the correct year and worth.

  • Each Mint instance has a year stamp. The update method sets the year stamp to the current_year class attribute of the Mint class.
  • The create method takes a subclass of Coin and returns an instance of that class stamped with the mint’s year (which may be different from Mint.current_year if it has not been updated.)
  • A Coin‘s worth method returns the cents value of the coin plus one extra cent for each year of age beyond 50. A coin’s age can be determined by subtracting the coin’s year from the current_year class attribute of the Mint class.
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class Mint:
"""A mint creates coins by stamping on years.

The update method sets the mint's stamp to Mint.current_year.

>>> mint = Mint()
>>> mint.year
2020
>>> dime = mint.create(Dime)
>>> dime.year
2020
>>> Mint.current_year = 2100 # Time passes
>>> nickel = mint.create(Nickel)
>>> nickel.year # The mint has not updated its stamp yet
2020
>>> nickel.worth() # 5 cents + (80 - 50 years)
35
>>> mint.update() # The mint's year is updated to 2100
>>> Mint.current_year = 2175 # More time passes
>>> mint.create(Dime).worth() # 10 cents + (75 - 50 years)
35
>>> Mint().create(Dime).worth() # A new mint has the current year
10
>>> dime.worth() # 10 cents + (155 - 50 years)
115
>>> Dime.cents = 20 # Upgrade all dimes!
>>> dime.worth() # 20 cents + (155 - 50 years)
125
>>> m = Mint()
>>> n = m.create(Nickel)
>>> n.worth()
5
>>> n.year = 2015
>>> n.worth()
115
"""
current_year = 2020

def __init__(self):
self.update()

def create(self, kind):
# Mint().create(Dime)
"*** YOUR CODE HERE ***"
# Use Mint's year to create a Coin_Instance
Coin_Instance = Coin(self.year)
# Returns an instance of that class stamped with the mint's year
return kind(Coin_Instance.year)

def update(self):
"*** YOUR CODE HERE ***"
# Update self.year to current_year
self.year = Mint.current_year

class Coin:
def __init__(self, year):
self.year = year

def worth(self):
"The worth is a coin's face value + 1 cent for each year over age 50."
"*** YOUR CODE HERE ***"
# If age >= 50, return extra value
if Mint().year - self.year >= 50:
return self.cents + ((Mint().year - self.year) - 50)
# Else, return the original value
else:
return self.cents

class Nickel(Coin):
cents = 5

class Dime(Coin):
cents = 10

Quidditch

It’s time for the opening quidditch match of the season! We represent the various positions for players with the QuidditchPlayer class and its subclasses. Every player begins with a base_energy level, but every position requires a different proportion of energy. Fill in the energy method for the Beater, Chaser, Seeker, and Keeper classes, according to their docstrings. In addition, fill in the __init__ method for the Chaser class.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
class QuidditchPlayer:
def __init__(self, name, base_energy):
"""
QuidditchPlayers have a name, and begin with base_energy.
"""
self.name = name
self.base_energy = base_energy

def energy(self):
return self.base_energy


class Beater(QuidditchPlayer):
role = "bludgers"

def energy(self, time):
"""
Returns the amount of energy left after playing for time minutes.
After playing for time minutes, Beaters lose their base energy level
divided by the number of minutes. If time is 0, catch the ZeroDivisionError
and print "You can't divide by zero!" instead.
>>> fred = Beater("Fred Weasley", 640)
>>> fred.energy(40)
624.0
>>> fred.energy(0)
You can't divide by zero!
"""
"*** YOUR CODE HERE ***"
try:
return self.base_energy - (self.base_energy / time)
# Catch ZeroDivisionError
except ZeroDivisionError:
print("You can't divide by zero!")


class Chaser(QuidditchPlayer):
role = "score"
energy_expended = 20

def __init__(self, name, base_energy, goals):
"""
Chasers have a name, score goals, and begin with base_energy.
"""
"*** YOUR CODE HERE ***"
QuidditchPlayer.__init__(self, name, base_energy)
self.goals = goals

def energy(self, time):
"""
Returns the amount of energy left after playing for time minutes. For every goal
they score, they use energy_expended units of energy. In addition, they also use
10% of energy_expended if the number of minutes they have played is a multiple of 9.
>>> katie = Chaser("Katie Bell", 230, 2)
>>> katie.energy(20)
190
>>> ginny = Chaser("Ginny Weasley", 400, 3)
>>> ginny.energy(45)
338.0
"""
"*** YOUR CODE HERE ***"
if time % 9 == 0:
return self.base_energy - (self.goals * Chaser.energy_expended) - 0.1 * Chaser.energy_expended
else:
return self.base_energy - (self.goals * Chaser.energy_expended)


class Seeker(QuidditchPlayer):
role = "snitch"
energy_expended = 5

def energy(self, time):
"""
Returns the amount of energy after time minutes. Seekers expend energy_expended
units of their energy for every minute they have been playing.
>>> harry = Seeker("Harry Potter", 700)
>>> harry.energy(30)
550
"""
"*** YOUR CODE HERE ***"
return self.base_energy - time * Seeker.energy_expended


class Keeper(QuidditchPlayer):
role = "guard"
energy_expended = 50

def energy(self, time):
"""
Returns the amount of energy after time minutes. If less than 30 minutes have
passed, then Keepers do not lose any energy. If 30 minutes or more have passed,
then Keepers expend 80% of their energy_expended units for every full 15
minutes that pass.
>>> oliver = Keeper("Oliver Wood", 380)
>>> oliver.energy(45)
260.0
"""
"*** YOUR CODE HERE ***"
if time < 30:
return self.base_energy
else:
return self.base_energy - 0.8 * Keeper.energy_expended * (time // 15)

Errors

It is often said that nothing in life is certain but death and taxes. For a programmer or data scientist, however, nothing is certain but encountering errors.

In Python, there are two primary types of errors, both of which you are likely familiar with: syntax errors and exceptions. Syntax errors occur when the proper structure of the language is not followed, while exceptions are errors that occur during the execution of a program. These include errors such as ZeroDivisionError, TypeError, NameError, and many more!

Under the hood, these errors are based in the concepts of object orientation, and all exceptions are class objects. If you’re interested in more detailed explanations of the structure of exceptions as well as how to create your own, check out this article from the Python documentation! In the meantime, we’ll implement our own version of an Error class

Complete the Error, SyntaxError, and ZeroDivisionError classes such that they create the correct messages when called.

  • The SyntaxError and ZeroDivisionError classes inherit from the Error class and add functionality that is unique to those particular errors. Their code is partially implemented for you.
  • The add_code method adds a new helpful message to your error, while the write method should print the output that you see when an error is raised.
  • You can access the parent class methods using the super() function
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class Error:
"""
>>> err1 = Error(12, "error.py")
>>> err1.write()
error.py:12
"""
def __init__(self, line, file):
"*** YOUR CODE HERE ***"
self.line = line
self.file = file

def format(self):
return self.file + ':' + str(self.line)

def write(self):
print(self.format())

class SyntaxError(Error):
"""
>>> err1 = SyntaxError(17, "lab10.py")
>>> err1.write()
lab10.py:17 SyntaxError : Invalid syntax
>>> err1.add_code(4, "EOL while scanning string literal")
>>> err2 = SyntaxError(18, "lab10.py", 4)
>>> err2.write()
lab10.py:18 SyntaxError : EOL while scanning string literal
"""
type = 'SyntaxError'
msgs = {0 : "Invalid syntax", 1: "Unmatched parentheses", 2: "Incorrect indentation", 3: "missing colon"}

def __init__(self, line, file, code=0):
"*** YOUR CODE HERE ***"
super().__init__(line, file)
self.code = code

def format(self):
"*** YOUR CODE HERE ***"
# return self.file + ':' + str(self.line) + ' ' + SyntaxError.type + ' : ' + SyntaxError.msgs[self.code]
return f'{self.file}:{str(self.line)} {SyntaxError.type} : {SyntaxError.msgs[self.code]}'

def add_code(self, code, msg):
"*** YOUR CODE HERE ***"
# Add new code to code dictionary msgs
SyntaxError.msgs[code] = msg


class ZeroDivisionError(Error):
"""
>>> err1 = ZeroDivisionError(273, "lab10.py")
>>> err1.write()
lab10.py:273 ZeroDivisionError : division by zero
"""
type = 'ZeroDivisionError'

def __init__(self, line, file, message='division by zero'):
"*** YOUR CODE HERE ***"
super().__init__(line, file)
self.message = message

def format(self):
end = self.type + ' : ' + self.message
"*** YOUR CODE HERE ***"
return f'{self.file}:{str(self.line)} {ZeroDivisionError.type} : {self.message}'

Checking account

We’d like to be able to cash checks, so let’s add a deposit_check method to our CheckingAccount class. It will take a Check object as an argument, and check to see if the payable_to attribute matches the CheckingAccount‘s holder. If so, it marks the Check as deposited, and adds the amount specified to the CheckingAccount‘s total.

Write an appropriate Check class, and add the deposit_check method to the CheckingAccount class. Make sure not to copy and paste code! Use inheritance whenever possible.

See the doctests for examples of how this code should work.

The Account class has been provided.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class Account(object):
"""A bank account that allows deposits and withdrawals.

>>> eric_account = Account('Eric')
>>> eric_account.deposit(1000000) # depositing my paycheck for the week
1000000
>>> eric_account.transactions
[('deposit', 1000000)]
>>> eric_account.withdraw(100) # buying dinner
999900
>>> eric_account.transactions
[('deposit', 1000000), ('withdraw', 100)]
"""

interest = 0.02

def __init__(self, account_holder):
self.balance = 0
self.holder = account_holder
self.transactions = []

def deposit(self, amount):
"""Increase the account balance by amount and return the
new balance.
"""
self.transactions.append(('deposit', amount))
self.balance = self.balance + amount
return self.balance

def withdraw(self, amount):
"""Decrease the account balance by amount and return the
new balance.
"""
self.transactions.append(('withdraw', amount))
if amount > self.balance:
return 'Insufficient funds'
self.balance = self.balance - amount
return self.balance


class CheckingAccount(Account):
"""A bank account that charges for withdrawals.

>>> check = Check("Steven", 42) # 42 dollars, payable to Steven
>>> steven_account = CheckingAccount("Steven")
>>> eric_account = CheckingAccount("Eric")
>>> eric_account.deposit_check(check) # trying to steal steven's money
The police have been notified.
>>> eric_account.balance
0
>>> check.deposited
False
>>> steven_account.balance
0
>>> steven_account.deposit_check(check)
42
>>> check.deposited
True
>>> steven_account.deposit_check(check) # can't cash check twice
The police have been notified.
"""
withdraw_fee = 1
interest = 0.01

def withdraw(self, amount):
return Account.withdraw(self, amount + self.withdraw_fee)

def deposit_check(self, check):
if (check.payable_to == self.holder) & (check.deposited == False):
# Change check.deposit to True
check.deposited = True
# Call self.deposit function for depositing and returning message
return self.deposit(check.check_amount)
else:
print('The police have been notified.')


class Check(object):
"*** YOUR CODE HERE ***"
# Set False as the default value to deposited
deposited = False

def __init__(self, payable_to, check_amount):
self.payable_to = payable_to
self.check_amount = check_amount

Python Iterators

Introduction

An iterator is an object that contains a countable number of values.

An iterator is an object that can be iterated upon, meaning that you can traverse through all the values.

Technically, in Python, an iterator is an object which implements the iterator protocol, which consist of the methods __iter__() and __next__().


Iterator vs Iterable

Lists, tuples, dictionaries, and sets are all iterable objects. They are iterable containers which you can get an iterator from.

All these objects have a iter() method which is used to get an iterator:

Return an iterator from a list, and print each value:

Python
1
2
3
4
5
6
7
8
9
10
11
l1 = [1, 2, 3]
l = iter(l1)

print(next(l))
# 1
print(next(l))
# 2
print(next(l))
# 3
print(next(l))
# StopIteration:

Even strings are iterable objects, and can return an iterator:

Strings are also iterable objects, containing a sequence of characters:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
s1 = "GUNDAM"
s = iter(s1)

print(next(s))
# G
print(next(s))
# U
print(next(s))
# N
print(next(s))
# D
print(next(s))
# A
print(next(s))
# M
print(next(s))
# StopIteration:

Looping Through an Iterator

We can also use a for loop to iterate through an iterable object:

Python
1
2
3
4
5
6
7
8
l1 = [1, 2, 3]
for i in l1:
print(i)
"""
1
2
3
"""
Python
1
2
3
4
5
6
7
8
9
10
11
s1 = "GUNDAM"
for i in s1:
print(i)
"""
G
U
N
D
A
M
"""

The for loop actually creates an iterator object and executes the next() method for each loop.


Create an Iterator

To create an object/class as an iterator you have to implement the methods __iter__() and __next__() to your object.

As you have learned in the Python Classes/Objects chapter, all classes have a function called __init__(), which allows you do some initializing when the object is being created.

The __iter__() method acts similar, you can do operations (initializing etc.), but must always return the iterator object itself.

The __next__() method also allows you to do operations, and must return the next item in the sequence.

Create an iterator that returns numbers, starting with 1, and each sequence will increase by one (returning 1,2,3,4,5 etc.):

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class MyNumbers:
def __iter__(self):
self.a = 1
return self

def __next__(self):
x = self.a
self.a += 1
return x

myclass = MyNumbers()
myiter = iter(myclass)

print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
"""
1
2
3
4
5
"""

StopIteration

The example above would continue forever if you had enough next() statements, or if it was used in a for loop.

To prevent the iteration to go on forever, we can use the StopIteration statement.

In the __next__() method, we can add a terminating condition to raise an error if the iteration is done a specified number of times:

Stop the program after 20 iterations:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class MyNumbers:
def __iter__(self):
self.a = 1
return self

def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration

myclass = MyNumbers()
myiter = iter(myclass)

for x in myiter:
print(x)
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"""

Python Scope

A variable is only available from inside the region it is created. This is called scope.

Local Scope

A variable created inside a function belongs to the local scope of that function, and can only be used inside that function.

The variable you used in a outside loop is NOT a local scope:

Python
1
2
3
4
5
6
7
8
9
10
11
del(i)
for i in range(3):
print(i)
"""
0
1
2
"""

print(i)
# 2

A variable created inside a function is available inside that function:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
del(i)
def loop(x):
for i in range(x):
print(i)

loop(3)
"""
0
1
2
"""

print(i)
# NameError: name 'i' is not defined

The Benefits of Non-Local Assignment

Python Particulars. This pattern of non-local assignment is a general feature of programming languages with higher-order functions and lexical scope. Most other languages do not require a nonlocal statement at all. Instead, non-local assignment is often the default behavior of assignment statements.

Python also has an unusual restriction regarding the lookup of names: within the body of a function, all instances of a name must refer to the same frame. As a result, Python cannot look up the value of a name in a non-local frame, then bind that same name in the local frame, because the same name would be accessed in two different frames in the same function. This restriction allows Python to pre-compute which frame contains each name before executing the body of a function. When this restriction is violated, a confusing error message results.

2.4.5 The Benefits of Non-Local Assignment

Non-local assignment is an important step on our path to viewing a program as a collection of independent and autonomous objects, which interact with each other but each manage their own internal state.

In particular, non-local assignment has given us the ability to maintain some state that is local to a function, but evolves over successive calls to that function.

This UnboundLocalError appears because balance is assigned locally in line 5, and so Python assumes that all references to balance must appear in the local frame as well. This error occurs before line 5 is ever executed, implying that Python has considered line 5 in some way before executing line 3. As we study interpreter design, we will see that pre-computing facts about a function body before executing it is quite common. In this case, Python’s pre-processing restricted the frame in which balance could appear, and thus prevented the name from being found. Adding a nonlocal statement corrects this error. The nonlocal statement did not exist in Python 2.

Python
1
2
3
4
5
6
7
8
9
10
11
12
def make_withdraw(balance):
# nonlocal balance
def withdraw(amount):
if amount > balance:
return 'Insufficient funds'
balance = balance - amount
return balance
return withdraw

wd = make_withdraw(20)
wd(5)
# UnboundLocalError: local variable 'balance' referenced before assignment

Global Scope

A variable created in the main body of the Python code is a global variable and belongs to the global scope.

Global variables are available from within any scope, global and local.

A variable created outside of a function is global and can be used by anyone:

Python
1
2
3
4
5
6
7
x = 5

def myFunc():
print(x)

myFunc()
# 5

Naming Variables

If you operate with the same variable name inside and outside of a function, Python will treat them as two separate variables, one available in the global scope (outside the function) and one available in the local scope (inside the function):

The function will print the local x, and then the code will print the global x:

Python
1
2
3
4
5
6
7
8
9
10
x = 5

def myFunc():
x = 10
print(x)

myFunc()
# 10
print(x)
# 5

Global Keyword

If you need to create a global variable, but are stuck in the local scope, you can use the global keyword.

The global keyword makes the variable global.

If you use the global keyword, the variable belongs to the global scope:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
def myFunc():
x = 10
global x # You must assigned a global variable before it has value
# ^
# SyntaxError: name 'x' is assigned to before global declaration

def myFunc():
global x
x = 10

myFunc() # And you have to run the function at least once.
print(x)
# 10

Also, use the global keyword if you want to make a change to a global variable inside a function.

To change the value of a global variable inside a function, refer to the variable by using the global keyword:

Python
1
2
3
4
5
6
7
8
x = 5

def myFunc():
global x
x = 10

myFunc()
print(x)

Python ADT

https://cs88-website.github.io/sp21/lab/lab04/#abstract-data-types
https://cs88-website.github.io/sp21/hw/hw04/#politican-adts


Usage

Data abstraction is a powerful concept in computer science that allows programmers to treat code as objects — for example, car objects, chair objects, people objects, etc. That way, programmers don’t have to worry about how code is implemented — they just have to know what it does.

Data abstraction mimics how we think about the world. For example, when you want to drive a car, you don’t need to know how the engine was built or what kind of material the tires are made of. You just have to know how to turn the wheel and press the gas pedal.

An abstract data type consists of two types of functions:

  • Constructors: functions that build the abstract data type.
  • Selectors: functions that retrieve information from the data type.

For example, say we have an abstract data type called definePolitician. This definePolitician object will hold the Politician’s name, and Politician’s party and Politician’s age. To create a definePolitician object, you’d use a constructor like

Python
1
<politician> = definePolitician('<name>', '<party>', <age>)

Notice that we don’t need to know how these functions were implemented. We are assuming that someone else has defined them for us.

It’s okay if the end user doesn’t know how functions were implemented. However, the functions still have to be defined by someone. We’ll look into defining the constructors and selectors later in this discussion.

Example:

I defined an Abstract Data Type that can be reused.
Users could reconstruct or query the ADT data but ignore the data structure.
Imagine you need to define 100 politicians. Without ADT, you have to repeatly type {'name'='<name>', 'party'='<party>', 'age'=<age>}.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def definePolitician(name, party, age):
return {'name': name, 'party': party, 'age': age}

def getName(politician):
return politician['name']

def getParty(politician):
return politician['party']

def getAge(politician):
return politician['age']

# Define ADT variable
trump = definePolitician('Donald Trump', 'Republica', 74)

# Query ADT variable
getName(trump)
# 'Donald Trump'
getParty(trump)
# 'Republica'
getAge(trump)
# 74

# Query ADT variable through dict method - abstraction violation
trump['name']
# 'Donald Trump'
trump['party']
# 'Republica'
trump[age]
# 74

Use lambda to define ADT.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def definePolitician(name, party, age):
return {'name': name, 'party': party, 'age': age}

getName = lambda politician: politician['name']

getParty = lambda politician: politician['party']

getAge = lambda politician: politician['age']

# Define ADT variable
trump = definePolitician('Donald Trump', 'Republica', 74)

# Query ADT variable
getName(trump)
# 'Donald Trump'
getParty(trump)
# 'Republica'
getAge(trump)
# 74

# Query ADT variable through dict method - abstraction violation
trump['name']
# 'Donald Trump'
trump['party']
# 'Republica'
trump[age]
# 74

Use class to simulate ADT.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

class politicianInfo:
def __init__(self, name, party, age):
self.politician = {'name':name, 'party':party, 'age':age}

def getName(self):
return self.politician['name']

def getParty(self):
return self.politician['party']

def getAge(self):
return self.politician['age']

trump = politicianInfo('Donald Trump', 'Republica', 74)

trump.getName()
# 'Donald Trump'
trump.getParty()
# 'Republica'
trump.getAge()
# 74

Think if we can construct class through ADT method in order to reduce code.


Python Modules (Packages)


What is a Module?

Consider a module to be the same as a code library.

A file containing a set of functions you want to include in your application.


Create a Module

To create a module just save the code you want in a file with the file extension .py:

Save the following code as Math.py

Python
1
2
3
4
5
def exp(b, n):
if n > 0:
return b * exp(b, n - 1)
else:
return 1

Use a Module

Now we can use the module we just created, by using the import statement:

Two ways to import a module:

Python
1
2
3
4
import Math

Math.exp(2, 10)
# 1024

OR

Python
1
2
3
4
from Math import exp

exp(2, 10)
# 1024

Note: When using a function from a module, use the syntax: module_name.function_name.
Note: When you loading your module, make sure they are in the same working directory.


Variables in Module

The module can contain functions, as already described, but also variables of all types (arrays, dictionaries, objects etc):

Save the following code as tmp.py.

Python
1
2
3
4
5
person = {
"Name": "Zacks",
"Age": 25,
"Country": "United States"
}
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import tmp

a = tmp.person
print(a)
# {'Name': 'Zacks', 'Age': 25, 'Country': 'United States'}
b = tmp.person["Name"]
print(b)
# Zacks

from tmp import person

print(person)
# {'Name': 'Zacks', 'Age': 25, 'Country': 'United States'}
print(person["Name"])
# Zacks

Naming a Module

You can name the module file whatever you like, but it must have the file extension .py


Re-naming a Module

You can create an alias when you import a module, by using the as keyword:

Python
1
2
3
4
import tmp as population

print(population.person)
# {'Name': 'Zacks', 'Age': 25, 'Country': 'United States'}

Built-in Modules

There are several built-in modules in Python, which you can import whenever you like.

Import and use the platform module:

Python
1
2
3
4
5
6
7
8
9
10
import platform

print(platform.system())
# Darwin
print(platform.mac_ver())
# ('10.15.2', ('', '', ''), 'x86_64')
print(platform.machine())
# x86_64
print(platform.python_version())
# 3.81

Using the dir() Function

There is a built-in function to list all the function names (or variable names) in a module. The dir() function:

List all the defined names belonging to the platform module:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import Math

dir(Math)
"""
['__builtins__',
'__cached__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'exp']
"""

import tmp

dir(tmp)
"""
['__builtins__',
'__cached__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'person']
"""

import platform

dir(platform)
"""
['_WIN32_CLIENT_RELEASES',
'_WIN32_SERVER_RELEASES',
'__builtins__',
'__cached__',
'__copyright__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'__version__',
'_comparable_version',
'_component_re',
'_default_architecture',
'_follow_symlinks',
'_ironpython26_sys_version_parser',
'_ironpython_sys_version_parser',
'_java_getprop',
'_libc_search',
'_mac_ver_xml',
'_node',
'_norm_version',
'_platform',
'_platform_cache',
'_pypy_sys_version_parser',
'_sys_version',
'_sys_version_cache',
'_sys_version_parser',
'_syscmd_file',
'_syscmd_uname',
'_syscmd_ver',
'_uname_cache',
'_ver_output',
'_ver_stages',
'architecture',
'collections',
'java_ver',
'libc_ver',
'mac_ver',
'machine',
'node',
'os',
'platform',
'processor',
'python_branch',
'python_build',
'python_compiler',
'python_implementation',
'python_revision',
'python_version',
'python_version_tuple',
're',
'release',
'sys',
'system',
'system_alias',
'uname',
'uname_result',
'version',
'win32_edition',
'win32_is_iot',
'win32_ver']
"""

Anaconda

Anaconda
Uninstalling Anaconda

By default, the Python interpreter will search for all installed built-in modules and third-party modules in the current working directory. The search path is stored in the path variable of the sys module.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import platform

print(platform.python_version())
# 3.8.1

import sys

sys.path
"""
['/private/var/folders/31/lj6nmqhx1711vgv7r7g9r_cm0000gp/T/9c5d056e-aad5-4997-99e9-b8991b740258',
'/Library/Frameworks/Python.framework/Versions/3.8/lib/python38.zip',
'/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8',
'/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/lib-dynload',
'',
'/Users/zack/Library/Python/3.8/lib/python/site-packages',
'/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages',
'/Users/zack/Library/Python/3.8/lib/python/site-packages/IPython/extensions',
'/Users/zack/.ipython']
"""

Anaconda is a free and open-source distribution of the Python and R programming languages for scientific computing (data science, machine learning applications, large-scale data processing, predictive analytics, etc.), that aims to simplify package management and deployment. Package versions are managed by the package management system conda. The Anaconda distribution includes data-science packages suitable for Windows, Linux, and MacOS. Click here to Download Anaconda, and choose 64-Bit Command Line Installer.

Then run the installer in your shell, the installer version may be different:

CLI
1
bash Anaconda3-2019.10-MacOSX-x86_64.sh

Before install Anaconda.

After install Anaconda.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import platform

print(platform.python_version())
# 3.7.4

import sys

sys.path
"""
['/private/var/folders/31/lj6nmqhx1711vgv7r7g9r_cm0000gp/T/c1b404a3-2753-4a56-931a-20c02831e04f',
'/Users/zack/.vscode/extensions/ms-python.python-2020.1.58038/pythonFiles',
'/Users/zack/.vscode/extensions/ms-python.python-2020.1.58038/pythonFiles/lib/python',
'/Users/zack/opt/anaconda3/lib/python37.zip',
'/Users/zack/opt/anaconda3/lib/python3.7',
'/Users/zack/opt/anaconda3/lib/python3.7/lib-dynload',
'',
'/Users/zack/opt/anaconda3/lib/python3.7/site-packages',
'/Users/zack/opt/anaconda3/lib/python3.7/site-packages/aeosa',
'/Users/zack/opt/anaconda3/lib/python3.7/site-packages/IPython/extensions',
'/Users/zack/.ipython']
"""

Anaconda integrates abundant packages for data science, which means you do not need to install them one by one. However, if you want to add another path including some packages to your python and the path is not your current .py file path, there are two ways to reach your target.

Add a temporary path

Replace /tmp to your path.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys

sys.path.append("/tmp")
sys.path
"""
['/private/var/folders/31/lj6nmqhx1711vgv7r7g9r_cm0000gp/T/c1b404a3-2753-4a56-931a-20c02831e04f',
'/Users/zack/.vscode/extensions/ms-python.python-2020.1.58038/pythonFiles',
'/Users/zack/.vscode/extensions/ms-python.python-2020.1.58038/pythonFiles/lib/python',
'/Users/zack/opt/anaconda3/lib/python37.zip',
'/Users/zack/opt/anaconda3/lib/python3.7',
'/Users/zack/opt/anaconda3/lib/python3.7/lib-dynload',
'',
'/Users/zack/opt/anaconda3/lib/python3.7/site-packages',
'/Users/zack/opt/anaconda3/lib/python3.7/site-packages/aeosa',
'/Users/zack/opt/anaconda3/lib/python3.7/site-packages/IPython/extensions',
'/Users/zack/.ipython',
'/tmp']
"""

Add a permanent path

https://bic-berkeley.github.io/psych-214-fall-2016/using_pythonpath.html


name

To avoid running executable statements in a script when it’s imported as a module in another script, include these lines in an if __name__ == "__main__" block. Or alternatively, include them in a function called main() and call this in the if main block.

Whenever we run a script like this, Python actually sets a special built-in variable called __name__ for any module. When we run a script, Python recognizes this module as the main program, and sets the __name__ variable for this module to the string "__main__". For any modules that are imported in this script, this built-in __name__ variable is just set to the name of that module. Therefore, the condition if __name__ == "__main__"is just checking whether this module is the main program.


Standard Library

The Python Standard Library

  • csv: very convenient for reading and writing csv files
  • collections: useful extensions of the usual data types including OrderedDict, defaultdict and namedtuple
  • random: generates pseudo-random numbers, shuffles sequences randomly and chooses random items
  • string: more functions on strings. This module also contains useful collections of letters like string.digits (a string containing all characters which are valid digits).
  • re: pattern-matching in strings via regular expressions
  • math: some standard mathematical functions
  • os: interacting with operating systems
  • os.path: submodule of os for manipulating path names
  • sys: work directly with the Python interpreter
  • json: good for reading and writing json files (good for web work)

Third-Party Libraries

There are tens of thousands of third-party libraries written by independent developers! You can install them using pip, a package manager that is included with Python 3. pip is the standard package manager for Python, but it isn’t the only one. One popular alternative is Anaconda which is designed specifically for data science.

To install a package using pip, just enter “pip install” followed by the name of the package in your command line like this: pip install package_name. This downloads and installs the package so that it’s available to import in your programs. Once installed, you can import third-party packages using the same syntax used to import from the standard library.

Using a requirements.txt File

Larger Python programs might depend on dozens of third party packages. To make it easier to share these programs, programmers often list a project’s dependencies in a file called requirements.txt. This is an example of a requirements.txt file.

1
2
3
4
beautifulsoup4==4.5.1
bs4==0.0.1
pytz==2016.7
requests==2.11.1

Each line of the file includes the name of a package and its version number. The version number is optional, but it usually should be included. Libraries can change subtly, or dramatically, between versions, so it’s important to use the same library versions that the program’s author used when they wrote the program.

You can use pip to install all of a project’s dependencies at once by typing pip install -r requirements.txt in your command line.

Useful Third-Party Packages

Being able to install and import third party libraries is useful, but to be an effective programmer you also need to know what libraries are available for you to use. People typically learn about useful new libraries from online recommendations or from colleagues. If you’re a new Python programmer you may not have many colleagues, so to get you started here’s a list of packages that are popular with engineers at Udacity.

  • IPython - A better interactive Python interpreter
  • requests - Provides easy to use methods to make web requests. Useful for accessing web APIs.
  • Flask - a lightweight framework for making web applications and APIs.
  • Django - A more featureful framework for making web applications. Django is particularly good for designing complex, content heavy, web applications.
  • Beautiful Soup - Used to parse HTML and extract information from it. Great for web scraping.
  • pytest - extends Python’s builtin assertions and unittest module.
  • PyYAML - For reading and writing YAML files.
  • NumPy - The fundamental package for scientific computing with Python. It contains among other things a powerful N-dimensional array object and useful linear algebra capabilities.
  • pandas - A library containing high-performance, data structures and data analysis tools. In particular, pandas provides dataframes!
  • matplotlib - a 2D plotting library which produces publication quality figures in a variety of hardcopy formats and interactive environments.
  • ggplot - Another 2D plotting library, based on R’s ggplot2 library.
  • Pillow - The Python Imaging Library adds image processing capabilities to your Python interpreter.
  • pyglet - A cross-platform application framework intended for game development.
  • Pygame - A set of Python modules designed for writing games.
  • pytz - World Timezone Definitions for Python

Python Datetime

Python Dates

A date in Python is not a data type of its own, but we can import a module named datetime to work with dates as date objects.

Import datetime module and show its functions

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import datetime

dir(datetime)
"""
['MAXYEAR',
'MINYEAR',
'__builtins__',
'__cached__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'date',
'datetime',
'datetime_CAPI',
'sys',
'time',
'timedelta',
'timezone',
'tzinfo']
"""

Import datetime module and display the current date:

Python
1
2
3
4
import datetime

datetime.datetime.now()
# datetime.datetime(2020, 2, 5, 15, 33, 8, 732931)

Date Output

When we execute the code from the example above the result will be:

2020, 2, 5, 15, 33, 8, 732931

The date contains year, month, day, hour, minute, second, and microsecond.

The datetime module has many methods to return information about the date object.

Here are a few examples, you will learn more about them later in this chapter:

Return the year and name of weekday:

Python
1
2
3
4
5
6
7
import datetime

t = datetime.datetime.now()
print(t. year)
# 2020
print(t.strftime("%A"))
# Wednesday

Creating Date Objects

To create a date, we can use the datetime() class (constructor) of the datetime module.

The datetime() class requires three parameters to create a date: year, month, day.

The datetime() class also takes parameters for time and timezone (hour, minute, second, microsecond, tzone), but they are optional, and has a default value of 0, (None for timezone).

Create a date object:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
import datetime

Kobe_Bryant = datetime.datetime(2020, 1, 26)
print(Kobe_Bryant)
# 2020-01-26 00:00:00
print(Kobe_Bryant.day)
# 26

Kobe_Bryant = datetime.datetime(2020, 1, 26, 15, 50, 23)
Kobe_Bryant.isoformat()
# '2020-01-26T15:50:23'
Kobe_Bryant.ctime()
# 'Sun Jan 26 15:50:23 2020'

The strftime() Method

The datetime object has a method for formatting date objects into readable strings.

The method is called strftime(), and takes one parameter, format, to specify the format of the returned string:

Python
1
2
3
4
5
6
7
8
import datetime

Kobe_Bryant = datetime.datetime(2020, 1, 26, 15, 50, 23)
print(Kobe_Bryant.strftime("%B"))
# January

print(Kobe_Bryant.strftime("%Y-%m-%d %H:%M:%S"))
# 2020-01-26 15:50:23

A reference of all the legal format codes:

Directive Description Example
%a Weekday, short version Wed
%A Weekday, full version Wednesday
%w Weekday as a number 0-6, 0 is Sunday 3
%d Day of month 01-31 31
%b Month name, short version Dec
%B Month name, full version December
%m Month as a number 01-12 12
%y Year, short version, without century 18
%Y Year, full version 2018
%H Hour 00-23 17
%I Hour 00-12 05
%p AM/PM PM
%M Minute 00-59 41
%S Second 00-59 08
%f Microsecond 000000-999999 548513
%z UTC offset +0100
%Z Timezone CST
%j Day number of year 001-366 365
%U Week number of year, Sunday as the first day of week, 00-53 52
%W Week number of year, Monday as the first day of week, 00-53 52
%c Local version of date and time Mon Dec 31 17:41:00 2018
%x Local version of date 12/31/18
%X Local version of time 17:41:00
%% A % character %

Time calculation

Time calculation

Python
1
2
3
4
5
import datetime 

t = datetime.timedelta(hours=12, minutes=10, seconds=36) - datetime.timedelta(hours=12, minutes=8, seconds=16)
str(t)
# '0:02:20'

Stopwatch

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import datetime
import time # module for letting python sleep

startTime = datetime.datetime.now().time()
time.sleep(5) # let python wait 5s to run the next line
endTime = datetime.datetime.now().time()

# get the datetime.timedelta
procTime = datetime.timedelta(hours=endTime.hour, minutes=endTime.minute, seconds=endTime.second) - datetime.timedelta(hours=startTime.hour, minutes=startTime.minute, seconds=startTime.second)
procTime
# datetime.timedelta(seconds=5)

procTime = str(procTime) # convert the datetime.delta to style "%H:%M:%S""
procTime
# '0:00:05'


Yesterday, Today, and Tomorrow

Python
1
2
3
4
5
6
7
8
9
10
import datetime

datetime.date.today() - datetime.timedelta(days = 1)
# datetime.date(2020, 2, 25)
datetime.date.today()
# datetime.date(2020, 2, 26)
datetime.date.today() + datetime.timedelta(days = 1)
# datetime.date(2020, 2, 27)
datetime.date.today() + datetime.timedelta(days = 7)
# datetime.date(2020, 3, 4)

Python JSON

JSON is a syntax for storing and exchanging data.

JSON is text, written with JavaScript object notation.


JSON in Python

Python has a built-in package called json, which can be used to work with JSON data.

Import the json module:

Python
1
import json

Parse JSON - Convert from JSON to Python

If you have a JSON string, you can parse it by using the json.loads() method.

The result will be a Python dictionary.

Convert from JSON to Python:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import json

# some JSON:
x = '{ "name":"John", "age":30, "city":"New York"}'

# parse x:
y = json.loads(x)

# the result is a Python dictionary:
print(y["age"])
# 30

type(y)
# dict

Convert from Python to JSON

If you have a Python object, you can convert it into a JSON string by using the json.dumps()method.

Convert from Python to JSON:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import json

# a Python object (dict):
x = {
"name": "John",
"age": 30,
"city": "New York"
}

# convert into JSON:
y = json.dumps(x)

# the result is a JSON string:
print(y)
# {"name": "John", "age": 30, "city": "New York"}
type(x)
# dict
type(y)
# str

You can convert Python objects of the following types, into JSON strings:

  • dict
  • list
  • tuple
  • string
  • int
  • float
  • True
  • False
  • None

Convert Python objects into JSON strings, and print the values:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import json

print(json.dumps({"name": "John", "age": 30}))
print(json.dumps(["apple", "bananas"]))
print(json.dumps(("apple", "bananas")))
print(json.dumps("hello"))
print(json.dumps(42))
print(json.dumps(31.76))
print(json.dumps(True))
print(json.dumps(False))
print(json.dumps(None))
"""
{"name": "John", "age": 30}
["apple", "bananas"]
["apple", "bananas"]
"hello"
42
31.76
true
false
null
"""
Python JSON
dict Object
list Array
tuple Array
str String
int Number
float Number
True true
False false
None null

Convert a Python object containing all the legal data types:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import json

x = {
"name": "John",
"age": 30,
"married": True,
"divorced": False,
"children": ("Ann","Billy"),
"pets": None,
"cars": [
{"model": "BMW 230", "mpg": 27.5},
{"model": "Ford Edge", "mpg": 24.1}
]
}

print(json.dumps(x))
# {"name": "John", "age": 30, "married": true, "divorced": false, "children": ["Ann", "Billy"], "pets": null, "cars": [{"model": "BMW 230", "mpg": 27.5}, {"model": "Ford Edge", "mpg": 24.1}]}

Format the Result

The example above prints a JSON string, but it is not very easy to read, with no indentations and line breaks.

The json.dumps() method has parameters to make it easier to read the result:

Use the indent parameter to define the numbers of indents:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
json.dumps(x, indent=4)
"""
{
"name": "John",
"age": 30,
"married": true,
"divorced": false,
"children": [
"Ann",
"Billy"
],
"pets": null,
"cars": [
{
"model": "BMW 230",
"mpg": 27.5
},
{
"model": "Ford Edge",
"mpg": 24.1
}
]
}
"""

You can also define the separators, default value is (,, :), which means using a comma and a space to separate each object, and a colon and a space to separate keys from values:

Use the separators parameter to change the default separator:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
json.dumps(x, indent=4, separators=(". ", "= "))
"""
{
"name" = "John".
"age" = 30.
"married" = true.
"divorced" = false.
"children" = [
"Ann".
"Billy"
],
"pets" = null.
"cars" = [
{
"model" = "BMW 230".
"mpg" = 27.5
}.
{
"model" = "Ford Edge".
"mpg" = 24.1
}
]
}
"""

Order the Result

The json.dumps() method has parameters to order the keys in the result:

Use the sort_keys parameter to specify if the result should be sorted or not:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
json.dumps(x, indent=4, sort_keys=True)
"""
{
"age": 30,
"cars": [
{
"model": "BMW 230",
"mpg": 27.5
},
{
"model": "Ford Edge",
"mpg": 24.1
}
],
"children": [
"Ann",
"Billy"
],
"divorced": false,
"married": true,
"name": "John",
"pets": null
}

Writing JSON to a File

Scott Robinson (August 17, 2016). Reading and Writing JSON to a File in Python

The easiest way to write your data in the JSON format to a file using Python is to use store your data in a dict object, which can contain other nested dicts, arrays, booleans, or other primitive types like integers and strings. You can find a more detailed list of data types supported here.

The built-in json package has the magic code that transforms your Python dict object in to the serialized JSON string.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import json

# Create a dict named data; data has one key.
data = {}
data['people'] = []

# Add three values to the key people.
data['people'].append({
'name': 'Scott',
'website': 'stackabuse.com',
'from': 'Nebraska'
})
data['people'].append({
'name': 'Larry',
'website': 'google.com',
'from': 'Michigan'
})
data['people'].append({
'name': 'Tim',
'website': 'apple.com',
'from': 'Alabama'
})

# Create a file named sample.json then export the variable out_file to it. It will be saved to the same working directory as your current Python working directory.
with open('sample.json', 'w') as out_file:
json.dump(data, out_file)
# {'people': [{'name': 'Scott', 'website': 'stackabuse.com', 'from': 'Nebraska'}, {'name': 'Larry', 'website': 'google.com', 'from': 'Michigan'}, {'name': 'Tim', 'website': 'apple.com', 'from': 'Alabama'}]}

After importing the json library, we construct some simple data to write to our file. The important part comes at the end when we use the with statement to open our destination file, then use json.dump to write the data object to the outfile file.

Any file-like object can be passed to the second argument, even if it isn’t an actual file. A good example of this would be a socket, which can be opened, closed, and written to much like a file. With JSON being popular throughout the web, this is another use-case you may encounter.

A slight variation on the json.dump method that’s worth mentioning is json.dump, which returns the actual JSON string instead of sending it directly to a writable object. This can give you some more control if you need to make some changes to the JSON string (like encrypting it, for example).


Reading JSON from a File

On the other end, reading JSON data from a file is just as easy as writing it to a file. Using the same json package again, we can extract and parse the JSON string directly from a file object. In the following example, we do just that and then print out the data we got:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import json

with open('sample.json') as json_file:
data = json.load(json_file)
for i in data['people']:
print('Name: ' + i['name'])
print('Website: ' + i['website'])
print('From: ' + i['from'])
print('')
"""
Name: Scott
Website: stackabuse.com
From: Nebraska

Name: Larry
Website: google.com
From: Michigan

Name: Tim
Website: apple.com
From: Alabama
"""

json.load is the important method to note here. It reads the string from the file, parses the JSON data, populates a Python dict with the data and returns it back to you.

Just like json.dump, json.load has an alternative method that lets you deal with strings directly since many times you probably won’t have a file-like object that contains your JSON. As you probably guessed, this method is json.load. Consider the case where you’re calling a REST GET endpoint that returns JSON. This data comes to you as a string, which you can then pass to json.loads directly instead.


Python RegEx

A RegEx, or Regular Expression, is a sequence of characters that forms a search pattern.

RegEx can be used to check if a string contains the specified search pattern.


RegEx Module

Python has a built-in package called re, which can be used to work with Regular Expressions.

Import the re module:

Python
1
import re

RegEx Functions

The re module offers a set of functions that allows us to search a string for a match:

Function Description
findall Returns a list containing all matches
search Returns a Match object if there is a match anywhere in the string
split Returns a list where the string has been split at each match
sub Replaces one or many matches with a string

We will try re.findall function first. Then learn the other three functions.


Metacharacters

Metacharacters are characters with a special meaning:

Character Description Example
[] A set of characters; Or a set for punctuations. "[a-e]"
\ Signals a special sequence(can also be used to escape special characters) "\d"
. Any character (except newline character) "Pa..y"
^ Starts with "^The"
$ Ends with "2020[.]$"
* Zero or more occurrences "isx*"
+ One or more occurrences "ine+"
? Zero or one occurrence "ab?"
{} Exactly the specified number of occurrences "om{2} -> omm"; "os{m, n}"
| Either or "Chi|Com"
() Capture and group "(ine)(se)*";"(ab|bc)"
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.findall("[a-e]", China) # Returns a list containing all matches in the original sequence and case sentitive.
# ['e', 'e', 'e', 'a', 'd', 'e', 'a', 'e']

re.findall("\d", China) # Find all digit characters:
# ['2', '0', '2', '0']

re.findall("Pa..y", China) # Search for a sequence that starts with "Pa", followed by two (any) characters, and an "y":
# ['Party']

re.findall("^The", China) # Check if the string starts with 'The':
# ['The']

re.findall("2020[.]$", China) # Check if the string ends with '2020.':
# ['2020.']

re.findall("isx*", China) # Check if the string contains "is" followed by 0 or more "x" characters. It returns 'is' twice because 'x' occures 0 time.
# ['is', 'is']

re.findall("ine+", China) # Check if the string contains "in" followed by 1 or more "e" characters:
# ['ine']

re.findall("om{2}", China) # Check if the string contains "o" followed by exactly two "m" characters:
# ['omm']

re.findall("Chi|Com", China) # Check if the string contains either "Chi" or "Com":
# ['Chi', 'Com']

re.findall("(Par)", China) # Put a series characters in a group. In this case, it is the same as "Par".

re.findall("(ine)(se)*", China) # Check if the string contains "ine" followed by 0 or more "se" characters:
# [('ine', 'se')]

re.findall("inese*", China) # Check if the string contains "ines" followed by 0 or more "e" characters:
# ['inese']

re.findall("(ine)(xx)*", China) # Check if the string contains "ine" followed by 0 or more "xx" characters:
# [('ine', '')]

Special Sequences \

A special sequence is a \ followed by one of the characters in the list below, and has a special meaning:

Character Description Example
\A Returns a match if the specified characters are at the beginning of the string "\AThe"
\b Returns a match where the specified characters are at the beginning or at the end of a word r"\bThe" r"2020[.]\b"
\B Returns a match where the specified characters are present, but NOT at the beginning (or at the end) of a word r"\BChi" r"hi\B"
\d Returns a match where the string contains digits (numbers from 0-9) "\d"
\D Returns a match where the string DOES NOT contain digits "\D"
\s Returns a match where the string contains a white space character "\s"
\S Returns a match where the string DOES NOT contain a white space character "\S"
\w Returns a match where the string contains any word characters (characters from a to Z, digits from 0-9, and the underscore _ character) "\w"
\W Returns a match where the string DOES NOT contain any word characters "\W"
\Z Returns a match if the specified characters are at the end of the string "2020[.]\Z"
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.findall("\AThe", China) # Check if the string starts with "The":
# ['The']
re.findall("\AThe", China) == re.findall("^The", China)
# True

# Note: Prefix r or R is used for escaping sequence.
print('a\\ab') # Backslash (\)
# a\ab
print('aa\ab') # ASCII Bell (BEL)
# aab
print('aa\bb') # ASCII Backspace (BS)
# ab
print('aa\fb') # Formfeed
# aa
# b
print('aa\nb') # ASCII Linefeed (LF)
# aa
# b
print('aa\rb') # Carriage Return
# b
print('aa\tb') # ASCII Horizontal Tab (TAB
# aa b
print('aa\vb') # ASCII Vertical Tab (VT)
# aa
# b

re.findall(r"\bThe", China) # Check if the string starts or ends with "The":
# ['The']
re.findall(r"\b2020[.]", China) # Check if the string starts or ends with "2020.":
# ['2020.']

re.findall(r'\BChi', China) # Check if "Chi" is present, but NOT at the beginning of a word:
# []
re.findall(r'\Bhi', China) # Check if "hi" is present, but NOT at the beginning of or at the end of a WORD:
# hi

re.findall('\d', China) # Check if the string contains any digits (numbers from 0-9):
# ['2', '0', '2', '0']

re.findall('\D', China) # Return a match at every no-digit character:
"""
['T',
'h',
'e',
' ',
'C',
'h',
'i',
'n',
'e',
's',
'e',
' ',
'C',
'o',
'm',
'm',
'u',
'n',
'i',
's',
't',
' ',
'P',
'a',
'r',
't',
'y',
' ',
'w',
'i',
'l',
'l',
' ',
'd',
'i',
's',
'i',
'n',
't',
'e',
'g',
'r',
'a',
't',
'e',
' ',
'i',
'n',
' ',
'.']
"""

re.findall('\s', China) # Return a match at every white-space character:
# [' ', ' ', ' ', ' ', ' ', ' ', ' ']
re.search('\s', China)
# <re.Match object; span=(3, 4), match=' '>
re.split('\s', China)
# ['The', 'Chinese', 'Communist', 'Party', 'will', 'disintegrate', 'in', '2020.']

re.findall('\S', China) # Return a match at every NON white-space character:
"""
['T',
'h',
'e',
'C',
'h',
'i',
'n',
'e',
's',
'e',
'C',
'o',
'm',
'm',
'u',
'n',
'i',
's',
't',
'P',
'a',
'r',
't',
'y',
'w',
'i',
'l',
'l',
'd',
'i',
's',
'i',
'n',
't',
'e',
'g',
'r',
'a',
't',
'e',
'i',
'n',
'2',
'0',
'2',
'0',
'.']
"""

re.findall('\w', China) # Return a match at every word character (characters from a to Z, digits from 0-9, and the underscore _ character):
"""
['T',
'h',
'e',
'C',
'h',
'i',
'n',
'e',
's',
'e',
'C',
'o',
'm',
'm',
'u',
'n',
'i',
's',
't',
'P',
'a',
'r',
't',
'y',
'w',
'i',
'l',
'l',
'd',
'i',
's',
'i',
'n',
't',
'e',
'g',
'r',
'a',
't',
'e',
'i',
'n',
'2',
'0',
'2',
'0']
"""

re.findall('\W', China) # Return a match at every NON word character (characters NOT between a and Z. Like "!", "?" white-space etc.):
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', '.']

re.findall('2020[.]\Z', China) # Check if the string ends with "2020.":
# ['2020.']
re.findall('2020[.]\Z', China) == re.findall('2020[.]$', China)
# True

Sets []

A set is a set of characters inside a pair of square brackets [] with a special meaning:

Set Description
[arn] Returns a match where one of the specified characters (a, r, or n) are present
[a-n] Returns a match for any lower case character, alphabetically between a and n
[^arn] Returns a match for any character EXCEPT a, r, and n
[0123] Returns a match where any of the specified digits (0, 1, 2, or 3) are present
[0-9] Returns a match for any digit between 0 and 9
[0-5][0-9] Returns a match for any two-digit numbers from 00 and 59
[a-zA-Z] Returns a match for any character alphabetically between a and z, lower case OR upper case
[+] In sets, +, *, ., , (), $,{} has no special meaning, so [+] means: return a match for any + character in the string
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.findall('[arn]', China) # Check if the string has any a, r, or n characters:
# ['n', 'n', 'a', 'r', 'n', 'r', 'a', 'n']

re.findall('[a-n]', China) # Check if the string has any characters between a and n:
"""
['h',
'e',
'h',
'i',
'n',
'e',
'e',
'm',
'm',
'n',
'i',
'a',
'i',
'l',
'l',
'd',
'i',
'i',
'n',
'e',
'g',
'a',
'e',
'i',
'n']
"""

re.findall('[^arn]', China) # Check if the string has other characters than a, r, or n:
"""
['T',
'h',
'e',
' ',
'C',
'h',
'i',
'e',
's',
'e',
' ',
'C',
'o',
'm',
'm',
'u',
'i',
's',
't',
' ',
'P',
't',
'y',
' ',
'w',
'i',
'l',
'l',
' ',
'd',
'i',
's',
'i',
't',
'e',
'g',
't',
'e',
' ',
'i',
' ',
'2',
'0',
'2',
'0',
'.']
"""

re.findall('[0123]', China) # Check if the string has any 0, 1, 2, or 3 digits:
# ['2', '0', '2', '0']

re.findall('[0-9]', China) # Check if the string has any digits:
# ['2', '0', '2', '0']
re.findall('[0-9]', China) == re.findall('\d', China)
# True

re.findall('[0-5][0-9]', China) # Check if the string has any two-digit numbers, from 00 to 59:
# ['20', '20']

re.findall('[a-zA-Z]', China) # Check if the string has any characters from a to z lower case, and A to Z upper case:
"""
['T',
'h',
'e',
'C',
'h',
'i',
'n',
'e',
's',
'e',
'C',
'o',
'm',
'm',
'u',
'n',
'i',
's',
't',
'P',
'a',
'r',
't',
'y',
'w',
'i',
'l',
'l',
'd',
'i',
's',
'i',
'n',
't',
'e',
'g',
'r',
'a',
't',
'e',
'i',
'n']
"""
re.findall('[a-zA-Z0-9_]', China) == re.findall('\w', China)
# True

re.findall('[.]', China) # Check if the string has any . characters:
# ['.']

RegEx in Python

When you have imported the re module, you can start using regular expressions and combine them together:

Python
1
2
3
4
5
6
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.findall('^The.*2020[.]$', China) # Check if the string starts with "The" and ends with "2020.":
# 'The Chinese Communist Party will disintegrate in 2020.']

The findall() Function

The findall() function returns a list containing all matches.

Python
1
2
3
4
5
import re

China = "The Chinese Communist Party will disintegrate in 2020."
re.findall('Chi', China) # Return a list containing every occurrence of "Chi":
# ['Chi']

The list contains the matches in the order they are found.
If no matches are found, an empty list is returned:

Python
1
2
3
4
5
6
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.findall('chi', China) # Return a list containing every occurrence of "chi":
# []

The search() Function

The search() function searches the string for a match, and returns a Match object if there is a match.

If there is more than one match, only the first occurrence of the match will be returned:

Python
1
2
3
4
5
6
7
8
9
10
11
12
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.findall('\s', China) # Return a match at every white-space character:
# [' ', ' ', ' ', ' ', ' ', ' ', ' ']
re.search('\s', China)
# <re.Match object; span=(3, 4), match=' '>
re.search('\s', China).start() # Search for the first white-space character in the string:
# 3
re.split('\s', China)
# ['The', 'Chinese', 'Communist', 'Party', 'will', 'disintegrate', 'in', '2020.']

If no matches are found, the value None is returned:

Python
1
2
3
4
5
6
import re

China = "The Chinese Communist Party will disintegrate in 2020."

print(re.search('[!]', China)) # Make a search that returns no match:
# None

The split() Function

The split() function returns a list where the string has been split at each match:

Python
1
2
3
4
5
6
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.split('\s', China) # Split at each white-space character:
# ['The', 'Chinese', 'Communist', 'Party', 'will', 'disintegrate', 'in', '2020.']

You can control the number of occurrences by specifying the maxsplit parameter:

Python
1
2
3
4
5
6
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.split('\s', China, 1) # Split the string only at the first occurrence:
# ['The', 'Chinese Communist Party will disintegrate in 2020.']

The sub() Function

The sub() function replaces the matches with the text of your choice:

Python
1
2
3
4
5
6
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.sub('\s', 'X', China) # Replace all white-space characters with the character 'X'
# 'TheXChineseXCommunistXPartyXwillXdisintegrateXinX2020.'

You can control the number of replacements by specifying the count parameter:

Python
1
2
3
4
5
6
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.sub('\s', 'X', China, 2) # Replace the first two white-space characters with the character 'X'
# 'TheXChineseXCommunist Party will disintegrate in 2020.'

Backreference

A backreference in regular expressions is a way to match the same text that was previously matched by a capturing group. In regular expressions, capturing groups are defined using parentheses, and are used to extract a specific part of the input string that matches the pattern. A backreference is defined using the syntax “\n”, where “n” is the number of the capturing group that it references. For example, if the regular expression pattern is “(\w+)\s\1”, and the input string is “hello world hello”, the match will be “hello hello”. The first capturing group “(\w+)” matches the first occurrence of “hello”, and the backreference “\1” matches the same text again.

Example of adding : to every word
1
2
3
4
5
s = """OverallQual      0.573994
YearBuilt 0.367914
GarageCars 0.355167"""

print(s)
1
2
3
OverallQual      0.573994
YearBuilt 0.367914
GarageCars 0.355167
1
2
3
s1 = re.sub(r"^", "- ", s, flags=re.MULTILINE)

print(s1)
1
2
3
- OverallQual      0.573994
- YearBuilt 0.367914
- GarageCars 0.355167
1
2
3
s2 = re.sub(r"\b([a-zA-Z]+)\b", r"\1:", s1, re.MULTILINE)

print(s2)
1
2
3
- OverallQual:      0.573994
- YearBuilt: 0.367914
- GarageCars: 0.355167

How to do backreference in VSCode? Using $& indead of \1.


Match Object

A Match Object is an object containing information about the search and the result.

Note: If there is no match, the value None will be returned, instead of the Match Object.

Do a search that will return a Match Object:

Python
1
2
3
4
5
6
7
8
9
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.search('Chi', China)
# <re.Match object; span=(4, 7), match='Chi'>

print(re.search('chi', China))
# None

The Match object has properties and methods used to retrieve information about the search, and the result:

  • .span() returns a tuple containing the start-, and end positions of the match.
  • .string returns the string passed into the function
  • .group() returns the part of the string where there was a match

Print the position (start- and end-position) of the first match occurrence.

The regular expression looks for any words that starts with an upper case “P”:

Python
1
2
3
4
5
6
7
8
9
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.search(r'\bP\w+', China) # Search for an upper case "P" character in the beginning of a word, and print its position:
# <re.Match object; span=(22, 27), match='Party'>

re.search(r'\bP\w+', China).span()
# (22, 27)

Print the string passed into the function:

Python
1
2
3
4
5
6
7
8
9
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.search(r'\bP\w+', China)
# <re.Match object; span=(22, 27), match='Party'>

re.search(r'\bP\w+', China).string # The string property returns the search string:
# 'The Chinese Communist Party will disintegrate in 2020.'

Print the part of the string where there was a match.

The regular expression looks for any words that starts with an upper case “P”:

Python
1
2
3
4
5
6
7
8
9
10
11
12
import re

China = "The Chinese Communist Party will disintegrate in 2020."

re.search(r'\bP\w+', China)
# <re.Match object; span=(22, 27), match='Party'>

re.search(r'\bP\w+', China).group() # Search for an upper case "P" character in the beginning of a word, and print the word:
# 'Party'

re.search(r'\bW\w+', China).group() # Search for an upper case "W" character in the beginning of a word, and print the word:
# AttributeError: 'NoneType' object has no attribute 'group'

Note: If there is no match, the value None will be returned, instead of the Match Object.


The match() function

match(pattern, string, flags=0)
Try to apply the pattern at the start of the string, returning
a Match object, or None if no match was found.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import re

m = re.search(r"\d{5}", "360 Huntington Ave, Boston MA 02115")
if m:
print(m.group(0))
# 02115

m = re.match(r"\d{5}", "360 Huntington Ave, Boston MA 02115")
if m:
print(m.group(0))
#

m = re.match(r"\d{5}", "02115 Huntington Ave, Boston MA")
if m:
print(m.group(0))
# 02115

m = re.match(r"\d{5}", "02115 Huntington Ave, Boston MA 02115")
if m:
print(m.group())
# 02115

m = re.findall(r"\d{5}", "02115 Huntington Ave, Boston MA 02115")
if m:
print(m)
# ['02115', '02115']

for m in re.finditer(r"\d{5}", "02115 Huntington Ave, Boston MA 02115"):
if m:
print(m.group(0))
# 02115
# 02115

The finditer() function

finditer(pattern, string, flags=0)
Return an iterator over all non-overlapping matches in the
string. For each match, the iterator returns a Match object.

Empty matches are included in the result.

The complie() function

2 way to use it.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
zipcode = re.compile(r'\d{5}')
for m in re.finditer(zipcode, "02115 Huntington Ave, Boston MA 02115"):
if m:
print(m.group(0))
# 02115
# 02115

result = zipcode.search("02115 Huntington Ave, Boston MA 02115")
result.group(0)
# 02115

for result in zipcode.finditer("02115 Huntington Ave, Boston MA 02115"):
if result:
print(result.group(0))
# 02115
# 02115

flags

  • re.I re.IGNORECASE: ignore the uppercase and lowercase letter
  • re.M re.MULTILINE: let ^ match the start of every row.
  • re.S re.DOTALL: let . match all of the characters. By defult, . will ignore /n.

Method

Attribute of match object

  • .string: reutrn the orginal string

  • .re: pattern object

  • .pos: start position of the string

  • .endpos: end position of the string

  • .group(0): return the matched string

  • .start(): the first matched position

  • .end(): the end matched position

  • .span(): return (.start(), .end())

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import re

zipcode = re.compile(r'\d{5}')
result = zipcode.search("02115 Huntington Ave, Boston MA 02115")

result.string
# '02115 Huntington Ave, Boston MA 02115'

result.re
# re.compile(r'\d{5}', re.UNICODE)

result.pos
# 0

result.endpos
# 37

result.group()
# '02115'

result.start()
# 0

result.end()
# 5

result.span()
# (0, 5)

Greedy matching vs. Optimal matching

Python
1
2
3
4
5
6
import re

m = re.search("^P.*", "Python")
if m:
print(m.group(0))
# Python

Why Python returns “Python” instead of “P”, “Py”, “Pyt”, “Pyth”, or “Pytho”?
By defult, Python returns the longest result which we called Greedy matching.

Try to output the shortest result:

Python
1
2
3
4
m = re.search("^P.*?", "Python")
if m:
print(m.group(0))
# P
  • *?: 0 or more occurances, optimal matching
  • +?: 1 or more occurances, optimal matching
  • ??: 0 or one occurance, optimal matching
  • {m, n}?: from m to n occurances, optimal matching

Classic RegEX

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
^[A-Za-z]+$ # Returns a match where the string contains any word characters (characters from a to Z)

^[A-Za-z0-9]+$ # Returns a match where the string contains any word characters (characters from a to Z, digits from 0-9)

^-?\d+$ # Returns a mathch of any integers

^[0-9]*[1-9][0-9]*$ # positive integer

[0-9]\d{5} # zip code

[\u4e00-\u9fa5] # Chinese in UTF-8

\d{3}-\d{8}|\d{4}-\d{7} # China mainland phone number

-?\d+\.?\d* # negative or possitive numeric

\d+\.?\d* # possitive numeric

(([1-99]?\d|1\d{2}|2[0-4]\d|25[0-5]).){3}([1-99]?\d|1\d{2}|2[0-4]\d|25[0-5]) # ip address

Python PIP

What is PIP?

PIP is a package manager for Python packages, or modules if you like.

Note: If you have Python version 3.4 or later, PIP is included by default.


What is a Package?

A package contains all the files you need for a module.

Modules are Python code libraries you can include in your project.


Check if PIP is Installed

Navigate your command line to the location of Python’s script directory, and type the following:

Check PIP version:

1
pip --version


Install PIP

If you do not have PIP installed, you can download and install it from this page: https://pypi.org/project/pip/


Download a Package

Downloading a package is very easy.

Open the command line interface and tell PIP to download the package you want.

Navigate your command line to the location of Python’s script directory, and type the following:

Download a package named “camelcase”:

1
pip install camelcase

Now you have downloaded and installed your first package!


Using a Package

Once the package is installed, it is ready to use.

Import camelcase package into your project then use it.

Python
1
2
3
4
5
6
import camelcase

c = camelcase.CamelCase() # #This method capitalizes the first letter of each word.
txt = "hello world"
print(c.hump(txt))
# Hello World

Find Packages

Find more packages at https://pypi.org/.


Remove a Package

Use the uninstall command to remove a package:

Uninstall the package named “camelcase” and press y:

1
pip uninstall camelcase


List Packages

Use the list command to list all the packages installed on your system:

List installed packages:

1
pip list


Python Try Except

Errors and Exceptions
Built-in Exceptions

The try block lets you test a block of code for errors.

The except block lets you handle the error.

The finally block lets you execute code, regardless of the result of the try- and except blocks.


Exception Handling

When an error occurs, or exception as we call it, Python will normally stop and generate an error message.

These exceptions can be handled using the try statement:

The try block will generate an exception, because x is not defined:

Python
1
2
3
4
5
try:
print(x)
except:
print("An exception occurred")
# An exception occurred

Since the try block raises an error, the except block will be executed.

Without the try block, the program will crash and raise an error:

This statement will raise an error, because x is not defined:

Python
1
2
print(x)
# NameError: name 'x' is not defined

Accessing Error Messages

Python
1
2
3
4
5
try:
# some code
except Exception as e:
# some code
print("Exception occurred: {}".format(e))

For example:

Python
1
2
3
4
5
try:
# some code
except ZeroDivisionError as e:
# some code
print("ZeroDivisionError occurred: {}".format(e))

Many Exceptions

You can define as many exception blocks as you want, e.g. if you want to execute a special block of code for a special kind of error:

Print one message if the try block raises a NameError and another for other errors:

Python
1
2
3
4
5
6
7
try:
print(x)
except NameError:
print("Variable x is not defined")
except:
print("Something else went wrong")
# Variable x is not defined

Else

You can use the else keyword to define a block of code to be executed if no errors were raised:

Python
1
2
3
4
5
6
7
8
try:
print("Hello")
except:
print("Something went wrong")
else:
print("Nothing went wrong")
# Hello
# Nothing went wrong

Finally

The finally block, if specified, will be executed regardless if the try block raises an error or not.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
try:
print(x)
except:
print("Something went wrong")
else:
print("Nothing went wrong")
finally:
print("The 'try except' is finished")
# Something went wrong
# The 'try except' is finished

try:
print("Hello")
except:
print("Something went wrong")
else:
print("Nothing went wrong")
finally:
print("The 'try except' is finished")
# Hello
# Nothing went wrong
# The 'try except' is finished

This can be useful to close objects and clean up resources:

Python
1
2
3
4
5
6
7
8
9
try:
f = open("demofile.txt")
f.write("Lorum Ipsum")
except:
print("Something went wrong when writing to the file")
finally:
f.close()
# Something went wrong when writing to the file
# NameError: name 'f' is not defined. We do not have a file named "demofile.txt", so we cannot open it. And f is never be daclared. The finally block cause an error.

The program can continue, without leaving the file object open.


Raise an exception

As a Python developer you can choose to throw an exception if a condition occurs.

To throw (or raise) an exception, use the raise keyword.

Raise an error and stop the program if x is lower than 0:

Python
1
2
3
4
5
x = -1

if x < 0:
raise Exception("Sorry, no numbers below zero")
# Exception: Sorry, no numbers below zero

The raise keyword is used to raise an exception.

You can define what kind of error to raise, and the text to print to the user.

Python
1
2
3
4
5
x = "hello"

if not type(x) is int:
raise TypeError("Only integers are allowed")
# TypeError: Only integers are allowed

Infinte program

An infinite WRONG program:

Notice the 14th line.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def hexo(x):
if x == 1:
print(1)
elif x == 2:
print(2)
elif x == 3:
print(3)

while True:
try:
x = int(input("Please enter a number from the options:"))
if x in [1, 2, 3]:
hexo(x)
# break
else:
print("This is an inviald number!")
except ValueError:
print("This is not a number!")

The RIGHT code

Notice the 14th line.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def hexo(x):
if x == 1:
print(1)
elif x == 2:
print(2)
elif x == 3:
print(3)

while True:
try:
x = int(input("Please enter a number from the options:"))
if x in [1, 2, 3]:
hexo(x)
break # The import stop
else:
print("This is an inviald number!")
except ValueError:
print("This is not a number!")

The full version (must contain exit option!)

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import os

# Detect User Input.
def detect_input():
while True:
try:
print("1. Runing the offline test. \n2. Release new version to Github. \n3. Push to Github, branch hexo. \n4. Exit the program.")
x = int(input("Please enter a number from the options: "))
if x in [1, 2, 3]:
hexo(x)
break
elif x == 4:
print("\nExit successfully!\n")
break
else:
print("\nThis is an inviald number!\n")
except ValueError:
print("\nThis is not a number!\n")

# Main function.
def hexo(x):
if x == 1:
os.system("hexo clean && hexo g && hexo s --debug")
elif x == 2:
os.system("hexo clean && hexo g && hexo d")
elif x == 3:
os.system("git checkout hexo && git add . && git commit -m 'Backup'; git push origin hexo")

# Detect if the program in the Hexo working directory.
def detect_wd():
if 'github.io' in os.getcwd():
detect_input()
else:
print('Please put this program in the Hexo WORKING DIRECTORY!')

# Execute the program.
detect_wd()

Python User Input

https://www.w3schools.com/python/ref_string_format.asp

User Input

Python allows for user input.

That means we are able to ask the user for input.

The method is a bit different in Python 3.6 than Python 2.7.

Python 3.x uses the input() method.

Python 2.7 uses the raw_input() method.

The following example asks for the username, and when you entered the username, it gets printed on the screen:

Python 3.x

Python
1
2
3
username = input("Enter username:")
print("Username is: " + username)
# Username is: Zacks

Note: Python stops executing when it comes to the input() function, and continues when the user has given some input.


Python Keywords

Keyword Description
andA logical operator
asTo create an alias
assertFor debugging
breakTo break out of a loop
classTo define a class
continueTo continue to the next iteration of a loop
defTo define a function
delTo delete an object
elifUsed in conditional statements, same as else if
elseUsed in conditional statements
exceptUsed with exceptions, what to do when an exception occurs
FalseBoolean value, result of comparison operations
finallyUsed with exceptions, a block of code that will be executed no matter if there is an exception or not
forTo create a for loop
fromTo import specific parts of a module
globalTo declare a global variable
ifTo make a conditional statement
importTo import a module
inTo check if a value is present in a list, tuple, etc.
isTo test if two variables are equal
lambdaTo create an anonymous function
NoneRepresents a null value
nonlocalTo declare a non-local variable
notA logical operator
orA logical operator
passA null statement, a statement that will do nothing
raiseTo raise an exception
returnTo exit a function and return a value
TrueBoolean value, result of comparison operations
tryTo make a try...except statement
whileTo create a while loop
withUsed to simplify exception handling
yieldTo end a function, returns a generator

assert

Python assert Keyword

Definition and Usage

The assert keyword is used when debugging code.

The assert keyword lets you test if a condition in your code returns True, if not, the program will raise an AssertionError.

You can write a message to be written if the code returns False, check the examples below.

Python
1
2
3
4
5
6
7
8
x = "hello"

#if condition returns True, then nothing happens:
assert x == "hello"

#if condition returns False, AssertionError is raised:
assert x == "goodbye"
# AssertionError:
Python
1
2
3
4
5
x = "hello"

#if condition returns False, AssertionError is raised:
assert x == "goodbye", "x should be 'hello'"
# AssertionError: x should be 'hello'

Python Built in Functions

Python Built in Functions


Function Description
abs()Returns the absolute value of a number
all()Returns True if all items in an iterable object are true
any()Returns True if any item in an iterable object is true
ascii()Returns a readable version of an object. Replaces none-ascii characters with escape character
bin()Returns the binary version of a number
bool()Returns the boolean value of the specified object
bytearray()Returns an array of bytes
bytes()Returns a bytes object
callable()Returns True if the specified object is callable, otherwise False
chr()Returns a character from the specified Unicode code.
classmethod()Converts a method into a class method
compile()Returns the specified source as an object, ready to be executed
complex()Returns a complex number
delattr()Deletes the specified attribute (property or method) from the specified object
dict()Returns a dictionary (Array)
dir()Returns a list of the specified object's properties and methods
divmod()Returns the quotient and the remainder when argument1 is divided by argument2
enumerate()Takes a collection (e.g. a tuple) and returns it as an enumerate object
eval()Evaluates and executes an expression
exec()Executes the specified code (or object)
filter()Use a filter function to exclude items in an iterable object
float()Returns a floating point number
format()Formats a specified value
frozenset()Returns a frozenset object
getattr()Returns the value of the specified attribute (property or method)
globals()Returns the current global symbol table as a dictionary
hasattr()Returns True if the specified object has the specified attribute (property/method)
hash()Returns the hash value of a specified object
help()Executes the built-in help system
hex()Converts a number into a hexadecimal value
id()Returns the id of an object
input()Allowing user input
int()Returns an integer number
isinstance()Returns True if a specified object is an instance of a specified object
issubclass()Returns True if a specified class is a subclass of a specified object
iter()Returns an iterator object
len()Returns the length of an object
list()Returns a list
locals()Returns an updated dictionary of the current local symbol table
map()Returns the specified iterator with the specified function applied to each item
max()Returns the largest item in an iterable
memoryview()Returns a memory view object
min()Returns the smallest item in an iterable
next()Returns the next item in an iterable
object()Returns a new object
oct()Converts a number into an octal
open()Opens a file and returns a file object
ord()Convert an integer representing the Unicode of the specified character
pow()Returns the value of x to the power of y
print()Prints to the standard output device
property()Gets, sets, deletes a property
range()Returns a sequence of numbers, starting from 0 and increments by 1 (by default)
repr()Returns a readable version of an object
reversed()Returns a reversed iterator
round()Rounds a numbers
set()Returns a new set object
setattr()Sets an attribute (property/method) of an object
slice()Returns a slice object
sorted()Returns a sorted list
@staticmethod()Converts a method into a static method
str()Returns a string object
sum()Sums the items of an iterator
super()Returns an object that represents the parent class
tuple()Returns a tuple
type()Returns the type of an object
vars()Returns the __dict__ property of an object
zip()Returns an iterator, from two or more iterators

enumerate()

Definition and Usage
The enumerate() function takes a collection (e.g. a tuple) and returns it as an enumerate object.

The enumerate() function adds a counter as the key of the enumerate object.

Syntax

Python
1
enumerate(iterable, start)

Parameter Values

Parameter Description
iterable An iterable object
start A Number. Defining the start number of the enumerate object. Default 0

Example: Save each index and element from a enumerate object in a new list

Python
1
2
3
4
5
6
7
letters = ['a', 'b', 'c', 'd']
enumerate(l)
# <enumerate at 0x7fc4d81f75c0>

# Use list() to restruct enumerate object
list(enumerate(letters))
# [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]

Example: Get each index and element from a enumerate object

Python
1
2
3
4
5
6
7
8
9
10
11
letters = ['a', 'b', 'c', 'd']

for i, element in enumerate(letters):
result = 'index: {0}, element: {1}'
print(result.format(i, element))
'''
index: 0, element: a
index: 1, element: b
index: 2, element: c
index: 3, element: d
'''

Example: Extract index and element from a enumerate object and calculate them

Python
1
2
3
l = [0, 1, 2, 3]
[element ** i for i, element in enumerate(l)]
# [1, 1, 4, 27]

Example: Specify a number as start index

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
letters = ['a', 'b', 'c', 'd']

for i, element in enumerate(letters, 1):
result = 'index: {0}, element: {1}'
print(result.format(i, element))
'''
index: 1, element: a
index: 2, element: b
index: 3, element: c
index: 4, element: d
'''

l = [0, 1, 2, 3]
[element ** i for i, element in enumerate(l, 1)]
# [0, 1, 8, 81]

Example: Use enumerate to modify the cast list so that each element contains the name followed by the character’s corresponding height. For example, the first element of cast should change from “Barney Stinson” to “Barney Stinson 72”.

Python
1
2
3
4
5
6
7
8
cast = ["Barney Stinson", "Robin Scherbatsky", "Ted Mosby", "Lily Aldrin", "Marshall Eriksen"]
heights = [72, 68, 72, 66, 76]

# write your for loop here
for i, name in enumerate(cast):
cast[i] = '{} {}'.format(cast[i], heights[i])

print(cast)

map()

Higher order functions fit into a domain of programming known as “functional” or “functional form” programming, centered around this idea of passing and returning functions as parameters and arguments. In class, you learned the command map that is a fundamental example of higher order functions.

Let’s take a closer look at how map works. At its core, map applies a function to all items in an input list. It takes in a function as the first parameter and a series of inputs as the second parameter.

Python
1
map(function_to_apply, list_of_inputs)
Python
1
2
help(map)
# Make an iterator that computes the function using arguments from each of the iterables. Stops when the shortest iterable is exhausted.

A potentially easier way to think about map is to draw an equivalent with a list comprehension! Given the func (function to apply) and inputs (list of inputs), a map is similar to this:

Python
1
[func(x) for x in inputs]

Keep in mind that the map function actually returns a map object, not a list. We need to convert this object to a list by passing it into the list() function.

Let’s do a Python Tutor example to understand how map works.

Open Python Tutor in a new tab.

This code should already be there:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
INCR = 2
def inc(x):
return x + INCR

def mymap(fun, seq):
return [fun(x) for x in seq]

result = mymap(inc, [5, 6, 7])
print(result)
# [7, 8, 9]

# It is equal to
# [i+2 for i in [5, 6, 7]]

So what’s happening here? In the first 3 lines, we’re defining a function inc which increments an input x by a certain amount, INCR.

Notice that INCR is defined once in the Global frame. This is a nice review of how Python resolves references when there are both local and global variables. When the inc method executes, python needs to find the value INCR. Since the INCR variable isn’t declared locally, within the inc function, Python will look at the parent frame, the frame in which inc was declared, for the value of INCR. In this case, since the inc function was declared in the Global frame, the global INC variable value will be used.

The second function, mymap, is an example of how map works in the form of a list comprehension! Notice that mymap takes in a function as its first argument and a sequence as its second. Just like map, this list comprehension runs each element of seq through the fun method.

As you run through the program in Python Tutor, notice how the list comprehension in mymap will repeatedly call the inc function. The functional anatomy of how map works is exactly encapsulated by the mymap function.

We defined mymap(fun, seq) function and inc(X). But how to use map function to directly apply all of the elements to inc(x)?

Python
1
2
3
4
5
6
INCR = 2
def inc(x):
return x + INCR

result = list(map(inc, [5, 6, 7]))
print(result)

Also, you can use built-in function and apply all elements to the function.

For example, convert all int in a list to str.

Python
1
2
3
list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
['1', '2', '3', '4', '5', '6', '7', '8', '9']
# ['1', '2', '3', '4', '5', '6', '7', '8', '9']

filter()

The filter keyword is similar in nature to map with a very important distinction. In map, the function we pass in is being applied to every item in our sequence. In filter, the function we pass in filters the elements, only leaving the elements for which the function returns true. For example, if I wanted to remove all negative numbers from a list, I could use the filter function to identify values that are greater than or equal to 0, and filter out the rest.

Python
1
2
help(filter)
# Return an iterator yielding those items of iterable for which function(item) is true. If function is None, return the items that are true.
Python
1
2
3
4
5
6
7
8
9
10
def isPositive(number):
return number >= 0

numbers = [-1, 1, -2, 2, -3, 3, -4, 4]
positive_nums = list(filter(isPositive, numbers))
positive_nums
# [1, 2, 3, 4]

# It is equal to
# list(filter(lambda number: number >= 0, numbers))

You can also define a filter to grab the elements that satisfy more complex conditions:

Python
1
2
3
4
5
6
def isGreaterThan(numbers, condition):
return list(filter(lambda number: number > condition, numbers))

numbers = [-1, 1, -2, 2, -3, 3, -4, 4]
isGreaterThan(numbers, 2)
[3, 4]

reduce()

Apply a function of two arguments cumulatively to the items of a sequence
or iterable, from left to right, so as to reduce the iterable to a single
value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5). If initial is present, it is placed before the items
of the iterable in the calculation, and serves as a default when the
iterable is empty.

Python
1
reduce(function, iterable[, initial]) -> value
Python
1
2
3
4
from functools import reduce

reduce(lambda x, y: x + y, range(1, 6)) == ((((1+2)+3)+4)+5) == sum(range(1, 6))
# 15

Let’s say I wanted to calculate the product of the square roots of a list of numbers. The non-reduce version of this code would look something along the lines of this:

Python
1
2
3
4
5
6
product = 1
numbers = [4, 9, 16, 25, 36]

for num in numbers:
product = product * num**.5
# 720.0

Here’s the reduce version

Python
1
2
3
4
5
6
from functools import reduce

initial = 1
numbers = [4, 9, 16, 25, 36]
reduce(lambda x, y: x * y ** .5, numbers, initial)
# 720.0

initial=1 is required here, becuase we are calculating $\sqrt{4} \times \sqrt{9} \times \sqrt{16} \times \sqrt{25} \times \sqrt{36} = 720$.
If there is no initial=1, we are in actual calculating $4 \times \sqrt{9} \times \sqrt{16} \times \sqrt{25} \times \sqrt{36} = 1440$

Therefore, the above version is as same as the no-initial version shown below:

Python
1
2
3
4
5
from functools import reduce

numbers = [1, 4, 9, 16, 25, 36]
reduce(lambda x, y: x * y ** .5, numbers)
# 720.0

Noitce we don’t have initial but have 1 as the 1st element in the list numbers.
So the process of calculation is $1 \times \sqrt{4} \times \sqrt{9} \times \sqrt{16} \times \sqrt{25} \times \sqrt{36} = 720$.


Combine reduce and map

For example, convert str to int

Python
1
2
3
4
5
6
7
8
9
10
11
12
from functools import reduce

DIGITS = {'1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}

def char2num(d):
return DIGITS[d]

def str2int(d):
return reduce(lambda x, y: x * 10 + y, map(char2num, d))

str2int(DIGITS)
# 123456789

map(char2num, s) first get all digit from DIGITS, like [1, 2, 3, 4, 5, 6, 7, 8, 9].
The regular method without reduce looks like this:

Python
1
2
3
4
5
6
7
8
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def char2int(l):
if len(l) == 1:
return l[0]
return l[0] + char2int(l[1:]) * 10

char2int(l[::-1])
# 123456789

OR:

Python
1
2
3
4
5
6
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
result = 0
for i in l:
result = result * 10 + i
result
# 123456789

zip()

Definition and Usage
The zip() function returns a zip object, which is an iterator of tuples where the first item in each passed iterator is paired together, and then the second item in each passed iterator are paired together etc.

If the passed iterators have different lengths, the iterator with the least items decides the length of the new iterator.

Syntax

Python
1
zip(iterator1, iterator2, iterator3 ...)

Parameter Values

Parameter Description
iterator1, iterator2, iterator3 ... Iterator objects that will be joined together

Examples

Python
1
2
3
4
5
6
7
8
a = ("John", "Charles", "Mike")
b = ("Jenny", "Christy", "Monica")

x = zip(a, b)
type(x)
# zip
tuple(x)
# (('John', 'Jenny'), ('Charles', 'Christy'), ('Mike', 'Monica'))
Python
1
2
3
4
5
6
a = ("John", "Charles", "Mike")
b = ("Jenny", "Christy", "Monica", "Vicky")

x = zip(a, b)
tuple(x)
# # (('John', 'Jenny'), ('Charles', 'Christy'), ('Mike', 'Monica'))
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
l_1 = [0, 1, 2, 3]
l_2 = [5, 6, 7, 8]

list(zip(l_1, l_2))
# [(0, 5), (1, 6), (2, 7), (3, 8)]

for i, j in zip(l_1, l_2):
print(i * j)
'''
0
6
14
24
'''

zip() source algorithm:

Python
1
2
3
4
5
6
7
8
9
10
list_1 = [0, 1]
list_2 = ['a', 'b']

list(map(lambda a, b: (a, b), list_1, list_2))
# [(0, 'a'), (1, 'b')]
list(zip(list_1, list_2))
# [(0, 'a'), (1, 'b')]

list(map(lambda a, b: (a, b), list_1, list_2)) == list(zip(list_1, list_2))
# True

Python
1
2
3
4
5
6
7
8
9
10
11
12
x_coord = [23, 53, 2, -12, 95, 103, 14, -5]
y_coord = [677, 233, 405, 433, 905, 376, 432, 445]
z_coord = [4, 16, -6, -42, 3, -6, 23, -1]
labels = ["F", "J", "A", "Q", "Y", "B", "W", "X"]

points = []
# write your for loop here
for point in zip(labels, x_coord, y_coord, z_coord):
points.append('{}: {}, {}, {}'.format(*point))

for point in points:
print(point)
1
2
3
4
5
6
7
8
F: 23, 677, 4
J: 53, 233, 16
A: 2, 405, -6
Q: -12, 433, -42
Y: 95, 905, 3
B: 103, 376, -6
W: 14, 432, 23
X: -5, 445, -1

Unzip

Python
1
2
3
4
5
6
7
cast = (("Barney", 72), ("Robin", 68), ("Ted", 72), ("Lily", 66), ("Marshall", 76))

# define names and heights here
names, heights = zip(*cast)

print(names)
print(heights)
1
2
('Barney', 'Robin', 'Ted', 'Lily', 'Marshall')
(72, 68, 72, 66, 76)

References

W3Schools
The Python Tutorial
The Python Standard Library
Role of Underscore(_) in Python

While there are many online resources about programming, not all of the them are created equal. This list of resources is in approximate order of reliability.

  1. The Python Tutorial - This section of the official documentation surveys Python’s syntax and standard library. It uses examples, and is written using less technical language than the main documentation. Make sure you’re reading the Python 3 version of the docs!
  2. The Python Language and Library References - The Language Reference and Library Reference are more technical than the tutorial, but they are the definitive sources of truth. As you become increasingly acquainted with Python you should use these resources more and more.
  3. Third-Party Library Documentation - Third-party libraries publish their documentation on their own websites, and often times at https://readthedocs.org/. You can judge the quality of a third-party library by the quality of its documentation. If the developers haven’t found time to write good docs, they probably haven’t found the time to polish their library either.
  4. The websites and blogs of prominent experts - The previous resources are primary sources, meaning that they are documentation from the same people who wrote the code being documented. Primary sources are the most reliable. Secondary sources are also extremely valuable. The difficulty with secondary sources is determining the credibility of the source. The websites of authors like Doug Hellmann and developers like Eli Bendersky are excellent. The blog of an unknown author might be excellent, or it might be rubbish.
  5. StackOverflow - This question and answer site has a good amount of traffic, so it’s likely that someone has asked (and someone has answered) a related question before! However, answers are provided by volunteers and vary in quality. Always understand solutions before putting them into your program. One line answers without any explanation are dubious. This is a good place to find out more about your question or discover alternative search terms.
  6. Bug Trackers - Sometimes you’ll encounter a problem so rare, or so new, that no one has addressed it on StackOverflow. You might find a reference to your error in a bug report on GitHub for instance. These bug reports can be helpful, but you’ll probably have to do some original engineering work to solve the problem.
  7. Random Web Forums - Sometimes your search yields references to forums that haven’t been active since 2004, or some similarly ancient time. If these are the only resources that address your problem, you should rethink how you’re approaching your solution.