Skip to content

Reading notes for Python Crash Course (2nd Edition)

Python Basics

Variable rules:

  1. Can only contain letters, digits, and underscores (unlike JS, which also allows dollar signs in variable names)
  2. Keywords cannot be used as variable names
  3. Python has no syntactic concept of constants — only naming conventions

String (Text Sequence Type)

Some Common Methods

Changing Case

  • title / capitalize
  • upper / lower
Code Example
python
name = "ada lovelace"
print(name.title())
print(name.capitalize())
print(name.upper())

f-strings (similar to JS template literals)

f-strings are only available in 3.6+. They are equivalent to the older "{0} {1}".format(f_name, l_name), where {0} represents the index of the argument to be substituted

Code Example
python
f_name = "ada"
l_name = "lovelace"
full_name = f"{f_name} {l_name}"
print("full_name:", full_name.title())
print("before 3.6: ", "{} {}".format(f_name, l_name).title())

Removing Whitespace

  • lstrip / rstrip / strip
Code Example
python
wb_word = " python "
print("rstrip:", wb_word.rstrip())
print("lstrip:", wb_word.lstrip())
Code Example
python
# 小练习:人名quotes
name = "\tRocky\n"
quotes = "Let me tell you something you already know. The world ain't all sunshine and rainbows. It's a very mean and nasty place. And I don't care how tough you are, it will beat you to knees and keep you there permanently if you let it! You, me, or nobody is gonna hit as hard as life. But it ain't about how hard you bit. It's about how hard you can get hit and keep moving forward. How much you can take and keep moving forward. That's how winning is done! Now if you know what you're worth, then go out and get what you're worth. But ya gotta be willing to take the hits, and not pointing fingers saying you ain't where you wanna be because of him, or her, or anybody! Cowards do that and that ain't you! You're better than that!"
print(f'{name.strip().title()} once said: "{quotes}"')

Number (Sequence Type)

Unlike JS, Python distinguishes between integers and floats. (Internally in JS, all numbers are represented as floats.)

  • Dividing any two numbers always results in a float
  • In other operations, if either operand is a float, the result is also a float

python allows underscores when writing large numbers for readability. python ignores them during parsing, so 1_0_00, 1_000, and 1000 are identical in python. (Like f-strings, only available in 3.6+)

List

Similar to JS, but supports negative indexing with -1. In addition to the standard literal declaration list = [0, 1, 2], python also provides the range function for quickly creating Number Lists, and List Comprehension for quickly declaring patterned Lists.

Some Common Methods

Basic Operations

  • append(x) insert(i, x) extend(t) s += t
  • pop() remove(x)
  • del s[i:j:k]
  • s[i:j] = t
  • sort() sorted() reverse() See the official documentation

Loops

Note that loop variables are global, so they remain accessible after the loop ends. In Python, Indent Matters!

List Comprehension

List comprehensions provide a concise way to create new Lists based on existing Lists or other iterable objects

Code Example
python
# mapList = [*map(lambda x: x ** 2, range(1, 11))]
mapList = list(map(lambda x: x**2, range(1, 11)))
resolveList = [value**2 for value in range(1, 11)]
print(mapList)
print(resolveList)

Number List

range(x, y, step) => generates an array in the range [x, y) with the given step min max sum

Code Example
python
testList = ["a", "b", "c", "d", "e"]
for s in testList:
    print(s)

for s in range(1, 6, 2):
    print(s)
print(f"s can still be used out of loop: {s}")

Tuple (Sequence Type)

Python calls values that cannot be modified immutable, and an immutable list is called a tuple. Unlike tuple in typescript, a Python tuple is more similar to the concept of a constant array in TS.

Tuples are identified by commas; parentheses just make them look neater and clearer. If you want to define a tuple with only one element, you must include a trailing comma after that element. Creating a single-element tuple is usually not meaningful, but auto-generated tuples may contain only one element.

Code Example
python
singleTuple = (200,)
testTuple = (200, 50)

print(testTuple[0])

Tuple unpacking

Tuple unpacking provides a shortcut to extract elements from a tuple, similar to array destructuring in javascript

python
tuple = (1, 2, 3)
x, y, z = tuple
print(x, y, z)

