Python 学习读书笔记

Python 学习读书笔记... 1

一、Python 基础入门... 2

1.1 Python 简介... 2

1.2 Python 入门(第一个程序)... 2

1.3 Python 关键字和标识符... 3

1.4 Python 语句、缩进和注释... 3

1.5 Python 变量、常量和字面量... 4

1.6 Python 数据类型... 5

1.7 Python 类型转换... 6

1.8 Python 输入、输出和导入... 7

1.9 Python 运算符... 7

1.10 Python 关键字列表... 9

二、Python 流程控制... 9

2.1 Python if...else 语句... 9

2.2 Python for 循环... 9

2.3 Python while 循环... 9

2.4 Python break 和 continue. 9

2.5 Python pass 语句... 9

三、Python 函数... 9

3.1 Python 函数定义与调用... 9

3.2 Python 函数参数类型... 10

3.3 Python 递归 (Recursion) 11

3.4 Python 匿名函数 (Lambda) 13

3.5 Python 全局、局部和非局部变量... 14

3.6 Python Global 关键字... 15

3.7 Python 模块... 16

3.8 Python 包(Package)... 17

3.9 Python 自定义函数... 18

四、Python 数据类型... 19

4.1 Python 数字 (Number) 19

4.2 Python 列表(List)... 20

4.3 Python 元组(Tuple)... 21

4.4 Python 字符串(String)... 22

4.5 Python 集合(Set)... 24

4.6 Python 字典(Dictionary)... 25

4.7 Python 集合方法... 27

五、Python 文件操作... 28

5.1 Python 文件 I/O.. 28

5.2 Python 目录和文件管理... 30

5.3 Python 错误和内置异常... 32

5.4 Python 异常处理... 34

5.5 Python 自定义异常... 37

六、Python 对象和类... 38

6.1 Python 面向对象编程... 38

6.2 Python 类和对象... 40

6.3 Python 继承... 42

6.4 Python 多重继承... 44

6.5 Python 运算符重载... 46

七、Python 日期和时间... 49

7.1 Python 日期时间 (datetime) 49

7.2 Python strftime() 51

7.3 Python strptime() 52

7.4 Python 当前日期和时间... 54

7.5 Python 获取当前时间... 56

7.6 Python 时间戳 (timestamp) 57

7.7 Python time 模块... 59

7.8 Python sleep() 61

八、Python 高级知识... 62

8.1 Python 命名空间和作用域... 62

8.2 Python 迭代器... 64

8.3 Python 生成器... 66

8.4 Python 闭包... 69

8.5 Python 装饰器... 71

8.6 Python @property. 75

8.7 Python 正则表达式 (RegEx) 78

8.8 Python 随机模块 (Random) 81

8.9 Python 数学模块 (Math) 83

一、Python 基础入门

1.1 Python 简介

核心内容:Python 是一种解释型、面向对象、动态类型的高级编程语言,具有简洁易读的语法(如使用缩进代替大括号),广泛应用于 Web 开发、数据分析、人工智能、自动化脚本等领域。其优势包括跨平台(Windows/macOS/Linux)、丰富的标准库和第三方库(如 NumPy、Django)、低学习门槛。

1.2 Python 入门(第一个程序)

核心内容:Python 环境搭建完成后,第一个经典程序是 "Hello World",有两种运行方式:

  1. 交互式环境(Python Shell):直接输入print("Hello World"),回车即执行;
  2. 脚本文件:创建.py文件(如hello.py),写入代码后通过python hello.py命令运行。

示例代码

# 第一个Python程序

print("Hello World")  # 输出:Hello World

print("Python学习之路")  # 支持中文,无需额外配置编码(Python 3默认UTF-8)

1.3 Python 关键字和标识符

核心内容

  1. 关键字:Python 内置的具有特殊含义的单词,不可作为变量名 / 函数名,如ifforclassdef等(共 35 个,可通过import keyword; print(keyword.kwlist)查看)。
  2. 标识符:用户自定义的变量名、函数名等,规则为:
    1. 由字母(a-z/A-Z)、数字(0-9)、下划线(_)组成;
    2. 不能以数字开头;
    3. 区分大小写(如nameName是两个不同标识符);
    4. 避免使用关键字和内置函数名(如printlen)。

难点赘述:标识符的 "大小写区分" 和 "避免冲突" 是新手易踩坑点。

  1. 场景模拟:若定义print = "我的打印变量",后续调用print("Hello")会报错(因为print已被覆盖为字符串,不再是函数)。
  2. 规范建议:变量名用 "蛇形命名法"(如user_name),函数名同变量名,类名用 "驼峰命名法"(如UserName)。

1.4 Python 语句、缩进和注释

