Skip to content

Python 编程从入门到实践(第二版)读书笔记

Python 基础

变量规则:

  1. 只能包含字母数字下划线(区分 js 可以以下划线和 dollar 符作为变量名)
  2. 关键词不能作为变量名
  3. python 中没有常量的语法概念。只有约定写法

String (Text Sequence Type)

一些常用的方法

修改大小写

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

f 字符串(类比 js 模板字符串)

f 字符串仅适用于 3.6+。等效于之前的 "{0} {1}".format(f_name, l_name),其中{0}中的 0 代表需要被替换的 args_idx

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())

删除空白

  • 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)

与 js 不同,python 区分整数与浮点数。(js 内部,所有数字都是作为浮点数表示)

  • 任意两个数相除,结果总是浮点数
  • 其他运算中,其中一方为浮点数,结果也是浮点数

python 表述大数时可以用下划线分割,python 解析时会全部忽略, 1_0_001_0001000python中没有区别。(与 f 字符串一样,仅 3.6+适用)

List

与 js 基本类似,但可以用 -1 进行访问。与此同时,python 除了使用常规的字面量声明 list = [0, 1, 2] 外,还提供了 range 方法,快速声明 Number List。以及 列表推导式(List Comprehension) 快速声明有迹可循的 List

一些常用方法

基本操作

  • append(x) insert(i, x) extend(t) s += t
  • pop() remove(x)
  • del s[i:j:k]
  • s[i:j] = t
  • sort() sorted() reverse() 参考官方文档

循环

注意循环声明的变量是全局的,因此在循环结束后依然可以访问。在 Python 的世界里,Indent Matters!

列表推导式

列表推导式提供了一种简介的方式来基于已存在的 List 或者其他 可迭代对象 声明新的 List

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) => 以 step 为间隔生成范围为[xy)的数组 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 将不能修改的值称为不可变的,而不可变的列表被称为元组。与typescript中的tuple不同,Python 中的元组更类似于 ts 中的数组常量的概念

元组是由逗号标识的,圆括号只是让元组看起来更整洁、更清晰。如果你要定义只包含一个元素的元组,必须在这个元素后面加上逗号。创建只包含一个元素的元组通常没有意义,但自动生成的元组有可能只有一个元素。

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

print(testTuple[0])

Tuple unpacking

元组解构 (Tuple unpacking) 提供了一种快捷方式从元组中提取元素,与 javascript 中的数组结构类似

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

由于 元组Tuple 的特性,即使不需要使用到前置元素,也必须使用占位符进行占位相同长度,否则解构将会报错

python
tuple = (1, 2, 3)
# 错误写法,将会直接赋值
x = tuple
# 错误写法,会报 ValueError 的错误
_, x = tuple
# 正确写法
_, x, _ = tuple
print(x)

Conditions

if 可以使用 comparison operators == >= etc. 或者使用 logical keywords and or 使用 in not in keywords 检查特定值是否在列表中

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)

参考官方网站

typescript 不同,在 Python 3.7 中,字典中元素的排列顺序与定义时相同。

  • 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() 遍历字典时会默认遍历所有键,因此 for name in studentsfor name in students.keys() 是等效的

既可以使用内置方法 set() 进行去重,也可以直接使用一对花括号创建 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

input() 函数接收用户输入,可以通过 \n 总是返回字符串。

对比 node.jspython 显然要简练很多

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")

传参的方式有两种:

  1. 位置实参(基于顺序)
  2. 关键字实参 (基于形参命名)

Python 的函数调用方式比 javascript 要灵活太多。 javascript 在定义的时候就已经确定了调用方式。因此经常会出现定义的时候使用多形参的格式 function foo(arg1, arg2){/* do something */},后续扩展不便的问题

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))

当参数个数不确定的时候,可以通过 *args 的语法接收为 Tuple (类似 javascript...args 语法),也可以通过 **kwargs 要求将参数接收为一个 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

扩展名为 .py 的文件天生就是一个模块

导入语法有多种,导入时可以通过 as 关键字指定别名:

  1. import module_name # 将 module_name 文件整个导入当前文件
  2. from module_name import func_name as fn # 从 module_name 中导入 func_name 并指定别名 fn

可以通过通配符 * 导入所有函数 from module_name import *

但在使用非自己编写的大型模块时,应避免这种方法,因为 Python 会对多个名称相同的函数或变量进行覆盖操作

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 标准库

Python 标准库是一组模块,我们安装的 Python 都包含它。你现在对函数和类的工作原理已有大致的了解,可以开始使用其他程序员编写好的模块了。可以使用标准库 中的任何函数和类,只需在程序开头包含一条简单的 import 语句即可。

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)

文件

  • with 关键字可以让 Python 自动确认文件的关闭时机
  • open(file_name, mode) close(file_name) 关键字可以 打开/关闭文件。但实际 close 如果因为错误代码等原因没有正确调用或未执行,可能导致文件受损。因此可以使用 with 自动确认
  • file.write(content)
  • file.read()

读写模式

open-moderr+ww+aa+
创建
覆盖
指针在开始
指针在结尾

文件每行末尾都有 \n的存在,因此需要注意用 strip 或者 rstrip 消除多余换行符

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

存储数据

json

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

os

有时候我们在创建文件的时候可能会有父级目录不存在的情况

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

这时候可以使用 模块 os。通过额外的代码进行容错操作

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)

异常

异常是使用 try-except 代码块处理的

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

except 代码块内,可以使用 pass 关键字,让代码什么都不做

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}")

测试

Python 标准库中的模块 unittest 提供了代码测试工具

常用断言方法

方法用途
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

测试类与测试函数基本类似,不同点在于测试类时,由于类往往具有内部属性,因此在编写测试用例时往往会有重复语句,可以通过 setUp 方法,预设内部数据

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()

实践项目章节示例可以查看其他文档