Due to the nature of Tuple, even if you don't need the preceding elements, you must use placeholders of the same length, otherwise unpacking will raise an error

python
tuple = (1, 2, 3)
# Wrong - this will assign the entire tuple
x = tuple
# Wrong - this will raise a ValueError
_, x = tuple
# Correct
_, x, _ = tuple
print(x)

Conditions

if You can use comparison operators == >= etc. Or use logical keywords and or Use in not in keywords to check whether a specific value is in a list

Code Example
python
recipes = ["mushrooms", "green peppers", "cheese"]
for m in recipes:
    if m == "green peppers":
        print("Sorry, out of green peppers right now")
    else:
        print(f"Adding {m}")
print("finished making pizza")

seqNumList = list(range(1, 10))
for i in range(len(seqNumList)):
    if i == 0:
        seqNumList[i] = "1st"
    elif i == 1:
        seqNumList[i] = "2nd"
    elif i == 2:
        seqNumList[i] = "3rd"
    else:
        seqNumList[i] = f"{i}th"
print(seqNumList)

Dict (Mapping Types)

See the official documentation

Unlike typescript, in Python 3.7, the order of elements in a dictionary matches the order in which they were defined.

  • get(key[, default]) Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
  • iter(d) Return an iterator over the keys of the dictionary. This is a shortcut for iter(d.keys()).
  • items() Return a new view of the dictionary’s items ((key, value) pairs)
  • keys() values() Iterating over a dictionary traverses all keys by default, so for name in students is equivalent to for name in students.keys()

You can use the built-in set() function to deduplicate, or directly use a pair of curly braces to create a set

python
languages = {'python', 'ruby', 'python', 'c'}
# languages {'ruby', 'python', 'c'}
Code Example
python
speed_x_increment = {"slow": 1, "medium": 2, "fast": 3}
alien_0 = {"color": "green", "points": 5, "speed": "fast"}
alien_0["x_position"] = 0
alien_0["y_position"] = 25
alien_0["x_position"] += speed_x_increment.get(alien_0["speed"], 5)
# for k in iter(alien_0):
for k, v in alien_0.items():
    print(f'alien_0["{k}"]: {alien_0[k]}')

Input and While

The input() function accepts user input and always returns a string. You can use \n for line breaks.

Compared to node.js, python is clearly much more concise

javascript
const { createInterface } = require("node:readline");
const { stdin, stdout } = require("node:process");

const rl = createInterface({
  input: stdin,
  output: stdout,
});

rl.question("Tell me something, and I will repeat it back 2 u", (answer) => {
  console.log("🚀 ~ file: test.js:7 ~ rl.question ~ answer:", answer);
  rl.close();
});
Code Example
python
message = "Tell me something, and I will repeat it back 2 u"
message += "\nEnter Q to end the program.\n"
result = ""
flag = True
while flag:
    result = input(message)
    flag = result.upper() != "Q"
    if flag:
        print(result)
Code Example
python
# list - append
unconfirmed_users = ["admin", "alice", "jack", "tom"]
confirmed_users = []
while unconfirmed_users:
    cur_user = unconfirmed_users.pop(0)
    confirmed_users.append(cur_user)
print(f"\nThe following users have been confirmed:")
for confirmed_user in confirmed_users:
    print(confirmed_user.title())

# list - remove
pets = ["dog", "cat", "dog", "goldfish", "cat", "rabbit", "cat"]
print(pets)

target = "cat"
while target in pets:
    pets.remove(target)

print(pets)
Code Example
python
responses = {}
polling = True
while polling:
    name = input("\nWhat's ur name? ")
    response = input("Which mountain would you like to climb someday? ")
    responses[name] = response

    polling = input("Would you like to let another person respond?(yes/no) ") != "no"

print("\n-- Poll Results ---")
for name, response in responses.items():
    print(f"{name.title()} would like to climb {response}")

Functions

python
def func_name(*params):
  """
  docstring
  """
  print("Hello world")

There are two ways to pass arguments:

  1. Positional arguments (based on order)
  2. Keyword arguments (based on parameter names)

Python's function calling is far more flexible than javascript. In javascript, the calling convention is determined at definition time, which often leads to issues when using multi-parameter formats like function foo(arg1, arg2){/* do something */} that are hard to extend later