核心内容

  1. 语句:Python 中每行代码默认是一条语句,多行语句可通过反斜杠(\)连接(如a = 1 + 2 + \ 3)。
  2. 缩进:Python 用缩进表示代码块(代替其他语言的{}),常用 4 个空格或 1 个 Tab(不可混用),缩进不一致会报IndentationError
  3. 注释:用于解释代码,不参与执行,分为单行注释(#开头)和多行注释('''"""包裹)。

难点赘述:缩进的语法强制性是新手高频错误点。

  1. 错误示例:
if 3 > 2:

print("3大于2")  # 错误:if代码块未缩进
  1. 正确示例:
if 3 > 2:

    print("3大于2")  # 正确:缩进4个空格,属于if代码块

    print("缩进一致才不会报错")

print("这行不属于if代码块,无论条件是否成立都会执行")
  1. 注释的误区:多行注释不能嵌套(如''' 外层注释 '''' 内层注释 '''会报错),需用不同符号区分(如外层''',内层#)。

1.5 Python 变量、常量和字面量

核心内容

  1. 变量:用于存储数据的容器,无需声明类型,赋值即定义(如age = 20name = "Alice"),值可修改(如age = age + 1)。
  2. 常量:理论上不可修改的值,Python 无严格常量语法,约定用全大写字母表示(如PI = 3.14159,但仍可修改,需靠开发者自觉)。
  3. 字面量:直接写在代码中的固定值,如整数(10)、浮点数(3.14)、字符串("Python")、布尔值(True/False)、None(空值)。

难点赘述:Python 变量的 "动态类型" 和 "引用传递" 特性。

  1. 动态类型:变量类型随赋值变化,示例:
x = 10  # x是整数类型

x = "Python"  # x变为字符串类型,无需声明
  1. 引用传递(以列表为例):变量存储的是数据的 "引用"(地址),而非数据本身,修改可变对象(如列表)会影响所有引用它的变量:
a = [1, 2, 3]

b = a  # b和a指向同一个列表(引用相同)

b.append(4)

print(a)  # 输出:[1,2,3,4](a也被修改)

# 若要避免影响,需创建新对象(浅拷贝)

c = a.copy()

c.append(5)

print(a)  # 输出:[1,2,3,4](a不受影响)

1.6 Python 数据类型

核心内容:Python 数据类型分 "基本类型" 和 "复合类型":

类型分类

具体类型

说明

示例

基本类型

整数(int)

无大小限制的整数

10-51000000

浮点数(float)

带小数点的数(精度有限)

3.14-0.5

布尔值(bool)

True(1)或False(0)

3 > 2结果为True

字符串(str)

字符序列,用""''包裹

"Hello"'Python'

复合类型

列表(list)

有序、可变的元素集合

[1, "a", True]

元组(tuple)

有序、不可变的元素集合

(1, "a", True)

集合(set)

无序、无重复的元素集合

{1, 2, 3}

字典(dict)

无序的键值对集合(键唯一)

{"name": "Alice"}

难点赘述:浮点数的精度问题是新手易忽略的点。

  1. 问题示例:0.1 + 0.2的结果不是0.3,而是0.30000000000000004,因为浮点数在计算机中用二进制存储,部分十进制小数无法精确表示。
  2. 解决方案:使用decimal模块精确计算(适用于金融场景):
from decimal import Decimal

print(Decimal("0.1") + Decimal("0.2"))  # 输出:0.3

1.7 Python 类型转换

核心内容:将一种数据类型转换为另一种,需使用内置转换函数,常见如下:

转换函数

说明

示例

int(x)

转为整数(x 需可被解析为整数)

int("10")10int(3.9)3

float(x)

转为浮点数

float("3.14")3.14

str(x)

转为字符串

str(10)"10"

bool(x)

转为布尔值(空 / 0 为False

bool(0)Falsebool([])False

list(x)

转为列表(x 需为可迭代对象)

list("abc")["a","b","c"]

难点赘述:转换失败的异常处理和 "隐性转换" 的区别。

  1. 转换失败场景:若x无法被解析为目标类型,会报ValueError,如int("abc")float("xyz")
    1. 解决方案:结合异常处理(后续章节内容)捕获错误:
s = "123a"

try:

    num = int(s)

except ValueError:

    print(f"字符串'{s}'无法转为整数")  # 输出:字符串'123a'无法转为整数
  1. 隐性转换:Python 在运算中自动转换类型,如10 + 3.14,会将10(int)转为10.0(float),结果为13.14(float)。

1.8 Python 输入、输出和导入

核心内容

  1. 输入input()函数,接收用户输入的内容(默认转为字符串),示例:name = input("请输入姓名:")
  2. 输出print()函数,可输出多个值(用逗号分隔,默认空格连接),支持格式化(如print(f"姓名:{name}"))。
  3. 导入:使用import导入模块 / 函数,常见方式:
    1. 导入整个模块:import math(使用时需加模块名,如math.sqrt(4));
    2. 导入指定函数:from math import sqrt(直接使用sqrt(4));
    3. 导入并改名:import math as m(用m.sqrt(4))。

难点赘述input()的类型问题和print()的格式化技巧。

  1. input()的坑:无论用户输入数字还是字符串,input()均返回字符串,需手动转换类型:
age = input("请输入年龄:")  # 用户输入20,age是"20"(字符串)

age = int(age)  # 转为整数后才能参与运算

print(f"明年年龄:{age + 1}")  # 正确:输出"明年年龄:21"
  1. print()格式化的 3 种方式(推荐 f-string,Python 3.6 + 支持):
name = "Alice"

age = 20

# 方式1:%格式化

print("姓名:%s,年龄:%d" % (name, age))

# 方式2:format()方法

print("姓名:{},年龄:{}".format(name, age))

# 方式3:f-string(最简洁)

print(f"姓名:{name},年龄:{age}")

1.9 Python 运算符

核心内容:按功能分为算术运算符、赋值运算符、比较运算符、逻辑运算符、成员运算符等,常用如下:

运算符类型

具体运算符

说明

示例

算术运算符

+-*/

加、减、乘、除(/返回 float)

5 / 22.5

//

整除(取整)

5 // 22

%

取余

5 % 21

**

幂运算

2 ** 38

比较运算符

==!=><

等于、不等于、大于、小于

3 == 3True

逻辑运算符

andornot

与、或、非(短路求值)

3>2 and 1<0False

成员运算符

innot in

判断元素是否在序列中

"a" in "abc"True

难点赘述:整除的正负号问题和逻辑运算符的 "短路求值"。

  1. 整除//的规则:结果向负无穷方向取整,而非四舍五入:

print(5 // 2)   # 输出:2(5/2=2.5,向负无穷取整为2)

print(-5 // 2)  # 输出:-3(-5/2=-2.5,向负无穷取整为-3)

  1. 短路求值:逻辑运算中,若前半部分已能确定结果,后半部分不再执行(提高效率):
    1. and:前半为False,后半不执行(如False and print("不会执行")print不触发);
    2. or:前半为True,后半不执行(如True or print("不会执行")print不触发)。

1.10 Python 关键字列表

核心内容:Python 3.12 版本共 35 个关键字,核心分类如下:

  1. 控制流:ifelifelseforwhilebreakcontinuepass
  2. 函数 / 类:defclassreturnyieldlambdaglobalnonlocal
  3. 数据类型:TrueFalseNoneintfloatstrlisttuplesetdict
  4. 其他:importfromastryexceptfinallyraisewithinnotandorisdel

使用建议:通过keyword模块实时查看当前版本关键字,避免误用:

import keyword

print("当前Python关键字:", keyword.kwlist)

print("'for'是否为关键字?", keyword.iskeyword("for"))  # 输出:True

二、Python 流程控制

2.1 Python if...else 语句

核心内容:根据条件判断执行不同代码块,语法如下:

  1. 基础 if:if 条件: 代码块(条件为True时执行);
  2. if-else:if 条件: 代码块1 else: 代码块2(二选一执行);
  3. if-elif-else:if 条件1: 代码块1 elif 条件2: 代码块2 else: 代码块3(多条件判断,仅执行第一个满足条件的代码块)。

难点赘述:条件表达式的简写和 "真值判断"。

  1. 条件表达式(三目运算符):简化if-else,语法1 if 条件 else 2,示例:
age = 20

status = "成年" if age >= 18 else "未成年"

print(status)  # 输出:成年
  1. 真值判断:条件无需显式写==,空值 / 0 会被视为False,非空 / 非 0 视为True,示例:
name = "Alice"

if name:  # 等价于if name != ""

    print(f"姓名:{name}")  # 执行

num = 0

if num:  # 等价于if num != 0

    print("num非0")  # 不执行

2.2 Python for 循环

核心内容:用于遍历可迭代对象(如列表、字符串、字典、range等),语法for 变量 in 可迭代对象: 代码块,常见场景:

  1. 遍历列表:for item in [1,2,3]: print(item)
  2. 遍历字符串:for char in "Python": print(char)
  3. 遍历字典:需指定遍历keys(默认)、valuesitems
info = {"name": "Alice", "age": 20}

# 遍历键

for key in info:

    print(key)  # 输出:name, age

# 遍历值

for value in info.values():

    print(value)  # 输出:Alice, 20

# 遍历键值对(用元组接收)

for key, value in info.items():

    print(f"{key}: {value}")  # 输出:name: Alice, age: 20
  1. range()函数:生成整数序列,语法range(开始, 结束, 步长)(左闭右开),示例for i in range(1, 5): print(i)(输出 1-4)。

难点赘述:遍历中修改列表的陷阱和range的惰性特性。

  1. 遍历中修改列表的坑:直接删除 / 添加元素会导致索引混乱,示例:
# 错误:删除列表中的偶数,结果不完整

nums = [1,2,3,4,5]

for num in nums:

    if num % 2 == 0:

        nums.remove(num)

print(nums)  # 输出:[1,3,5]?实际输出[1,3,5](本例碰巧正确,下例错误)

# 错误示例:删除[1,2,3,4,5,6]中的偶数

nums = [1,2,3,4,5,6]

for num in nums:

    if num % 2 == 0:

        nums.remove(num)

print(nums)  # 输出:[1,3,5]?实际输出[1,3,5](再试[2,4,6])

nums = [2,4,6]

for num in nums:

    if num % 2 == 0:

        nums.remove(num)

print(nums)  # 输出:[4](因为删除2后,列表变为[4,6],下一个遍历元素是6,删除后列表变为[4],循环结束)
    1. 解决方案:遍历列表的副本(如for num in nums.copy():),或倒序遍历:
nums = [2,4,6]

for num in nums.copy():  # 遍历副本

    if num % 2 == 0:

        nums.remove(num)

print(nums)  # 输出:[](正确)
  1. range的惰性特性:range(1, 1000000)不直接生成百万个数字,而是在遍历中动态生成,节省内存。

2.3 Python while 循环

核心内容:根据条件重复执行代码块,语法while 条件: 代码块,需确保条件最终为False(否则无限循环),常见场景:

  1. 固定次数循环(用计数器):
count = 0

while count < 3:

    print(f"第{count+1}次循环")

    count += 1  # 计数器更新,避免无限循环
  1. 无限循环(需内部用break终止):
while True:

    user_input = input("请输入'退出'结束:")

    if user_input == "退出":

        break  # 终止循环

    print(f"你输入的是:{user_input}")

难点赘述:无限循环的排查和while-else的用法。

  1. 无限循环原因:计数器未更新、条件恒为True(如while 1:),排查方法:打印计数器值,确认是否更新:
count = 0

while count < 3:

    print(f"count: {count}")

    # 忘记写count += 1,导致count始终为0,无限循环
  1. while-else:循环正常结束(未被break终止)时,执行else代码块,示例:
count = 0

while count < 3:

    print(f"循环中,count={count}")

    count += 1

else:

    print("循环正常结束")  # 执行(count达到3,条件不满足)

count = 0

while count < 3:

    print(f"循环中,count={count}")

    if count == 1:

        break  # 提前终止循环

    count += 1

else:

    print("循环正常结束")  # 不执行(被break终止)

2.4 Python break 和 continue

核心内容

  1. break:终止当前所在的循环(跳出整个循环),不执行后续迭代;
  2. continue:跳过当前迭代的剩余代码,直接进入下一次迭代。

难点赘述:嵌套循环中break的作用范围和continue的 "跳过" 逻辑。

  1. 嵌套循环中break:仅终止内层循环,外层循环继续:
# 外层循环3次,内层循环3次,内层遇到2则break

for i in range(1, 4):

    print(f"外层循环:i={i}")

    for j in range(1, 4):

        if j == 2:

            break  # 仅终止内层循环

        print(f"  内层循环:j={j}")

# 输出:

# 外层循环:i=1

#   内层循环:j=1

# 外层循环:i=2

#   内层循环:j=1

# 外层循环:i=3

#   内层循环:j=1
  1. continue的示例:遍历 1-5,跳过偶数:
for num in range(1, 6):

    if num % 2 == 0:

        continue  # 跳过当前迭代的print(num)

    print(num)  # 仅输出奇数:1,3,5

2.5 Python pass 语句

核心内容pass是 "空语句",无实际功能,仅用于占位(避免语法错误),常见场景:

  1. 定义空函数 / 类(后续补充代码):
def my_function():

    pass  # 暂时不写逻辑,避免报错

class MyClass:

    pass  # 暂时不写属性/方法
  1. 空代码块(如iffor中):
age = 17

if age < 18:

    pass  # 暂时不处理未成年逻辑,先占位

else:

    print("成年")

难点赘述pass与注释的区别:

  1. 注释:# 这是注释,解释代码,Python 解释器会忽略;
  2. pass:是语法层面的 "空操作",解释器会执行(但无任何效果),若不写pass,空代码块会报语法错误:
def my_func():

    # 这是注释,没有pass会报错

# 报错:IndentationError: expected an indented block

三、Python 函数

3.1 Python 函数定义与调用

核心内容:函数是可复用的代码块,用def定义,语法:

def 函数名(参数):

    """函数文档字符串(说明功能)"""

    函数体

    return 返回值  # 可选,无return则返回None

示例:定义计算两数之和的函数:

def add(a, b):

    """计算两个数的和"""

    result = a + b

    return result

# 调用函数

sum_result = add(3, 5)

print(sum_result)  # 输出:8

print(add.__doc__)  # 输出:计算两个数的和(查看文档字符串)

难点赘述:函数的 "参数默认值陷阱"(默认参数为可变对象时):

  1. 错误示例:默认参数是列表,多次调用函数会累积值:
def add_item(item, items=[]):

    items.append(item)

    return items

print(add_item(1))  # 输出:[1]

print(add_item(2))  # 输出:[1,2](预期是[2],实际累积)
  1. 原因:默认参数在函数定义时初始化一次,而非每次调用时初始化;
  2. 解决方案:默认参数用None,在函数内初始化可变对象:
def add_item(item, items=None):

    if items is None:

        items = []  # 每次调用时重新创建列表

    items.append(item)

    return items

print(add_item(1))  # 输出:[1]

print(add_item(2))  # 输出:[2](正确)

3.2 Python 函数参数类型

核心内容:Python 函数参数分为以下几类:

  1. 位置参数:必须按顺序传递,数量必须匹配函数定义。
  2. 默认参数:在定义时为参数提供默认值,调用时可以省略。但需要注意默认参数的位置,非默认参数不能跟随默认参数。
  3. 关键字参数:调用时通过参数名指定值,允许改变参数的顺序,但必须放在位置参数之后。
  4. 可变参数
    1. *args:接收任意数量的位置参数,打包成元组;
    2. **kwargs:接收任意数量的关键字参数,打包成字典。

难点赘述:参数混合使用的规则和可变参数的解包。

  1. 参数混合使用的顺序:位置参数 → 可变位置参数(*args)→ 关键字参数 → 可变关键字参数(**kwargs)。
def func(a, *args, b=10, **kwargs):

    print(a, args, b, kwargs)

func(1, 2, 3, b=20, c=30)  # 输出:1 (2, 3) 20 {'c': 30}
  1. 可变参数的解包:
# 位置参数解包

def greet(a, b, c):

    print(f"Hello {a}, {b}, {c}")

args = (1, 2, 3)

greet(*args)  # 输出:Hello 1, 2, 3

# 关键字参数解包

kwargs = {"a": "Alice", "b": "Bob", "c": "Charlie"}

greet(**kwargs)  # 输出:Hello Alice, Bob, Charlie

3.3 Python 递归 (Recursion)

核心内容:递归是函数直接或间接调用自身的过程,必须包含终止条件。常见示例:

  1. 计算阶乘:
def factorial(n):

    if n == 0:

        return 1  # 终止条件

    return n * factorial(n-1)  # 递归调用

print(factorial(5))  # 输出:120
  1. 斐波那契数列:
def fibonacci(n):

    if n <= 1:

        return n  # 终止条件

    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(6))  # 输出:8(斐波那契数列前7项:0,1,1,2,3,5,8)

难点赘述:递归深度限制和性能问题。

  1. 递归深度限制:Python 默认递归深度有限制(约 1000 层),超过会报RecursionError
# 测试递归深度限制

def deep_recursion(n):

    if n == 0:

        return

    deep_recursion(n+1)

# deep_recursion(0)  # 会报RecursionError: maximum recursion depth exceeded
  1. 解决方案:改用迭代方式或增加递归深度限制(不推荐):
import sys

sys.setrecursionlimit(1000000)  # 增加递归深度限制(不推荐)
  1. 性能问题:递归可能导致重复计算(如斐波那契数列的递归实现),可用缓存优化(装饰器lru_cache):
from functools import lru_cache

@lru_cache(maxsize=None)

def fibonacci(n):

    if n <= 1:

        return n

    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(100))  # 高效计算第100项

3.4 Python 匿名函数 (Lambda)

核心内容:匿名函数(Lambda 函数)是没有函数名的小型函数,用lambda关键字定义,语法:

lambda 参数: 表达式;示例:

# 普通函数

def add(a, b):

    return a + b

# 等价的Lambda函数

add_lambda = lambda a, b: a + b

print(add_lambda(3, 5))  # 输出:8

难点赘述:Lambda 函数的适用场景和限制。(map和filter对象只能被消费一次,第二次调用就会变为空)

  1. 适用场景:
    1. 作为其他函数的参数(如sortedmapfilter):
# 按年龄排序

people = [("Alice", 25), ("Bob", 30), ("Charlie", 20)]

people_sorted = sorted(people, key=lambda x: x[1])

print(people_sorted)  # 输出:[("Charlie", 20), ("Alice", 25), ("Bob", 30)]

# 获取列表中的偶数和值为1的数据

numbers = [1, 2, 3, 4, 5, 6, 7, 8]

even_numbers = filter(lambda x: x % 2 == 0 or x == 1, numbers)

print(list(even_numbers))  # 输出:[1, 2, 4, 6, 8]
print(list(even_numbers))  # 输出:[]
    1. 简单函数的临时使用:
# 计算平方

squares = map(lambda x: x**2, [1, 2, 3, 4, 5])

print(list(squares))  # 输出:[1, 4, 9, 16, 25]

print(list(squares))  # 输出:[]
  1. 限制:
    1. Lambda 函数只能有一个表达式,不能包含多条语句或return语句;
    2. 可读性较差,复杂逻辑不建议使用 Lambda 函数。

3.5 Python 全局、局部和非局部变量

核心内容

  1. 全局变量:在函数外部定义的变量,作用域为整个模块;
  2. 局部变量:在函数内部定义的变量,作用域为函数内部;
  3. 非局部变量:在嵌套函数中,内部函数引用外部函数的变量。

难点赘述:变量作用域的 LEGB 规则和修改全局 / 非局部变量的方法。

  1. LEGB 规则:Python 查找变量时遵循的顺序:Local → Enclosing → Global → Built-in。
x = "全局变量"

def outer():

    x = "外部函数变量"

    def inner():

        x = "内部函数变量"

        print("内部函数:", x)  # 输出:内部函数:内部函数变量

    inner()

    print("外部函数:", x)  # 输出:外部函数:外部函数变量

outer()

print("全局:", x)  # 输出:全局:全局变量
  1. 修改全局变量:使用global关键字声明。
count = 0

def increment():

    global count  # 声明使用全局变量count

    count += 1

    print(count)

increment()  # 输出:1

increment()  # 输出:2
  1. 修改非局部变量:使用nonlocal关键字声明。
def outer():

    x = 10

    def inner():

        nonlocal x  # 声明使用外部函数的变量x

        x += 5

        print(x)  # 输出:15

    inner()

    print(x)  # 输出:15

outer()

3.6 Python Global 关键字

核心内容global关键字用于在函数内部声明使用全局变量,使函数可以修改全局变量的值。

难点赘述globalnonlocal的区别及使用场景。

  1. global用于声明全局变量,nonlocal用于声明外部函数的变量。

# global示例

x = 10

def func():

    global x

    x = 20

    print(x)  # 输出:20

func()

print(x)  # 输出:20(全局变量x被修改)

# nonlocal示例

def outer():

    x = 10

    def inner():

        nonlocal x

        x = 20

        print(x)  # 输出:20

    inner()

    print(x)  # 输出:20(外部函数的x被修改)

outer()
  1. 使用场景:
    1. global:在函数内部修改全局变量;
    2. nonlocal:在嵌套函数内部修改外部函数的变量;
    3. 避免滥用globalnonlocal,优先通过参数传递和返回值来实现数据交换。

3.7 Python 模块

核心内容:模块是包含 Python 代码的文件(.py文件),用于组织代码,提高代码复用性。

  1. 导入模块:
import module_name  # 导入整个模块

from module_name import function_name  # 导入特定函数

from module_name import *  # 导入模块中的所有函数(不推荐)

import module_name as mn  # 导入并命名
  1. 模块的__name__属性:每个模块都有__name__属性,当模块作为主程序运行时,__name__"__main__";当模块被导入时,__name__为模块名。

难点赘述:模块的搜索路径和__init__.py文件的作用。

  1. 模块搜索路径:Python 解释器查找模块的路径列表,可通过sys.path查看和修改。
import sys

print(sys.path)  # 输出模块搜索路径列表

sys.path.append("/path/to/module")  # 添加自定义路径
  1. __init__.py文件:在 Python 3.3 之前,目录中包含__init__.py文件才被视为包。__init__.py可以为空,也可以包含包的初始化代码。

mypackage/

    __init__.py

    module1.py

    module2.py

3.8 Python 包(Package)

核心内容:包是组织多个模块的目录结构,用于管理大型项目。包的结构通常如下:

mypackage/

    __init__.py

    module1.py

    module2.py

    subpackage/

        __init__.py

        submodule.py

难点赘述:相对导入和绝对导入的区别。

  1. 绝对导入:从包的根目录开始导入。
# 在submodule.py中导入module1

from mypackage import module1
  1. 相对导入:基于当前模块的相对位置导入。
# 在submodule.py中导入module1

from .. import module1  # 相对导入父包中的module1
  1. 注意事项:
    1. 相对导入只能在包内部使用;
    2. 主模块(__main__)不能使用相对导入;
    3. Python 3 推荐使用绝对导入,提高代码可读性和可维护性。

3.9 Python 自定义函数

核心内容:用户可以根据需求定义自己的函数,实现特定功能。自定义函数的最佳实践包括:

  1. 函数命名:使用 "蛇形命名法"(如my_function);
  2. 参数设计:明确参数的类型和用途;
  3. 返回值:明确函数的返回值类型和含义;
  4. 文档字符串:为函数编写清晰的文档字符串,说明功能、参数、返回值等。

难点赘述:函数参数的设计原则和异常处理。

  1. 参数设计原则:
    1. 参数数量不宜过多,尽量控制在 5 个以内;
    2. 使用默认参数提供合理的默认值;
    3. 避免使用可变对象作为默认参数;
    4. 考虑参数的顺序(位置参数在前,默认参数在后)。
  2. 异常处理:在函数内部处理可能的异常,提高函数的健壮性。
def divide(a, b):

    try:

        return a / b

    except ZeroDivisionError:

        print("错误:除数不能为零")

        return None

print(divide(10, 2))  # 输出:5.0

print(divide(10, 0))  # 输出:错误:除数不能为零,返回None
  1. 函数式编程与过程式编程的选择:根据问题特性选择合适的编程范式。
    1. 函数式编程:强调纯函数(无副作用,相同输入总是返回相同输出);
    2. 过程式编程:允许有副作用(如修改全局变量)。

四、Python 数据类型

4.1 Python 数字 (Number)

核心内容:Python 支持三种数字类型:

  1. 整数(int:表示整数,大小不限(受限于内存);
  2. 浮点数(float:表示带小数点的数,精度有限;
  3. 复数(complex:表示复数,形式为a + bj

难点赘述:浮点数的精度问题和数值运算的类型转换。

  1. 浮点数精度问题:
    1. 示例:0.1 + 0.2的结果不是0.3,而是0.30000000000000004
    2. 原因:浮点数在计算机中以二进制表示,部分十进制小数无法精确表示。
    3. 解决方案:使用decimal模块进行高精度计算。
from decimal import Decimal

print(Decimal("0.1") + Decimal("0.2"))  # 输出:0.3
  1. 数值运算的类型转换:
    1. 自动转换:当不同类型的数值进行运算时,Python 会自动将整数转换为浮点数。
print(10 + 3.14)  # 输出:13.14(10被转为10.0)
    1. 强制转换:使用int()float()complex()进行类型转换。
print(int(3.9))  # 输出:3(向下取整)

print(float(5))  # 输出:5.0

print(complex(2))  # 输出:(2+0j)

4.2 Python 列表(List)

核心内容:列表是有序、可变的元素集合,用[]表示,元素类型可以不同。

难点赘述:列表的索引、切片和常见操作。

  1. 索引和切片:
fruits = ["apple", "banana", "cherry"]

print(fruits[0])  # 输出:apple(索引从0开始)

print(fruits[-1])  # 输出:cherry(负索引从末尾开始)

print(fruits[1:3])  # 输出:["banana", "cherry"](切片包括起始索引,不包括结束索引)
  1. 常见操作:
fruits = ["apple", "banana", "cherry"]

fruits.append("date")  # 添加到末尾

fruits.insert(1, "blueberry")  # 在指定位置插入

print(fruits)  # 输出:["apple", "blueberry", "banana", "cherry", "date"]

fruits.remove("banana")  # 按值删除

print(fruits)  # 输出:["apple", "blueberry", "cherry", "date"]

popped = fruits.pop(1)  # 按索引删除并返回删除的元素

print(popped)  # 输出:blueberry

del fruits[0]  # 按索引删除

print(fruits)  # 输出:["cherry", "date"]

print("cherry" in fruits)  # 输出:True(检查元素是否存在)

print(fruits.index("date"))  # 输出:1(查找元素索引)

fruits.sort()  # 原地排序

print(fruits)  # 输出:["cherry", "date"](按字母顺序)
    1. 添加元素:append()insert()
    2. 删除元素:pop()remove()del
    3. 查找元素:in运算符、index()方法;
    4. 排序:sort()(原地排序)、sorted()(返回新列表)。
  1. 列表推导式:简洁创建列表的方式。
squares = [x**2 for x in range(1, 6)]  # 生成1到5的平方列表

print(squares)  # 输出:[1, 4, 9, 16, 25]

even_numbers = [x for x in range(1, 11) if x % 2 == 0]  # 筛选偶数

print(even_numbers)  # 输出:[2, 4, 6, 8, 10]

4.3 Python 元组(Tuple)

核心内容:元组是有序、不可变的元素集合,用()表示,元素类型可以不同。

难点赘述:元组与列表的区别和元组的不可变性。

  1. 元组与列表的区别:
    1. 元组不可变,列表可变;
    2. 元组使用(),列表使用[]
    3. 元组的创建和访问速度比列表快;
    4. 元组适用于存储不可变的数据,列表适用于需要频繁修改的数据。
  2. 元组的不可变性:元组的元素一旦创建就不能修改,但如果元素是可变对象(如列表),则可以修改其内容。
# 元组示例

person = ("Alice", 30, ["Python", "Java"])

print(person[0])  # 输出:Alice

# person[1] = 31  # 错误:元组元素不可变

# 修改元组中的列表元素

person[2].append("C++")

print(person)  # 输出:("Alice", 30, ["Python", "Java", "C++"])
  1. 元组的解包:将元组的元素赋值给多个变量。
point = (3, 5)

x, y = point  # 元组解包

print(x, y)  # 输出:3 5

# 交换两个变量的值

a = 10

b = 20

a, b = b, a  # 元组解包实现交换

print(a, b)  # 输出:20 10

4.4 Python 字符串(String)

核心内容:字符串是不可变的字符序列,用""''表示。

难点赘述:字符串的操作、格式化和编码问题。

  1. 字符串操作:
s = "Hello, World!"

print(s[0])  # 输出:H

print(s[7:])  # 输出:World!

print(s + " Welcome!")  # 输出:Hello, World! Welcome!

print("-" * 20)  # 输出:--------------------

print(s.find("World"))  # 输出:7(找到返回起始索引)

print(s.find("Python"))  # 输出:-1(未找到返回-1)

print(s.replace("World", "Python"))  # 输出:Hello, Python!

parts = s.split(", ")

print(parts)  # 输出:["Hello", "World!"]

print(" ".join(parts))  # 输出:Hello World!
    1. 索引和切片:与列表类似;
    2. 连接和重复:+*运算符;
    3. 查找和替换:find()replace()
    4. 分割和合并:split()join()
  1. 字符串格式化:
    1. 旧式格式化(% 操作符):
name = "Alice"

age = 30

print("姓名:%s,年龄:%d" % (name, age))  # 输出:姓名:Alice,年龄:30
    1. 新式格式化(format () 方法):
print("姓名:{},年龄:{}".format(name, age))  # 输出:姓名:Alice,年龄:30

print("姓名:{0},年龄:{1},{0}今年{1}岁".format(name, age))  # 输出:姓名:Alice,年龄:30,Alice今年30岁
    1. f-string(推荐):
print(f"姓名:{name},年龄:{age}")  # 输出:姓名:Alice,年龄:30
  1. 字符串编码:
    1. Python 3 默认使用 UTF-8 编码;
    2. 使用encode()方法将字符串转换为字节(bytes),decode()方法将字节转换为字符串。
s = "你好,世界"

b = s.encode("utf-8")  # 转换为UTF-8字节

print(b)  # 输出:b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c'

s2 = b.decode("utf-8")  # 转换回字符串

print(s2)  # 输出:你好,世界

4.5 Python 集合(Set)

核心内容:集合是无序、无重复元素的集合,用{}set()创建。

难点赘述:集合的操作和用途。

  1. 集合的创建:
s = {1, 2, 3, 4}

print(s)  # 输出:{1, 2, 3, 4}

# 空集合必须用set()创建

empty_set = set()

print(empty_set)  # 输出:set()
  1. 集合操作:
s = {1, 2, 3}

s.add(4)

print(s)  # 输出:{1, 2, 3, 4}

s.update({5, 6})

print(s)  # 输出:{1, 2, 3, 4, 5, 6}

s.remove(3)

print(s)  # 输出:{1, 2, 4, 5, 6}

s.discard(7)  # 不报错

s.discard(5)

print(s)  # 输出:{1, 2, 4, 6}

# 集合运算

a = {1, 2, 3, 4}

b = {3, 4, 5, 6}

print(a | b)  # 并集:{1, 2, 3, 4, 5, 6}

print(a & b)  # 交集:{3, 4}

print(a - b)  # 差集:{1, 2}

print(a ^ b)  # 对称差:{1, 2, 5, 6}
    1. 添加元素:add()update()
    2. 删除元素:remove()(不存在则报错)、discard()(不存在不报错);
    3. 集合运算:并集(|)、交集(&)、差集(-)、对称差(^)。
  1. 集合的用途:
# 列表去重

lst = [1, 2, 2, 3, 3, 3]

unique = list(set(lst))

print(unique)  # 输出:[1, 2, 3](注意:集合是无序的)
    1. 去重:快速去除列表中的重复元素;
    2. 成员检测:in操作的时间复杂度为 O (1),比列表快;
    3. 数学集合运算:方便进行并、交、差等操作。

4.6 Python 字典(Dictionary)

核心内容:字典是无序的键值对集合,用{}表示,键必须是不可变类型(如字符串、数字、元组)。

难点赘述:字典的操作、遍历和性能。

  1. 字典操作:
person = {"name": "Alice", "age": 30, "hobbies": ["reading", "travel"]}

print(person["name"])  # 输出:Alice

print(person.get("age"))  # 输出:30

print(person.get("gender", "未知"))  # 输出:未知(指定默认值)

person["age"] = 31  # 修改现有键的值

person["gender"] = "female"  # 添加新键值对

print(person)  # 输出:{"name": "Alice", "age": 31, "hobbies": ["reading", "travel"], "gender": "female"}

del person["gender"]  # 删除键值对

print(person)  # 输出:{"name": "Alice", "age": 31, "hobbies": ["reading", "travel"]}

popped = person.pop("age")

print(popped)  # 输出:31

print(person)  # 输出:{"name": "Alice", "hobbies": ["reading", "travel"]}

print("name" in person)  # 输出:True

print("gender" in person)  # 输出:False

print(person.keys())  # 输出:dict_keys(["name", "hobbies"])

print(person.values())  # 输出:dict_values(["Alice", ["reading", "travel"]])

print(person.items())  # 输出:dict_items([("name", "Alice"), ("hobbies", ["reading", "travel"])])
    1. 访问和修改:[]get()
    2. 添加和删除:直接赋值、delpop()
    3. 键的存在性检查:in运算符;
    4. 获取键、值、项:keys()values()items()
  1. 字典遍历:
person = {"name": "Alice", "age": 30}

# 遍历键

for key in person:

    print(key)  # 输出:name, age

# 遍历值

for value in person.values():

    print(value)  # 输出:Alice, 30

# 遍历键值对

for key, value in person.items():

    print(f"{key}: {value}")  # 输出:name: Alice, age: 30
  1. 字典推导式:
squares = {x: x**2 for x in range(1, 6)}

print(squares)  # 输出:{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

even_squares = {x: x**2 for x in range(1, 6) if x % 2 == 0}

print(even_squares)  # 输出:{2: 4, 4: 16}
  1. 字典的性能:
    1. 字典的查找和插入操作时间复杂度为 O (1)(平均情况下);
    2. 字典的内存开销较大,适合需要频繁查找和修改的数据。

4.7 Python 集合方法

核心内容:集合对象提供了一系列方法,用于集合的操作和运算。

难点赘述:集合方法的使用场景和性能比较。

  1. 集合方法分类:
s1 = {1, 2, 3}

s2 = {3, 4, 5}

# 集合运算方法

print(s1.union(s2))  # 并集:{1, 2, 3, 4, 5}

print(s1.intersection(s2))  # 交集:{3}

print(s1.difference(s2))  # 差集:{1, 2}

print(s1.symmetric_difference(s2))  # 对称差:{1, 2, 4, 5}

# 集合关系检查

print(s1.issubset({1, 2, 3, 4}))  # 输出:True

print({1, 2}.issuperset(s1))  # 输出:False

# 复制集合

s3 = s1.copy()

print(s3)  # 输出:{1, 2, 3}
    1. 基础方法:add()remove()discard()clear()
    2. 集合运算方法:union()intersection()difference()symmetric_difference()
    3. 其他方法:copy()issubset()issuperset()
  1. 集合方法与运算符的区别:
s1 = {1, 2}

s2 = {2, 3}

s3 = {3, 4}

print(s1.union(s2, s3))  # 输出:{1, 2, 3, 4}
    1. 运算符(如|&-^)返回新集合;
    2. 方法(如union()intersection()等)可以接受多个集合作为参数。
  1. 集合方法的性能:
    1. 集合的成员检测(in)时间复杂度为 O (1);
    2. 集合的并、交、差运算时间复杂度与集合的大小有关;
    3. 避免在循环中频繁进行集合运算,尤其是大集合。

五、Python 文件操作

5.1 Python 文件 I/O

核心内容:Python 提供了open()函数用于文件操作,支持多种模式(读、写、追加等)。

难点赘述:文件打开模式、文件对象的方法和上下文管理器。

  1. 文件打开模式:
# 打开文件(默认文本模式)

f = open("example.txt", "r")

# 二进制模式打开图片文件

with open("image.jpg", "rb") as f:

    data = f.read()
    1. r:只读模式(默认),文件不存在则报错;
    2. w:写入模式,文件存在则覆盖,不存在则创建;
    3. a:追加模式,文件存在则在末尾追加,不存在则创建;
    4. r+:读写模式;
    5. b:二进制模式(如rbwb);
    6. t:文本模式(默认,如rtwt)。
  1. 文件对象的方法:
# 读取整个文件内容

with open("example.txt", "r") as f:

    content = f.read()

    print(content)

# 逐行读取

with open("example.txt", "r") as f:

    line = f.readline()

    while line:

        print(line.strip())  # 去除换行符

        line = f.readline()

# 读取所有行到列表

with open("example.txt", "r") as f:

    lines = f.readlines()

    print(lines)

# 写入文件

with open("output.txt", "w") as f:

    f.write("Hello, World!\n")

    f.write("This is a test.\n")

# 写入多行

lines = ["Line 1\n", "Line 2\n", "Line 3\n"]

with open("output.txt", "a") as f:

    f.writelines(lines)

# 文件定位

with open("example.txt", "r") as f:

    print(f.tell())  # 输出:0(当前位置)

    f.seek(5)  # 移动到第5个字节

    print(f.tell())  # 输出:5

    print(f.read(1))  # 读取一个字符
    1. 读取:read()readline()readlines()
    2. 写入:write()writelines()
    3. 定位:seek()tell()
  1. 使用上下文管理器(with语句):
# 不使用with语句

f = open("example.txt", "r")

content = f.read()

f.close()  # 必须手动关闭

# 使用with语句

with open("example.txt", "r") as f:

    content = f.read()

# 离开with块后,文件自动关闭
    1. 自动管理文件的打开和关闭,确保文件资源被正确释放;
    2. 避免忘记关闭文件导致的资源泄漏。

5.2 Python 目录和文件管理

核心内容:Python 提供了osshutil模块用于目录和文件的管理。

难点赘述:目录操作、文件路径处理和跨平台兼容性。

  1. 目录操作:
import os

# 创建目录(单级)

os.mkdir("test_dir")

# 创建多级目录

os.makedirs("test_dir/sub_dir")

# 删除空目录

os.rmdir("test_dir/sub_dir")

# 删除非空目录(需要shutil模块)

import shutil

shutil.rmtree("test_dir")

# 切换目录

os.chdir("/path/to/directory")

# 获取当前目录

print(os.getcwd())

# 列出目录内容

print(os.listdir("."))
    1. 创建目录:os.mkdir()os.makedirs()
    2. 删除目录:os.rmdir()shutil.rmtree()
    3. 切换目录:os.chdir()
    4. 获取当前目录:os.getcwd()
    5. 列出目录内容:os.listdir()
  1. 文件路径处理:
import os

# 路径拼接

path = os.path.join("dir1", "dir2", "file.txt")

print(path)  # 输出:dir1/dir2/file.txt(Linux/macOS)或 dir1\dir2\file.txt(Windows)

# 分离路径和文件名

dirname, filename = os.path.split(path)

print(dirname)  # 输出:dir1/dir2

print(filename)  # 输出:file.txt

# 获取文件扩展名

print(os.path.splitext(filename))  # 输出:("file", ".txt")

# 路径检查

print(os.path.exists(path))  # 检查路径是否存在

print(os.path.isfile(path))  # 检查是否为文件

print(os.path.isdir(path))  # 检查是否为目录
    1. 拼接路径:os.path.join()
    2. 分离路径和文件名:os.path.split()
    3. 获取文件名和扩展名:os.path.basename()os.path.splitext()
    4. 判断路径是否存在:os.path.exists()
    5. 判断是否为文件或目录:os.path.isfile()os.path.isdir()
  1. 跨平台兼容性:
# 错误示例(硬编码路径分隔符)

path = "C:\data\file.txt"  # 在Linux/macOS上会出错

# 正确示例

path = os.path.join("C:", "data", "file.txt")
    1. 使用os模块的函数处理路径,避免直接使用操作系统特定的路径分隔符;
    2. 使用os.path模块的函数进行路径操作,确保代码在不同平台上的兼容性。

5.3 Python 错误和内置异常

核心内容:Python 中的错误分为语法错误(SyntaxError)和异常(Exception),异常可以被捕获和处理。

难点赘述:异常的分类、自定义异常和异常处理的最佳实践。

  1. 异常分类:
# 常见内置异常

try:

    x = 10 / 0

except ZeroDivisionError as e:

    print("除数不能为零:", e)

try:

    print(my_list[100])

except IndexError as e:

    print("索引错误:", e)

try:

    int("abc")

except ValueError as e:

    print("值错误:", e)
    1. 内置异常:Python 预定义的异常,如ValueErrorTypeErrorIndexError等;
    2. 用户自定义异常:继承自Exception类的异常。
  1. 异常处理结构:
# try-except-else-finally结构

try:

    x = int(input("请输入一个整数:"))

    result = 10 / x

except ValueError:

    print("错误:输入不是整数")

except ZeroDivisionError:

    print("错误:除数不能为零")

else:

    print("结果:", result)

finally:

    print("执行结束")
    1. try-except:捕获特定异常;
    2. try-except-else:无异常时执行else块;
    3. try-except-finally:无论是否发生异常,都执行finally块;
    4. try-except-except-...:捕获多个不同的异常。
  1. 自定义异常:
class MyError(Exception):

    """自定义异常类"""

    def __init__(self, message):

        super().__init__(message)

        self.message = message

# 使用自定义异常

try:

    raise MyError("这是一个自定义异常")

except MyError as e:

    print(e.message)  # 输出:这是一个自定义异常
  1. 异常处理最佳实践:
    1. 捕获具体的异常,而非通用的ExceptionBaseException
    2. 在适当的层次处理异常;
    3. 避免在循环中处理异常,应优先使用条件判断;
    4. 在异常处理中记录日志,而非简单打印。

5.4 Python 异常处理

核心内容:Python 的异常处理机制允许程序捕获和处理运行时错误,提高程序的健壮性。

难点赘述:异常传播、raise语句和异常链。

  1. 异常传播:
def func1():

    func2()

def func2():

    func3()

def func3():

    x = 10 / 0  # 抛出ZeroDivisionError

try:

    func1()

except ZeroDivisionError:

    print("捕获到异常:除数不能为零")
    1. 异常未被当前函数处理时,会向上层调用函数传播;
    2. 直到找到处理该异常的except块或程序终止。
  1. raise语句:
def divide(a, b):

    if b == 0:

        raise ZeroDivisionError("除数不能为零")

    return a / b

try:

    result = divide(10, 0)

except ZeroDivisionError as e:

    print(e)  # 输出:除数不能为零

# 重新抛出异常

try:

    x = int("abc")

except ValueError as e:

    print("值错误:", e)

    raise  # 重新抛出捕获的异常
    1. 主动抛出异常;
    2. 重新抛出捕获的异常。
  1. 异常链:
try:

    x = 10 / 0

except ZeroDivisionError as e:

    raise ValueError("无效的输入") from e  # 建立异常链
    1. 在处理一个异常时,可以引发另一个异常,形成异常链;
    2. 使用raise ... from ...语法显式建立异常链。
  1. 上下文管理器与异常:
class FileHandler:

    def __init__(self, filename, mode):

        self.filename = filename

        self.mode = mode

        self.file = None

    def __enter__(self):

        self.file = open(self.filename, self.mode)

        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):

        if self.file:

            self.file.close()

        # 返回True表示异常已处理,不继续传播

        return True

# 使用自定义上下文管理器

with FileHandler("test.txt", "w") as f:

    f.write("Hello, World!")

    # 故意引发异常

    x = 10 / 0
    1. 上下文管理器的__exit__方法可以处理异常;
    2. 使用with语句管理资源时,可以在上下文管理器中处理异常。

5.5 Python 自定义异常

核心内容:用户可以自定义异常类,用于特定业务逻辑的错误处理。

难点赘述:自定义异常的设计原则和使用场景。

  1. 自定义异常的定义:
class CustomError(Exception):

    """自定义异常的基类"""

    pass

class ValidationError(CustomError):

    """验证错误异常"""

    def __init__(self, message, errors):

        super().__init__(message)

        self.errors = errors

class DatabaseError(CustomError):

    """数据库操作异常"""

    def __init__(self, message, code):

        super().__init__(message)

        self.code = code
  1. 自定义异常的使用:
def validate_user_input(data):

    if not data:

        raise ValidationError("输入数据不能为空", errors=["data"])

    # 其他验证逻辑...

try:

    validate_user_input("")

except ValidationError as e:

    print(e)  # 输出:输入数据不能为空

    print("错误详情:", e.errors)
  1. 自定义异常的最佳实践:
    1. 异常类应继承自Exception类;
    2. 提供有意义的错误消息;
    3. 包含足够的上下文信息(如错误代码、错误详情);
    4. 在适当的层次抛出异常,避免在底层模块处理高层异常。

六、Python 对象和类

6.1 Python 面向对象编程

核心内容:面向对象编程(OOP)是一种编程范式,将数据和操作数据的方法封装在对象中。

难点赘述:面向对象的四大特性(封装、继承、多态、抽象)和类与实例的关系。

  1. 面向对象特性:
    1. 封装:将数据和方法封装在类中,通过访问修饰符(如__)控制访问权限;
    2. 继承:子类可以继承父类的属性和方法;
    3. 多态:不同子类对同一方法的不同实现;
    4. 抽象:通过抽象类定义接口,强制子类实现特定方法。
  2. 类与实例:
# 定义类

class Person:

    def __init__(self, name, age):

        self.name = name  # 公有属性

        self.__age = age  # 私有属性

    def say_hello(self):  # 公有方法

        print(f"你好,我是{self.name},今年{self.__age}岁。")

    def __private_method(self):  # 私有方法

        print("这是一个私有方法")

# 创建实例

alice = Person("Alice", 30)

alice.say_hello()  # 输出:你好,我是Alice,今年30岁。

# 访问私有属性和方法(不推荐)

print(alice._Person__age)  # 输出:30(通过名称改写访问)

alice._Person__private_method()  # 输出:这是一个私有方法
    1. 类:对象的模板,定义属性和方法;
    2. 实例:类的具体对象,拥有类定义的属性和方法。
  1. 类属性与实例属性:
class Car:

    wheels = 4  # 类属性

    def __init__(self, brand):

        self.brand = brand  # 实例属性

print(Car.wheels)  # 输出:4

car1 = Car("Toyota")

car2 = Car("Honda")

print(car1.wheels)  # 输出:4

print(car2.wheels)  # 输出:4

# 修改类属性

Car.wheels = 5

print(car1.wheels)  # 输出:5

print(car2.wheels)  # 输出:5

# 实例属性会覆盖类属性

car1.wheels = 6

print(car1.wheels)  # 输出:6(实例属性)

print(car2.wheels)  # 输出:5(类属性)
    1. 类属性:所有实例共享的属性;
    2. 实例属性:每个实例独有的属性。

6.2 Python 类和对象

核心内容:类是对象的模板,对象是类的实例。

难点赘述:构造方法、析构方法和特殊方法(魔术方法)。

  1. 构造方法(__init__):
class Person:

    def __init__(self, name, age):

        self.name = name

        self.age = age

person = Person("Alice", 30)

print(person.name)  # 输出:Alice

print(person.age)  # 输出:30
    1. 在实例创建时自动调用;
    2. 用于初始化实例的属性。
  1. 析构方法(__del__):
class Resource:

    def __init__(self):

        print("资源初始化")

    def __del__(self):

        print("资源清理")

r = Resource()  # 输出:资源初始化

del r  # 输出:资源清理(当引用计数为零时)
    1. 在实例被销毁时自动调用;
    2. 用于资源清理。
  1. 特殊方法(魔术方法):
class Vector:

    def __init__(self, x, y):

        self.x = x

        self.y = y

    def __str__(self):

        return f"Vector({self.x}, {self.y})"

    def __add__(self, other):

        return Vector(self.x + other.x, self.y + other.y)

    def __eq__(self, other):

        return self.x == other.x and self.y == other.y

v1 = Vector(1, 2)

v2 = Vector(3, 4)

print(v1)  # 输出:Vector(1, 2)

v3 = v1 + v2

print(v3)  # 输出:Vector(4, 6)

print(v1 == v2)  # 输出:False
    1. 以双下划线开头和结尾的方法,如__str____repr____add__等;
    2. 允许类的实例支持内置操作(如打印、相加、比较等)。
  1. 类方法和静态方法:
class MathUtils:

    @classmethod

    def add(cls, a, b):

        return a + b

    @staticmethod

    def multiply(a, b):

        return a * b

print(MathUtils.add(2, 3))  # 输出:5

print(MathUtils.multiply(2, 3))  # 输出:6
    1. 类方法:使用@classmethod装饰器,第一个参数是类对象;
    2. 静态方法:使用@staticmethod装饰器,无特殊参数。

6.3 Python 继承

核心内容:继承是面向对象编程的重要特性,允许子类继承父类的属性和方法。

难点赘述:单继承、多继承和方法重写。

  1. 单继承:
class Animal:

    def __init__(self, name):

        self.name = name

    def speak(self):

        pass  # 抽象方法,由子类实现

class Dog(Animal):

    def speak(self):

        return "汪汪"

class Cat(Animal):

    def speak(self):

        return "喵喵"

dog = Dog("旺财")

print(dog.name)  # 输出:旺财

print(dog.speak())  # 输出:汪汪

# 使用super()调用父类方法

class Animal:

    def __init__(self, name):

        self.name = name

        self.legs = 4

    def move(self):

        print(f"{self.name} 用{self.legs}条腿移动")

class Bird(Animal):

    def __init__(self, name):

        super().__init__(name)

        self.legs = 2

    def move(self):

        super().move()  # 调用父类的move方法

        print(f"{self.name} 还会飞")

bird = Bird("鹦鹉")

bird.move()  # 输出:鹦鹉 用2条腿移动,鹦鹉 还会飞
    1. 子类继承一个父类;
    2. 使用super()函数调用父类的方法。
  1. 多继承:
class A:

    def method(self):

        print("A的方法")

class B:

    def method(self):

        print("B的方法")

class C(A, B):

    pass

c = C()

c.method()  # 输出:A的方法(根据MRO,先查找A)

print(C.__mro__)  # 输出:(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
    1. 子类继承多个父类;
    2. 注意方法解析顺序(MRO)。
  1. 方法重写:
class Vehicle:

    def start(self):

        print("车辆启动")

class Car(Vehicle):

    def start(self):

        print("汽车启动")

        super().start()  # 调用父类的start方法

car = Car()

car.start()  # 输出:汽车启动,车辆启动
    1. 子类重新定义父类的方法;
    2. 使用super()调用父类的方法。
  1. 多重继承的菱形问题:
class A:

    def method(self):

        print("A的方法")

class B(A):

    def method(self):

        print("B的方法")

        super().method()

class C(A):

    def method(self):

        print("C的方法")

        super().method()

class D(B, C):

    pass

d = D()

d.method()  # 输出:B的方法,C的方法,A的方法(根据MRO)
    1. 当多个父类有共同的祖先时,可能导致方法被多次调用;
    2. 使用super()和正确的 MRO 解决菱形问题。

6.4 Python 多重继承

核心内容:多重继承允许子类继承多个父类的属性和方法。

难点赘述:多重继承的复杂性、方法解析顺序和 Mixin 模式。

  1. 方法解析顺序(MRO):
class A:

    def method(self):

        print("A的方法")

class B(A):

    def method(self):

        print("B的方法")

        super().method()

class C(A):

    def method(self):

        print("C的方法")

        super().method()

class D(B, C):

    pass

print(D.__mro__)  # 输出:(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

d = D()

d.method()  # 输出:B的方法,C的方法,A的方法
    1. Python 使用 C3 线性化算法确定方法解析顺序;
    2. 可以通过__mro__属性或mro()方法查看 MRO。
  1. Mixin 模式:
class LoggingMixin:

    def log(self, message):

        print(f"日志:{message}")

class Calculator(LoggingMixin):

    def add(self, a, b):

        self.log(f"执行加法:{a} + {b}")

        return a + b

class Database(LoggingMixin):

    def connect(self):

        self.log("连接数据库")

        # 数据库连接逻辑...

calc = Calculator()

print(calc.add(2, 3))  # 输出:日志:执行加法:2 + 3,5

db = Database()

db.connect()  # 输出:日志:连接数据库
    1. 使用多重继承实现 Mixin 类,为多个不相关的类提供功能;
    2. Mixin 类通常不单独使用,而是与其他类组合。
  1. 多重继承的最佳实践:
    1. 避免复杂的多重继承关系;
    2. 优先使用组合而非继承;
    3. Mixin 类应该功能单一,不依赖其他类;
    4. 在多重继承中明确指定父类的顺序。

6.5 Python 运算符重载

核心内容:运算符重载允许自定义类的实例使用内置运算符(如+-*/等)。

难点赘述:运算符重载的方法和使用场景。

  1. 算术运算符重载:
class Vector:

    def __init__(self, x, y):

        self.x = x

        self.y = y

    def __add__(self, other):

        return Vector(self.x + other.x, self.y + other.y)

    def __sub__(self, other):

        return Vector(self.x - other.x, self.y - other.y)

    def __mul__(self, scalar):

        return Vector(self.x * scalar, self.y * scalar)

    def __rmul__(self, scalar):

        return self * scalar

v1 = Vector(1, 2)

v2 = Vector(3, 4)

v3 = v1 + v2

print(v3.x, v3.y)  # 输出:4 6

v4 = v1 * 2

print(v4.x, v4.y)  # 输出:2 4

v5 = 2 * v1  # 由于定义了__rmul__,可以交换顺序

print(v5.x, v5.y)  # 输出:2 4
    1. __add__()+运算符;
    2. __sub__()-运算符;
    3. __mul__()*运算符;
    4. __truediv__()/运算符;
    5. __floordiv__()//运算符;
    6. __mod__()%运算符;
    7. __pow__()**运算符。
  1. 比较运算符重载:
class Point:

    def __init__(self, x, y):

        self.x = x

        self.y = y

    def __eq__(self, other):

        return self.x == other.x and self.y == other.y

    def __lt__(self, other):

        return self.x < other.x or (self.x == other.x and self.y < other.y)

p1 = Point(1, 2)

p2 = Point(1, 3)

p3 = Point(2, 1)

print(p1 == p2)  # 输出:False

print(p1 < p2)  # 输出:True

print(p1 < p3)  # 输出:True
    1. __eq__()==运算符;
    2. __ne__()!=运算符;
    3. __lt__()<运算符;
    4. __le__()<=运算符;
    5. __gt__()>运算符;
    6. __ge__()>=运算符。
  1. 其他运算符重载:
class MyList:

    def __init__(self, data):

        self.data = data

    def __len__(self):

        return len(self.data)

    def __getitem__(self, index):

        return self.data[index]

    def __setitem__(self, index, value):

        self.data[index] = value

    def __contains__(self, item):

        return item in self.data

ml = MyList([1, 2, 3, 4, 5])

print(len(ml))  # 输出:5

print(ml[2])  # 输出:3

ml[2] = 10

print(ml.data)  # 输出:[1, 2, 10, 4, 5]

print(10 in ml)  # 输出:True
    1. 成员运算符:__contains__()
    2. 索引和切片:__getitem__()__setitem__()
    3. 长度:__len__()
    4. 字符串表示:__str__()__repr__()
  1. 运算符重载的最佳实践:
    1. 运算符重载应保持与内置类型一致的行为;
    2. 只重载有意义的运算符;
    3. 避免过度使用运算符重载,影响代码可读性;
    4. 在文档字符串中说明运算符的行为。

七、Python 日期和时间

7.1 Python 日期时间 (datetime)

核心内容:Python 的datetime模块提供了处理日期和时间的类,包括datetimedatetimetimedelta等。

难点赘述:日期时间对象的创建、格式化和时间差计算。

  1. 日期时间对象的创建:
from datetime import date, time, datetime

# 创建date对象

d = date(2023, 10, 1)

print(d)  # 输出:2023-10-01

# 创建time对象

t = time(12, 30, 45)

print(t)  # 输出:12:30:45

# 创建datetime对象

dt = datetime(2023, 10, 1, 12, 30, 45)

print(dt)  # 输出:2023-10-01 12:30:45

# 获取当前日期时间

now = datetime.now()

print(now)  # 输出类似:2023-10-01 15:30:45.123456

# 从timestamp创建datetime对象

timestamp = 1696150245

dt = datetime.fromtimestamp(timestamp)

print(dt)  # 输出:2023-10-01 12:30:45
  1. 日期时间的属性和方法:
from datetime import datetime

dt = datetime(2023, 10, 1, 12, 30, 45)

print(dt.year)  # 输出:2023

print(dt.month)  # 输出:10

print(dt.day)  # 输出:1

print(dt.hour)  # 输出:12

print(dt.minute)  # 输出:30

print(dt.second)  # 输出:45

# 替换部分属性

dt2 = dt.replace(hour=15, minute=0)

print(dt2)  # 输出:2023-10-01 15:00:45

# 日期时间比较

dt1 = datetime(2023, 10, 1, 12, 0, 0)

dt2 = datetime(2023, 10, 1, 15, 0, 0)

print(dt1 < dt2)  # 输出:True
  1. 时间差计算:
from datetime import datetime, timedelta

dt = datetime(2023, 10, 1, 12, 30, 45)

delta = timedelta(days=7, hours=3, minutes=30)

# 日期时间加上时间差

future_dt = dt + delta

print(future_dt)  # 输出:2023-10-08 16:00:45

# 日期时间减去时间差

past_dt = dt - delta

print(past_dt)  # 输出:2023-09-24 09:00:45

# 计算两个日期时间的差

dt1 = datetime(2023, 10, 1, 12, 0, 0)

dt2 = datetime(2023, 10, 1, 15, 30, 0)

diff = dt2 - dt1

print(diff)  # 输出:3:30:00

print(diff.total_seconds())  # 输出:12600.0(总秒数)
    1. 使用timedelta类表示时间间隔;
    2. 可以进行日期时间的加减运算。

7.2 Python strftime()

核心内容strftime()方法将datetime对象格式化为字符串。

难点赘述:格式代码的使用和本地化设置。

  1. 基本格式代码:
from datetime import datetime

dt = datetime(2023, 10, 1, 12, 30, 45)

print(dt.strftime("%Y-%m-%d %H:%M:%S"))  # 输出:2023-10-01 12:30:45

print(dt.strftime("%a, %b %d %Y"))  # 输出:Sun, Oct 01 2023

print(dt.strftime("今天是%A,%B %d, %Y"))  # 输出:今天是Sunday,October 01, 2023
    1. %Y:四位数年份;
    2. %m:两位数月份(01-12);
    3. %d:两位数日期(01-31);
    4. %H:24 小时制小时(00-23);
    5. %M:分钟(00-59);
    6. %S:秒(00-59);
    7. %a:星期几的缩写(如 Mon);
    8. %A:星期几的全称(如 Monday);
    9. %b:月份的缩写(如 Oct);
    10. %B:月份的全称(如 October);
    11. %c:本地日期时间表示;
    12. %x:本地日期表示;
    13. %X:本地时间表示。
  1. 本地化格式:
import locale

from datetime import datetime

# 设置本地化环境为中文(需要系统支持)

locale.setlocale(locale.LC_ALL, "zh_CN.UTF-8")

dt = datetime(2023, 10, 1, 12, 30, 45)

print(dt.strftime("%c"))  # 输出:2023年10月01日 周日 12:30:45

print(dt.strftime("%x"))  # 输出:2023/10/01

print(dt.strftime("%X"))  # 输出:12:30:45
    1. 不同地区的日期时间格式可能不同;
    2. 使用locale模块设置本地化环境。
  1. 自定义格式组合:
from datetime import datetime

dt = datetime(2023, 10, 1, 12, 30, 45)

print(dt.strftime("%Y年%m月%d日 %H时%M分%S秒"))  # 输出:2023年10月01日 12时30分45秒

print(dt.strftime("%Y-%m-%dT%H:%M:%S"))  # 输出:2023-10-01T12:30:45(ISO 8601格式)
    1. 可以组合多个格式代码创建自定义的日期时间字符串。

7.3 Python strptime()

核心内容strptime()方法将字符串解析为datetime对象。

难点赘述:解析格式的匹配和异常处理。

  1. 基本解析方法:
from datetime import datetime

s = "2023-10-01 12:30:45"

dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S")

print(dt)  # 输出:2023-10-01 12:30:45

s = "2023/10/01"

dt = datetime.strptime(s, "%Y/%m/%d")

print(dt)  # 输出:2023-10-01 00:00:00

s = "Oct 1, 2023 12:30 PM"

dt = datetime.strptime(s, "%b %d, %Y %I:%M %p")

print(dt)  # 输出:2023-10-01 12:30:00
    1. 使用与strftime()相同的格式代码;
    2. datetime.strptime(字符串, 格式)
  1. 本地化解析:
import locale

from datetime import datetime

# 设置本地化环境为中文(需要系统支持)

locale.setlocale(locale.LC_ALL, "zh_CN.UTF-8")

s = "2023年10月01日 12:30:45"

dt = datetime.strptime(s, "%Y年%m月%d日 %H:%M:%S")

print(dt)  # 输出:2023-10-01 12:30:45

s = "星期日, 2023年10月01日"

dt = datetime.strptime(s, "%A, %Y年%m月%d日")

print(dt)  # 输出:2023-10-01 00:00:00
    1. 解析本地化日期时间字符串时,需要设置相应的本地化环境;
    2. 不同地区的月份和星期名称可能不同。
  1. 异常处理:
from datetime import datetime

s = "2023-13-01"  # 无效的月份

try:

    dt = datetime.strptime(s, "%Y-%m-%d")

except ValueError as e:

    print("解析错误:", e)  # 输出:解析错误: day is out of range for month
    1. 字符串格式与指定格式不匹配时,会抛出ValueError
    2. 使用try-except块处理解析错误。

7.4 Python 当前日期和时间

核心内容:获取当前日期和时间的方法。

难点赘述:时区处理和不同精度的时间获取。

  1. 获取当前日期时间:
from datetime import datetime, date

# 获取当前日期时间(本地时间)

now = datetime.now()

print("当前日期时间:", now)

# 获取当前UTC日期时间

utc_now = datetime.utcnow()

print("当前UTC日期时间:", utc_now)

# 获取当前日期

today = date.today()

print("当前日期:", today)
    1. datetime.now():获取当前日期时间(本地时间);
    2. datetime.utcnow():获取当前 UTC 日期时间;
    3. date.today():获取当前日期。
  1. 时区处理:
from datetime import datetime

import pytz  # 需要安装pytz库

# 获取当前北京时间

beijing_tz = pytz.timezone("Asia/Shanghai")

beijing_now = datetime.now(beijing_tz)

print("北京时间:", beijing_now)

# 获取当前纽约时间

new_york_tz = pytz.timezone("America/New_York")

new_york_now = datetime.now(new_york_tz)

print("纽约时间:", new_york_now)

# 时区转换

dt = datetime.now(beijing_tz)

dt_utc = dt.astimezone(pytz.utc)

print("转换为UTC时间:", dt_utc)
    1. Python 的datetime模块对时区的支持有限;
    2. 使用第三方库pytzzoneinfo(Python 3.9+)处理时区。
  1. 时间戳:
from datetime import datetime

# 获取当前时间戳(浮点数,秒)

timestamp = datetime.now().timestamp()

print("当前时间戳:", timestamp)

# 将时间戳转换为datetime对象

dt = datetime.fromtimestamp(timestamp)

print("对应的日期时间:", dt)

# UTC时间戳

utc_timestamp = datetime.utcnow().timestamp()

print("UTC时间戳:", utc_timestamp)
    1. 获取当前时间戳(从 1970 年 1 月 1 日 UTC 到现在的秒数)。

7.5 Python 获取当前时间

核心内容:获取当前时间的不同方法。

难点赘述:时间精度和性能考虑。

  1. 获取当前时间:
from datetime import datetime

import time

# 获取当前时间(time对象)

current_time = datetime.now().time()

print("当前时间:", current_time)

# 获取当前时间戳(秒)

timestamp = time.time()

print("当前时间戳:", timestamp)

# 获取当前时间的字符串表示

current_time_str = time.ctime()

print("当前时间字符串:", current_time_str)
    1. datetime.now().time():获取当前时间(time对象);
    2. time模块的time()函数:获取当前时间戳;
    3. time模块的ctime()函数:获取当前时间的字符串表示。
  1. 时间精度:
import time

# 测量代码执行时间

start = time.perf_counter()

# 执行一些操作

end = time.perf_counter()

print("执行时间:", end - start, "秒")

# 获取CPU时间

cpu_time = time.process_time()

print("CPU时间:", cpu_time, "秒")
    1. time.time()返回的时间戳精度为秒或毫秒(取决于系统);
    2. 使用time.perf_counter()time.process_time()获取高精度时间。
  1. 时间格式转换:
from datetime import datetime, time

# 将time对象格式化为字符串

t = datetime.now().time()

print(t.strftime("%H:%M:%S"))  # 输出:当前时间的HH:MM:SS格式

# 将字符串解析为time对象

s = "12:30:45"

t = datetime.strptime(s, "%H:%M:%S").time()

print(t)  # 输出:12:30:45
    1. time对象格式化为字符串;
    2. 将字符串解析为time对象。

7.6 Python 时间戳 (timestamp)

核心内容:时间戳是从 1970 年 1 月 1 日 UTC 到指定时间的秒数。

难点赘述:时间戳与datetime对象的转换和时区问题。

  1. 时间戳与datetime转换:
from datetime import datetime

# 创建datetime对象

dt = datetime(2023, 10, 1, 12, 30, 45)

# 转换为时间戳

timestamp = dt.timestamp()

print("时间戳:", timestamp)  # 输出:1696150245.0

# 将时间戳转换为本地datetime对象

dt_local = datetime.fromtimestamp(timestamp)

print("本地时间:", dt_local)  # 输出:2023-10-01 12:30:45

# 将时间戳转换为UTC datetime对象

dt_utc = datetime.utcfromtimestamp(timestamp)

print("UTC时间:", dt_utc)  # 输出:2023-10-01 04:30:45(假设时区为UTC+8)
    1. datetime.timestamp():将datetime对象转换为时间戳;
    2. datetime.fromtimestamp():将时间戳转换为datetime对象(本地时间);
    3. datetime.utcfromtimestamp():将时间戳转换为 UTCdatetime对象。
  1. 时区与时间戳:
from datetime import datetime

import pytz  # 需要安装pytz库

# 获取当前北京时间的时间戳

beijing_tz = pytz.timezone("Asia/Shanghai")

beijing_now = datetime.now(beijing_tz)

timestamp = beijing_now.timestamp()

print("北京时间戳:", timestamp)

# 将时间戳转换为UTC时间

dt_utc = datetime.utcfromtimestamp(timestamp)

print("UTC时间:", dt_utc)

# 将时间戳转换为其他时区的时间

new_york_tz = pytz.timezone("America/New_York")

new_york_dt = datetime.fromtimestamp(timestamp, new_york_tz)

print("纽约时间:", new_york_dt)
    1. 时间戳是 UTC 时间的表示,与时区无关;
    2. 将时间戳转换为本地时间时,需考虑时区偏移。
  1. 时间戳的精度:
import time

# 获取高精度时间戳(可能包含毫秒)

timestamp = time.time()

print("高精度时间戳:", timestamp)
    1. 时间戳通常为浮点数,精确到秒或毫秒;
    2. 不同系统的时间戳精度可能不同。

7.7 Python time 模块

核心内容time模块提供了处理时间的函数,包括时间戳、睡眠和性能测量。

难点赘述time模块的函数与datetime模块的区别和使用场景。

  1. 时间获取函数:
import time

# 获取当前时间戳

timestamp = time.time()

print("时间戳:", timestamp)

# 获取当前时间的字符串表示

current_time_str = time.ctime()

print("当前时间字符串:", current_time_str)

# 将时间戳转换为UTC时间的struct_time

utc_time = time.gmtime(timestamp)

print("UTC时间:", utc_time)

# 将时间戳转换为本地时间的struct_time

local_time = time.localtime(timestamp)

print("本地时间:", local_time)
    1. time.time():获取当前时间戳;
    2. time.ctime():获取当前时间的字符串表示;
    3. time.gmtime():将时间戳转换为 UTC 时间的 struct_time;
    4. time.localtime():将时间戳转换为本地时间的 struct_time。
  1. 时间格式化:
import time

# 获取当前时间的struct_time

now = time.localtime()

# 格式化为字符串

print(time.strftime("%Y-%m-%d %H:%M:%S", now))  # 输出:当前日期时间的字符串表示

# 将字符串解析为struct_time

s = "2023-10-01 12:30:45"

struct_time = time.strptime(s, "%Y-%m-%d %H:%M:%S")

print(struct_time)  # 输出:time.struct_time(tm_year=2023, tm_mon=10, tm_mday=1, tm_hour=12, tm_min=30, tm_sec=45, ...)
    1. time.strftime():将 struct_time 格式化为字符串;
    2. time.strptime():将字符串解析为 struct_time。
  1. 性能测量和睡眠:
import time

# 测量代码执行时间

start = time.perf_counter()

time.sleep(1)  # 暂停1秒

end = time.perf_counter()

print("执行时间:", end - start, "秒")

# 测量CPU时间

cpu_start = time.process_time()

# 执行一些CPU密集型操作

cpu_end = time.process_time()

print("CPU时间:", cpu_end - cpu_start, "秒")
    1. time.perf_counter():测量性能的高精度计时器;
    2. time.process_time():测量 CPU 时间;
    3. time.sleep():暂停执行指定秒数。

7.8 Python sleep()

核心内容time.sleep()函数暂停当前线程的执行指定秒数。

难点赘述:睡眠的精度和中断处理。

  1. 基本用法:
import time

print("开始睡眠")

time.sleep(2)  # 暂停2秒

print("睡眠结束")
  1. 睡眠的精度:
import time

start = time.perf_counter()

time.sleep(1)  # 期望暂停1秒

end = time.perf_counter()

print("实际暂停时间:", end - start, "秒")  # 可能略大于1秒
    1. sleep()的实际暂停时间可能比指定时间长;
    2. 受系统调度和其他因素影响。
  1. 中断处理:
import time

try:

    print("开始长时间睡眠")

    time.sleep(3600)  # 暂停1小时

except KeyboardInterrupt:

    print("睡眠被用户中断")
    1. 在睡眠期间,线程可以被信号中断;
    2. 处理KeyboardInterrupt异常。
  1. 睡眠的应用场景:
import time

# 控制循环每秒钟执行一次

while True:

    print("执行任务")

    time.sleep(1)  # 暂停1秒

# 模拟网络请求延迟

print("发送请求...")

time.sleep(2)  # 模拟2秒的网络延迟

print("请求完成")
    1. 控制循环的执行频率;
    2. 模拟长时间操作;
    3. 在多线程程序中协调线程执行。

八、Python 高级知识

8.1 Python 命名空间和作用域

核心内容:命名空间是变量的容器,作用域是变量可以被访问的区域。

难点赘述:命名空间的生命周期、作用域链和闭包的作用域问题。

  1. 命名空间分类:
# 内置命名空间示例

print(len.__class__)  # 输出:<class 'builtin_function_or_method'>

# 全局命名空间示例

global_var = 10

def func():

    # 局部命名空间示例

    local_var = 20

    print(locals())  # 输出:{'local_var': 20}

print(globals())  # 输出:包含全局变量的字典

func()
    1. 内置命名空间:包含 Python 内置函数和类型;
    2. 全局命名空间:模块级别的变量;
    3. 局部命名空间:函数或类内部的变量。
  1. 作用域链:
global_var = "全局变量"

def outer():

    outer_var = "外部函数变量"

    def inner():

        inner_var = "内部函数变量"

        print(inner_var)  # 本地作用域

        print(outer_var)  # 外部函数作用域

        print(global_var)  # 全局作用域

        print(len)  # 内置作用域

    inner()

outer()
    1. Python 查找变量时遵循 LEGB 规则:Local → Enclosing → Global → Built-in;
    2. 闭包中的变量查找会访问外部函数的命名空间。
  1. 闭包的作用域问题:
def create_counter():

    count = 0

    def counter():

        nonlocal count

        count += 1

        return count

    return counter

c1 = create_counter()

print(c1())  # 输出:1

print(c1())  # 输出:2

# 循环中创建闭包的问题

functions = []

for i in range(3):

    functions.append(lambda: i)

for f in functions:

    print(f())  # 输出:2, 2, 2(所有闭包共享同一个i)

# 解决方案:使用默认参数捕获当前值

functions = []

for i in range(3):

    functions.append(lambda x=i: x)

for f in functions:

    print(f())  # 输出:0, 1, 2
    1. 闭包中的变量在外部函数返回后仍然存在;
    2. 循环中创建闭包时,可能共享同一变量。

8.2 Python 迭代器

核心内容:迭代器是实现了__iter__()__next__()方法的对象,可以逐个访问集合中的元素。

难点赘述:迭代器的创建、使用和终止条件。

  1. 迭代器协议:
class MyIterator:

    def __init__(self, data):

        self.data = data

        self.index = 0

    def __iter__(self):

        return self

    def __next__(self):

        if self.index >= len(self.data):

            raise StopIteration

        value = self.data[self.index]

        self.index += 1

        return value

# 使用迭代器

it = MyIterator([1, 2, 3, 4, 5])

print(next(it))  # 输出:1

print(next(it))  # 输出:2

print(next(it))  # 输出:3

print(next(it))  # 输出:4

print(next(it))  # 输出:5

# print(next(it))  # 抛出StopIteration异常
    1. 迭代器对象必须实现__iter__()方法,返回迭代器自身;
    2. 必须实现__next__()方法,返回下一个元素,无元素时抛出StopIteration异常。
  1. 可迭代对象与迭代器:
# 列表是可迭代对象

my_list = [1, 2, 3]

it = iter(my_list)  # 获取迭代器

print(next(it))  # 输出:1

print(next(it))  # 输出:2

print(next(it))  # 输出:3
    1. 可迭代对象是实现了__iter__()方法的对象,可以生成迭代器;
    2. 迭代器是可迭代对象的具体实现。
  1. 迭代器的应用场景:
# 惰性生成斐波那契数列

class FibonacciIterator:

    def __init__(self, max_num):

        self.max_num = max_num

        self.prev = 0

        self.curr = 1

    def __iter__(self):

        return self

    def __next__(self):

        if self.curr > self.max_num:

            raise StopIteration

        value = self.curr

        self.prev, self.curr = self.curr, self.prev + self.curr

        return value

fib = FibonacciIterator(100)

for num in fib:

    print(num, end=" ")  # 输出:1 1 2 3 5 8 13 21 34 55 89
    1. 自定义数据结构的遍历;
    2. 惰性计算(按需生成元素);
    3. 内存高效的数据处理。

8.3 Python 生成器

核心内容:生成器是一种特殊的迭代器,使用yield语句生成值,简化迭代器的创建。

难点赘述:生成器表达式、生成器函数和生成器的状态管理。

  1. 生成器函数:
def my_generator():

    yield 1

    yield 2

    yield 3

gen = my_generator()

print(next(gen))  # 输出:1

print(next(gen))  # 输出:2

print(next(gen))  # 输出:3

# print(next(gen))  # 抛出StopIteration异常
    1. 使用yield语句返回值,函数会暂停执行并保存状态;
    2. 再次调用时从暂停处继续执行。
  1. 生成器表达式:
# 生成器表达式

gen = (x**2 for x in range(1, 6))

print(next(gen))  # 输出:1

print(next(gen))  # 输出:4

print(next(gen))  # 输出:9

print(next(gen))  # 输出:16

print(next(gen))  # 输出:25
    1. 简洁的生成器创建方式,类似于列表推导式;
    2. 使用圆括号而非方括号。
  1. 生成器的应用场景:
# 生成无限序列(如斐波那契数列)

def fibonacci():

    a, b = 0, 1

    while True:

        yield b

        a, b = b, a + b

gen = fibonacci()

for _ in range(10):

    print(next(gen), end=" ")  # 输出:1 1 2 3 5 8 13 21 34 55

# 处理大文件

def read_large_file(filepath):

    with open(filepath, "r") as f:

        for line in f:

            yield line.strip()

for line in read_large_file("large_file.txt"):

    process(line)  # 处理每一行,内存高效

    1. 惰性计算大数据集;
    2. 无限序列的生成;
    3. 内存高效的数据处理。
  1. 生成器的状态和控制:

def counter():

    count = 0

    while True:

        command = yield count

        if command == "inc":

            count += 1

        elif command == "dec":

            count -= 1

        elif command == "reset":

            count = 0

gen = counter()

print(next(gen))  # 输出:0

print(gen.send("inc"))  # 输出:1

print(gen.send("inc"))  # 输出:2

print(gen.send("dec"))  # 输出:1

print(gen.send("reset"))  # 输出:0

gen.close()
    1. send()方法可以向生成器发送值;
    2. throw()方法可以在生成器中抛出异常;
    3. close()方法可以关闭生成器。

8.4 Python 闭包

核心内容:闭包是函数和其所在环境的组合,允许函数访问和修改外部函数的变量。

难点赘述:闭包的创建、作用域问题和应用场景。

  1. 闭包的定义:
def outer(x):

    def inner(y):

        return x + y

    return inner

add_5 = outer(5)

print(add_5(3))  # 输出:8

print(add_5(5))  # 输出:10
    1. 闭包由内部函数和其引用的外部函数变量组成;
    2. 内部函数在外部函数返回后仍然可以访问外部函数的变量。
  1. 闭包的作用域问题:
def counter():

    count = 0

    def increment():

        nonlocal count  # 声明使用外部函数的变量

        count += 1

        return count

    return increment

c = counter()

print(c())  # 输出:1

print(c())  # 输出:2

print(c())  # 输出:3
    1. 闭包中的变量在外部函数返回后仍然存在;
    2. 闭包中的变量是不可变对象时,无法直接修改;
    3. 使用nonlocal关键字声明变量为非局部变量。
  1. 闭包的应用场景:
# 工厂函数示例

def make_multiplier(factor):

    def multiplier(x):

        return x * factor

    return multiplier

double = make_multiplier(2)

triple = make_multiplier(3)

print(double(5))  # 输出:10

print(triple(5))  # 输出:15

# 数据封装示例

def bank_account(initial_balance):

    balance = initial_balance

    def deposit(amount):

        nonlocal balance

        balance += amount

        return balance

    def withdraw(amount):

        nonlocal balance

        if amount > balance:

            return "余额不足"

        balance -= amount

        return balance

    return {"deposit": deposit, "withdraw": withdraw}

account = bank_account(1000)

print(account["deposit"](500))  # 输出:1500

print(account["withdraw"](200))  # 输出:1300

print(account["withdraw"](2000))  # 输出:余额不足
    1. 创建工厂函数(动态生成函数);
    2. 实现装饰器;
    3. 数据封装和状态保持。
  1. 闭包与装饰器的关系:
def decorator(func):

    def wrapper():

        print("装饰器执行前")

        func()

        print("装饰器执行后")

    return wrapper

@decorator

def greet():

    print("你好,世界!")

greet()  # 输出:装饰器执行前,你好,世界!,装饰器执行后
    1. 装饰器本质上是闭包的应用;
    2. 装饰器函数返回一个新的函数,该函数引用了装饰器的参数和原始函数。

8.5 Python 装饰器

核心内容:装饰器是一种特殊的闭包,用于修改函数或类的行为,而无需直接修改其源代码。

难点赘述:装饰器的定义、带参数的装饰器和类装饰器。

  1. 基本装饰器:
def decorator(func):

    def wrapper():

        print("执行前")

        func()

        print("执行后")

    return wrapper

@decorator

def greet():

    print("你好,世界!")

greet()  # 输出:执行前,你好,世界!,执行后
    1. 装饰器函数接收被装饰的函数作为参数,并返回一个新的函数;
    2. 使用@语法糖应用装饰器。
  1. 带参数的装饰器:
def repeat(n):

    def decorator(func):

        def wrapper(*args, **kwargs):

            for _ in range(n):

                func(*args, **kwargs)

        return wrapper

    return decorator

@repeat(3)

def say_hello():

    print("Hello!")

say_hello()  # 输出:Hello!三次
    1. 装饰器工厂函数返回实际的装饰器;
    2. 可以传递参数给装饰器。
  1. 类装饰器:
class CountCalls:

    def __init__(self, func):

        self.func = func

        self.count = 0

    def __call__(self, *args, **kwargs):

        self.count += 1

        print(f"函数被调用了{self.count}次")

        return self.func(*args, **kwargs)

@CountCalls

def greet():

    print("你好!")

greet()  # 输出:函数被调用了1次,你好!

greet()  # 输出:函数被调用了2次,你好!

greet()  # 输出:函数被调用了3次,你好!
    1. 使用类作为装饰器,实现__call__方法;
    2. 类装饰器可以保持状态。
  1. 装饰器的应用场景:
# 日志记录装饰器

def log_execution(func):

    def wrapper(*args, **kwargs):

        print(f"执行函数:{func.__name__}")

        result = func(*args, **kwargs)

        print(f"函数{func.__name__}执行完毕,结果:{result}")

        return result

    return wrapper

@log_execution

def add(a, b):

    return a + b

print(add(3, 5))  # 输出:执行函数:add,函数add执行完毕,结果:8,8

# 性能分析装饰器

import time

def measure_time(func):

    def wrapper(*args, **kwargs):

        start = time.perf_counter()

        result = func(*args, **kwargs)

        end = time.perf_counter()

        print(f"{func.__name__}执行时间:{end - start:.4f}秒")

        return result

    return wrapper

@measure_time

def heavy_task():

    time.sleep(1)

heavy_task()  # 输出:heavy_task执行时间:1.000x秒
    1. 日志记录;
    2. 性能分析;
    3. 权限验证;
    4. 缓存;
    5. 输入验证。
  1. 装饰器的最佳实践:
from functools import wraps

def decorator(func):

    @wraps(func)

    def wrapper(*args, **kwargs):

        """包装器函数文档字符串"""

        print("执行前")

        result = func(*args, **kwargs)

        print("执行后")

        return result

    return wrapper

@decorator

def greet():

    """被装饰函数文档字符串"""

    print("你好,世界!")

print(greet.__name__)  # 输出:greet(而不是wrapper)

print(greet.__doc__)  # 输出:被装饰函数文档字符串
    1. 使用functools.wraps装饰器保留被装饰函数的元数据;
    2. 为装饰器提供清晰的文档字符串;
    3. 避免过度使用装饰器,保持代码简洁。

8.6 Python @property

核心内容@property装饰器将类的方法转换为属性,允许像访问属性一样调用方法。

难点赘述@property的使用、setterdeleter的定义。

  1. 基本用法:
class Circle:

    def __init__(self, radius):

        self._radius = radius

    @property

    def radius(self):

        return self._radius

    @property

    def area(self):

        return 3.14159 * self._radius ** 2

c = Circle(5)

print(c.radius)  # 输出:5

print(c.area)  # 输出:78.53975

# c.area = 100  # 报错:can't set attribute 'area'
    1. 将方法转换为只读属性;
    2. 使用@property装饰器。
  1. setterdeleter方法:
class Person:

    def __init__(self, name):

        self._name = name

    @property

    def name(self):

        return self._name

    @name.setter

    def name(self, value):

        if not isinstance(value, str):

            raise TypeError("姓名必须是字符串")

        self._name = value

    @name.deleter

    def name(self):

        del self._name

p = Person("Alice")

print(p.name)  # 输出:Alice

p.name = "Bob"

print(p.name)  # 输出:Bob

# p.name = 123  # 抛出TypeError异常

del p.name

# print(p.name)  # 抛出AttributeError异常
    1. 使用@属性名.setter装饰器定义设置方法;
    2. 使用@属性名.deleter装饰器定义删除方法。
  1. 计算属性的应用场景:
class Rectangle:

    def __init__(self, width, height):

        self._width = width

        self._height = height

    @property

    def width(self):

        return self._width

    @width.setter

    def width(self, value):

        if value <= 0:

            raise ValueError("宽度必须为正数")

        self._width = value

    @property

    def height(self):

        return self._height

    @height.setter

    def height(self, value):

        if value <= 0:

            raise ValueError("高度必须为正数")

        self._height = value

    @property

    def area(self):

        return self._width * self._height

r = Rectangle(5, 3)

print(r.area)  # 输出:15

r.width = 6

r.height = 4

print(r.area)  # 输出:24
    1. 隐藏实现细节;
    2. 数据验证;
    3. 延迟计算;
    4. 兼容性维护。
  1. @property__getattr__的区别:
class DynamicAttributes:

    def __init__(self):

        self._data = {}

    def __getattr__(self, name):

        return self._data.get(name, None)

    def __setattr__(self, name, value):

        if name == "_data":

            super().__setattr__(name, value)

        else:

            self._data[name] = value

obj = DynamicAttributes()

obj.x = 10

obj.y = 20

print(obj.x)  # 输出:10

print(obj.z)  # 输出:None
    1. @property用于特定属性的访问控制;
    2. __getattr__用于动态处理不存在的属性。

8.7 Python 正则表达式 (RegEx)

核心内容:正则表达式是用于匹配和操作字符串的强大工具,Python 通过re模块提供支持。

难点赘述:正则表达式的语法、匹配模式和高级应用。

  1. 基本匹配:
import re

s = "Hello, World!"

# 匹配开头

if re.match("Hello", s):

    print("匹配成功")  # 输出:匹配成功

# 搜索子串

if re.search("World", s):

    print("找到World")  # 输出:找到World

# 查找所有数字

s = "abc123def456"

numbers = re.findall(r"\d+", s)

print(numbers)  # 输出:["123", "456"]

# 替换子串

s = "Hello, World!"

new_s = re.sub("World", "Python", s)

print(new_s)  # 输出:Hello, Python!
    1. re.match():从字符串开头匹配;
    2. re.search():在字符串中查找匹配项;
    3. re.findall():查找所有匹配项;
    4. re.sub():替换匹配的字符串。
  1. 正则表达式语法:
# 匹配邮箱地址

email_pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"

print(re.match(email_pattern, "user@example.com"))  # 匹配成功

print(re.match(email_pattern, "user@example"))  # 匹配失败

# 匹配电话号码

phone_pattern = r"^(\+?\d{1,3}[-.\s]?)?(\(\d{3}\)|\d{3})[-.\s]?\d{3}[-.\s]?\d{4}$"

print(re.match(phone_pattern, "+1 (123) 456-7890"))  # 匹配成功

print(re.match(phone_pattern, "123-456-7890"))  # 匹配成功
    1. 元字符:.^$*+?{}[]()|
    2. 字符类:\d\w\s[a-z][^0-9]
    3. 量词:*+?{n}{n,}{n,m}
    4. 分组和捕获:(...)(?P<name>...)
  1. 匹配模式:
s = """Hello,

World!

Python is fun!"""

# 匹配以大写字母开头的单词(忽略大小写)

pattern = r"\b[A-Z]\w+\b"

print(re.findall(pattern, s, re.I))  # 输出:["Hello", "World", "Python"]

# 匹配所有行的开头和结尾

pattern = r"^Hello|World!$"

print(re.findall(pattern, s, re.M))  # 输出:["Hello", "World!"]

# 点匹配包括换行符

pattern = r".+"

print(re.match(pattern, s, re.S).group())  # 输出整个字符串

# 详细模式

pattern = r"""

    ^(\+?\d{1,3})?  # 可选的国家代码

    [-.\s]?         # 可选的分隔符

    (\(\d{3}\)|\d{3})  # 区号

    [-.\s]?         # 可选的分隔符

    \d{3}           # 中间三位

    [-.\s]?         # 可选的分隔符

    \d{4}$          # 最后四位

"""

print(re.match(pattern, "+1-123-456-7890", re.X))  # 匹配成功
    1. re.I:忽略大小写;
    2. re.M:多行模式;
    3. re.S:点匹配包括换行符;
    4. re.X:详细模式(允许注释和空格)。
  1. 高级应用:
# 匹配重复的单词

pattern = r"\b(\w+)\s+\1\b"

s = "hello hello world"

print(re.findall(pattern, s))  # 输出:["hello"]

# 匹配HTML标签

pattern = r"<(\w+)>(.*?)</\1>"

s = "<h1>标题</h1>"

print(re.match(pattern, s).groups())  # 输出:("h1", "标题")

# 前瞻断言

pattern = r"\d+(?=%)"  # 匹配后面跟着%的数字

s = "20% discount, 10% off"

print(re.findall(pattern, s))  # 输出:["20", "10"]

# 命名分组

pattern = r"(?P<name>\w+), (?P<age>\d+)"

s = "Alice, 30"

match = re.match(pattern, s)

print(match.group("name"))  # 输出:Alice

print(match.group("age"))  # 输出:30
    1. 后向引用:\1\2等;
    2. 前瞻和后顾断言;
    3. 命名分组:(?P<name>...)

8.8 Python 随机模块 (Random)

核心内容random模块提供了生成伪随机数的函数,用于随机选择和分布。

难点赘述:随机数的生成、种子设置和不同分布的应用。

  1. 基本随机函数:
import random

# 生成随机浮点数

print(random.random())  # 输出:0.123456789...(每次不同)

# 生成随机整数

print(random.randint(1, 10))  # 输出:1到10之间的整数

# 随机选择元素

fruits = ["apple", "banana", "cherry"]

print(random.choice(fruits))  # 输出:随机一个水果

# 打乱序列

numbers = [1, 2, 3, 4, 5]

random.shuffle(numbers)

print(numbers)  # 输出:打乱后的列表
    1. random():生成 0 到 1 之间的随机浮点数;
    2. randint(a, b):生成 [a, b] 之间的随机整数;
    3. choice(seq):从序列中随机选择一个元素;
    4. shuffle(seq):随机打乱序列。
  1. 随机种子:
import random

# 设置种子,确保每次生成相同的随机数序列

random.seed(42)

print(random.random())  # 输出:0.6394267984578837

print(random.randint(1, 10))  # 输出:14(因为seed(42)的randint范围可能不同)

# 不同种子生成不同的序列

random.seed(100)

print(random.random())  # 输出:0.7357088787345654
    1. seed()函数设置随机数生成器的种子,确保可复现的随机序列。
  1. 分布函数:
import random

# 均匀分布

print(random.uniform(1, 10))  # 输出:1到10之间的随机浮点数

# 正态分布

print(random.normalvariate(0, 1))  # 输出:均值为0,标准差为1的随机数

# 指数分布

print(random.expovariate(1))  # 输出:λ=1的指数分布随机数
    1. uniform(a, b):均匀分布;
    2. normalvariate(mu, sigma):正态分布;
    3. expovariate(lambd):指数分布;
    4. gammavariate(alpha, beta):伽马分布。
  1. 随机采样和排列:
import random

# 随机采样

population = range(1, 101)

sample = random.sample(population, 10)

print(sample)  # 输出:10个不同的随机数

# 按权重选择

fruits = ["apple", "banana", "cherry"]

weights = [0.1, 0.3, 0.6]

print(random.choices(fruits, weights=weights, k=5))  # 输出:可能多次选择cherry
    1. sample(population, k):从总体中随机采样 k 个元素;
    2. choices(population, weights=None, k=1):按权重随机选择。

8.9 Python 数学模块 (Math)

核心内容math模块提供了数学函数和常量,用于数值计算。

难点赘述:数学函数的应用、精度问题和特殊函数的使用。

  1. 数学常量:
import math

print(math.pi)  # 输出:3.141592653589793

print(math.e)  # 输出:2.718281828459045

print(math.inf)  # 输出:inf

print(math.nan)  # 输出:nan
    1. math.pi:圆周率 π;
    2. math.e:自然对数的底 e;
    3. math.inf:无穷大;
    4. math.nan:非数字(NaN)。
  1. 数值运算函数:
import math

# 三角函数

print(math.sin(math.pi / 2))  # 输出:1.0

print(math.cos(math.pi))  # 输出:-1.0

print(math.tan(math.pi / 4))  # 输出:1.0

# 指数和对数

print(math.exp(1))  # 输出:2.718281828459045

print(math.log(math.e))  # 输出:1.0

print(math.log10(100))  # 输出:2.0

# 幂和根

print(math.pow(2, 3))  # 输出:8.0

print(math.sqrt(25))  # 输出:5.0

# 取整

print(math.ceil(3.14))  # 输出:4

print(math.floor(3.99))  # 输出:3

print(round(3.5))  # 输出:4
    1. 三角函数:sin()cos()tan()asin()acos()atan()
    2. 指数和对数:exp()log()log10()
    3. 幂和根:pow()sqrt()
    4. 取整:ceil()floor()round()
    5. 绝对值:abs()
  1. 特殊函数:
import math

# 阶乘

print(math.factorial(5))  # 输出:120

# 组合数

print(math.comb(5, 2))  # 输出:10

print(math.perm(5, 2))  # 输出:20

# 双曲函数

print(math.sinh(0))  # 输出:0.0

print(math.cosh(0))  # 输出:1.0
    1. 阶乘:math.factorial()
    2. 组合数:math.comb()math.perm()
    3. 双曲函数:sinh()cosh()tanh()
    4. 误差函数:erf()erfc()

更多推荐