Code Example
python
unprinted_designs = ["phone case", "robot pendant", "dodecahedron"]


def print_models(models):
    """打印模型"""
    finished_designs = []
    sliced_designs = models.copy()
    while sliced_designs:
        finished_designs.append(sliced_designs.pop())
    return finished_designs


def show_completed_models(models):
    """显示已完成的模型"""
    print("\nThe following models have been printed:")
    for model in models:
        print(model)


show_completed_models(print_models(unprinted_designs))

When the number of arguments is uncertain, you can use *args syntax to receive them as a Tuple (similar to javascript's ...args syntax), or use **kwargs to receive them as a Dict

Code Example
python
def make_pizza(size, *toppings):
    """概述当前披萨"""
    print(f"\nMaking a {size}-inch pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")


make_pizza(16, "mushrooms", "green peppers", "extra cheese")

# Python 甚至支持接受任意个数的参数并生成字典
def build_profile(name, age, **user_info):
    """用户信息"""
    user_info["name"] = name
    user_info["age"] = age
    return user_info
user_profile = build_profile("Jack", 22, sex="male")
print(user_profile)

import

Any file with a .py extension is inherently a module

There are multiple import syntaxes, and you can use the as keyword to specify an alias:

  1. import module_name # imports the entire module_name file into the current file
  2. from module_name import func_name as fn # imports func_name from module_name with alias fn

You can use the wildcard * to import all functions: from module_name import *

However, when using large modules written by others, you should avoid this approach because Python will overwrite functions or variables with the same name

Code Example
python
class Car:
    """一次模拟汽车的简单尝试。"""

    def __init__(self, make, model, year):
        """初始化描述汽车的属性。"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整洁的描述性信息。"""
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()

    def read_odometer(self):
        """打印里程信息"""
        print(f"This car has {self.odometer_reading} miles on it.")

    def update_odometer(self, mileage):
        """设置里程信息"""
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increase_odometer(self, miles):
        self.update_odometer(self.odometer_reading + miles)


class ElectricCar(Car):
    """电动汽车"""

    def __init__(self, *args):
        super().__init__(*args)
        self.battery_size = 75

    def describe_battery(self):
        print(f"This car has a {self.battery_size}-kWh battery")


my_tesla = ElectricCar("tesla", "model s", 2019)
print(my_tesla.battery_size)
my_tesla.describe_battery()

Python Standard Library

The Python standard library is a set of modules included with every Python installation. Now that you have a general understanding of how functions and classes work, you can start using modules written by other programmers. You can use any function or class from the standard library by simply including an import statement at the beginning of your program.

python
from random import randint

randint(1, 6)
Code Example
python
from random import randint

test_list = ["A", "B", "C", "D", "E", "F", "G", "H"]
count = 4
winning_list = []
while len(winning_list) != count:
    winning_list.append(test_list.pop(randint(0, len(test_list) - 1)))
winning_list.sort()
print(f"You will win if you get: {winning_list}")
print(test_list)

Files

  • The with keyword lets Python automatically determine when to close the file
  • open(file_name, mode) close(file_name) keywords can open/close files. However, if close is not called correctly due to code errors or other reasons, the file may become corrupted. Therefore, you can use with for automatic handling
  • file.write(content)
  • file.read()

Read/Write Modes

open-moderr+ww+aa+
Read
Write
Create
Overwrite
Pointer at start
Pointer at end

Each line in a file ends with \n, so be mindful to use strip or rstrip to remove extra newlines

python
with open("./README.md") as readme_file:
    for line in readme_file:
        print(line.rstrip())

Storing Data

json

  • json.dump()
  • json.load()

os

Sometimes when creating a file, the parent directory may not exist

python
data = {"test": 111}
data_path = "no_exist_dir/data.json"
with open(data_path, "w") as f:
    json.dump(data, f, indent=4) # FileNotFoundError: [Errno 2] No such file or directory

In this case, you can use the os module to add error-handling code

python
import os
data = {"test": 111}
data_path = "no_exist_dir/data.json"
# Create the directory if it doesn't exist
os.makedirs(os.path.dirname(no_exist_dir), exist_ok=True) # set exist_ok not to override existed dir
with open(data_path, "w") as f:
    json.dump(data, f, indent=4)

Exceptions

Exceptions are handled using try-except blocks

python
try:
  print(5/0)
except ZeroDivisionError:
  print("You can't divide by zero!")

Inside the except block, you can use the pass keyword to do nothing

Code Example
python
print("Give me two numbers, and I'll divide them.")
print("Enter 'q' to quit.")

while True:
    first_num = input("\nFirst number: ")
    if first_num == "q":
        break
    sec_num = input("\nSecond number: ")
    if sec_num == "q":
        break
    try:
        answer = int(first_num) / int(sec_num)
    except ZeroDivisionError:
        print("You can't divide by 0!")
    except ValueError:
        print("value invalid")
    else:
        print(answer)
Code Example
python
filename = "not_exist.txt"

try:
    with open(filename, encoding="utf-8") as f:
        contents = f.read()
except FileNotFoundError:
    print(f"Sorry, the file {filename} does not exist.")
Code Example
python
# 练习 10-6
def accumulator():
    """加法运算"""
    from functools import reduce

    print("Give me two numbers, and I'll divide them.")
    print("Enter 'q' to quit.")

    def trans_2_int(str):
        return int(str)

    input_str = ""
    num_list = []
    while input_str != "q":
        try:
            input_str = input(
                "\nPlease input a number to accumulate ('q' to execute): "
            )
            if input_str != "q":
                num = trans_2_int(input_str)
                num_list.append(num)
        except ValueError:
            print("Value invalid! Input should be numbers")
    result = reduce(lambda acc, val: acc + val, num_list)
    print(f"{' + '.join([*map(str, num_list)])} = {result}")

Testing

The unittest module in Python's standard library provides code testing tools

Common Assertion Methods

MethodPurpose
assertEqual(a, b)a == b
assertNotEqual(a, b)a != b
assertTrue(x)x == True
assertFalse(x)x == False
assertIn(item, list)item in list
assertNotIn(item, list)item not in list

TIP

Testing classes is similar to testing functions. The difference is that classes often have internal attributes, so test cases tend to have repetitive setup code. You can use the setUp method to preset internal data

Code Example
python
# 测试函数
# name_func.py
def get_formatted_name(first, last, middle=""):
    """生成格式化姓名"""
    if middle:
        full_name = f"{first} {middle} {last}"
    else:
        full_name = f"{first} {last}"

    return full_name.title()


# should be in test_name_func.py (not executable in Jupyter book)
# import unittest
# class NamesTestCase(unittest.TestCase):
#     def test_first_last_name(self):
#         formatted_name = get_formatted_name("janis", "joplin")
#         self.assertEqual(formatted_name, "Janis Joplin")

#     def test_first_last_middle_name(self):
#         formatted_name = get_formatted_name("wolfgang", "mozart", "amadeus")
#         self.assertEqual(formatted_name, "Wolfgang Amadeus Mozart")

# if __name__ == "__main__":
#     unittest.main()
Code Example
python
# 测试类
# survey.py
class AnonymousSurvey:
    def __init__(self, question):
        """存储一个问题,并未存储答案做准备"""
        self.question = question
        self.responses = []

    def show_question(self):
        print(self.question)

    def store_response(self, new_response):
        self.responses.append(new_response)

    def show_results(self):
        """显示收集到的所有答卷"""
        print("Survey results:")
        for response in self.responses:
            print(f"- {response}")

# should be in test_survey.py (not executable in Jupyter book)
# import unittest
# from survey import AnonymousSurvey

# class TestAnonymousSurvey(unittest.TestCase):
#     def setUp(self):
#         """创建一个调查对象和一组答案,供测试方法使用"""
#         self.question = "What language did you first learn to speak"
#         self.responses = ["English", "Spanish", "Mandarin"]
#         self.my_survey = AnonymousSurvey(self.question)

#     def test_store_single_response(self):
#         first_response = self.responses[0]
#         self.my_survey.store_response(first_response)
#         self.assertIn(first_response, self.my_survey.responses)

#     def test_store_three_response(self):
#         for response in self.responses:
#             self.my_survey.store_response(response)
#         for response in self.responses:
#             self.assertIn(response, self.my_survey.responses)

# if __name__ == "__main__":
#     unittest.main()

See other documents for practical project examples