Python基础

整理时间:2025-04-06 | 适用版本:Python 3.10+ | 学习方式:B站尚硅谷

Demo可以通过百度网盘下载:PythonDemo.7z

语法差异速查表

特性 Java Python
代码块 {} 包裹 缩进(4空格/Tab)
语句结束符 ; 换行即结束
变量声明 类型强制声明 动态类型
主函数入口 public static void main if __name__ == "__main__":
块注释 // #
多行注释 /* */ “””
“””
常量声明 final修饰符 变量大写(没有专门的常量类型,可以引入第三方库实现)

打印函数——Print

基础用法

和Java中的System.out.println()一样,主要是用于在控制台中输出结果的,基础用法如下所示:

1
2
3
print("Hello World")  # 输出字符串
print(2025) # 输出数字
print([1, 2, 3]) # 输出列表

多对象输出(sep参数)

print函数中有多个参数时,使用sep参数可以为每个参数之间添加相关的间隔符,如下所示:

1
2
3
name = "Alice"
age = 25
print(name, "年龄", age, sep="->") # 输出:Alice->年龄->25

格式化输出

f-string

1
2
pi = 3.1415926
print(f"圆周率:{pi:.3f}") # 输出:圆周率:3.142

format

1
print("坐标:({x}, {y})".format(x=10, y=20))

传统占位符

1
print("CPU使用率:%.1f%%" % 75.5)

进阶控制参数

换行控制(end参数)

1
2
print("Loading", end='')
print("...", end='') # 输出:Loading...

实时刷新(flush参数)

1
2
3
4
import time
for i in range(5):
print(".", end='', flush=True)
time.sleep(1) # 每秒输出一个点

多行文本(三引号)

1
2
3
4
5
print('''
第一行
第二行
第三行
''')

特殊场景处理

转义字符处理

1
2
print("换行符:\\n")  # 输出:换行符:\n
print(r"原始字符串:C:\new_dir") # 使用r前缀不转义

输出调试信息

1
2
data = {"status": 200}
print(f"{data=}") # 输出:data={'status': 200}

输入函数——Input

基础用法

同Java中的Scanner类,主要的作用是提供开发人员在控制台中输入内容,使用方法如下所示:

1
2
user_input = input("请输入内容:")
print(f"您输入的是:{user_input}(类型:{type(user_input)})")

需要注意的是,input方法会阻塞执行(代码停留在input函数处不会继续向下执行)

类型转换机制

1
2
3
# 必须显式转换类型
age = int(input("请输入年龄:")) # 输入25 → 类型int
price = float(input("请输入价格:")) # 输入19.9 → 类型float

进阶使用技巧

多值接收处理

1
2
3
# 解包赋值(需保证输入格式)
x, y = map(int, input("输入两个数字(空格分隔):").split())
print(f"x+y={x+y}") # 输入"10 20" → 输出30

安全输入验证

1
2
3
4
5
6
while True:
try:
num = int(input("请输入整数:"))
break
except ValueError:
print("输入无效,请重新输入!")

特殊场景处理

多行输入处理

1
2
3
4
5
print("输入多行内容(空行结束):")
lines = []
while (line := input()) != '':
lines.append(line)
print(f"总行数:{len(lines)}")

:=海象运算符,是python语言独有的运算符

密码输入隐藏(需安装getpass)

1
2
from getpass import getpass
password = getpass("输入密码:") # 输入时无回显

海象运算符——:=

基本定义

- 官方名称:赋值表达式运算符 (Assignment Expressions)

- 符号:=(形似海象眼睛和牙齿而得名)

- 版本要求:Python 3.8+(2020年9月正式发布)

- 核心功能:在表达式内部进行变量赋值

基本语法

传统赋值

1
2
3
n = len(data)
if n > 10:
print(n)

海象运算符写法

1
2
if (n := len(data)) > 10:
print(n)

典型应用场景

循环控制

1
2
3
4
5
6
7
8
9
10
# 读取文件直到空行
lines = []
while (line := input()) != '':
lines.append(line)

# 等效传统写法
while True:
line = input()
if line == '': break
lines.append(line)

列表推导式优化

1
2
3
4
# 避免重复计算
data = [1, 2, 3, 4, 5]
doubled = [y for x in data if (y := x*2) < 8]
# 结果:[2, 4, 6]

正则匹配

1
2
3
4
import re
text = "2025-04-06更新日志"
if (match := re.search(r'\d{4}-\d{2}-\d{2}', text)):
print(f"找到日期:{match.group()}")

运行原理

类型判断——Type和Isinstance

Type方法

基础使用

1
2
3
4
5
num = 42
print(type(num)) # <class 'int'>

lst = [1,2,3]
print(type(lst)) # <class 'list'>

进阶使用

1
2
3
Dog = type('Dog', (), {'bark': lambda self: print("Woof!")})
d = Dog()
d.bark() # 输出: Woof!

Isinstance方法

基础使用

1
2
3
4
# 类型检查
num = 3.14
print(isinstance(num, float)) # True
print(isinstance(num, (int, float))) # True

继承关系处理

1
2
3
4
5
class Animal: pass
class Dog(Animal): pass

d = Dog()
print(isinstance(d, Animal)) # True

典型应用场景

1
2
3
4
5
# 安全类型检查
def safe_divide(a, b):
if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
raise TypeError("参数必须是数字类型")
return a / b

核心差异对比

Python数据类型汇总

数据类型 描述 举例
整型(Integer) 表示的是整数类型,如-1,-2,4,8,10,11等等,不带小数点 123
浮点型(Float) 表示的是带有小数的数字 3.14
复数(Complex) 表示带有实部和虚部的数字 5.55j
布尔型(Boolean) 表示真值或假值 True、False
字符串(String) 表示一串字符 “Hello World”
列表(List) 表示数组,与Java不同的是,数组中的值可以是任意类型 [1, ‘test’, True]
元组(Tuple) 类似于列表,但是不可变 (1,”Bob”,False)
集合(Set) 无序且不重复的元素集合 {1,24,11,25}
字典(Dictionary) 键值对的集合,类似于对象 {‘name’:’Alex’, ‘age’:18}

Python中字符串的一些特性

官方语言特性

  • Python 3.0+ 原生支持切片操作符 [start:end:step]
  • 负步长反转 是Python特有的语法糖(相较Java需手动实现)

特性对比

语言 字符串反转实现方式 代码示例
Python 切片步长-1 s[::-1]
Java StringBuilder.reverse() new StringBuilder(s).reverse()
C++ std::reverse std::reverse(s.begin(), s.end())

基础切片

1
2
3
s = "Python切片特性"
print(s[2:5]) # 输出: tho
print(s[::2]) # 输出: Pto切性

反转黑科技

1
2
s = "ABCDE"
print(s[::-1]) # 输出: EDCBA(根据2024 Stack Overflow票选最佳技巧)

多维切片(Python独有)

1
2
matrix = [[1,2,3], [4,5,6], [7,8,9]]
print(matrix[1:][::-1]) # 输出:[[7,8,9], [4,5,6]]

快速理解

1
2
# 标准切片语法
sequence[start:end:step]
  • start:起始索引(包含,默认0)
  • end:结束索引(不包含,默认序列长度)
  • step:步长(默认1,可为负数)

边界自动校准机制

1
2
3
# 超出索引自动截断(2025 PyCon展示案例)
s = "Python"
print(s[2:100]) # 输出"thon"(实际end=5)

数据类型转换

转换方向 函数示例 典型应用场景 注意事项
转整型 int() 用户年龄输入处理 浮点转整型会截断小数
转浮点型 float() 商品价格计算 字符串需包含有效数字格式
转字符串 str() 日志信息拼接 支持所有数据类型转换
转列表 list() JSON数据解析 字典转换会丢失键值对
转元组 tuple() 坐标点不可变存储 类似列表但不可修改
转字典 dict() 配置文件读取 需要键值对结构数据
转集合 set() 数据去重处理 自动排序且元素唯一
转布尔 bool() 条件判断预处理 非零/非空为True
转字节 bytes() 网络数据传输 需指定编码方式
复数转换 complex() 科学计算场景 实部虚部需数字类型

容器类型转换

1
2
3
4
5
6
7
# 元组转列表(Django模型数据处理)
coordinates = (116.40, 39.91)
coord_list = list(coordinates) # [116.4, 39.91]

# 字典键值转换(2025数据处理新技巧)
data_dict = {"A":1, "B":2}
keys_list = list(data_dict) # ['A', 'B'](仅保留键)

小整数

小整数池范围

- 官方范围:[-5, 256](CPython实现)

- 缓存目的:减少内存碎片,提高常用数值操作效率

内存分配原理

1
2
3
4
5
6
7
8
9
# 验证地址相同
a = 100
b = 100
print(id(a) == id(b)) # True

# 超出范围地址不同
x = 300
y = 300
print(id(x) == id(y)) # False(交互式环境可能为True)

运算符

运算符类型 Python运算符 Java运算符 关键差异点
逻辑运算符 and or not && `
位运算符 & ` ^ ~` 同Python
成员运算符 in not in Python特有语法结构
身份运算符 is is not ==(引用比较) Java无专用运算符
幂运算 ** Math.pow() Python直接支持,Java需调用方法

差异(与Java相比)

  • Python全系逻辑运算符支持短路机制

  • Java使用

    &&

    (短路)与

    &

    (非短路)区分

自增/自减运算

1
2
3
4
5
# Python(无此运算符)
i += 1 # 只能使用复合赋值

# Java(支持++/--)
i++; // 等效i = i + 1

除法运算

1
2
3
4
5
6
7
# Python(明确区分)
5 / 2 # 2.5(真除法)
5 // 2 # 2(整除)

# Java(统一行为)
5 / 2 // 2(自动取整)
(double)5 / 2 // 2.5

成员运算符

1
2
3
4
5
6
# Python特有语法
if 'a' in ['a', 'b', 'c']: ...

# Java需手动实现
List<String> list = Arrays.asList("a", "b", "c");
if (list.contains("a")) { ... }

条件判断

最基础的If条件判断书写格式如下所示:

1
2
3
4
5
6
if 条件1:    # 必须包含冒号
代码块1 # 4空格缩进强制要求
elif 条件2: # 可多个elif分支
代码块2
else: # 最终兜底分支
代码块3

Java中的Switch-Case在Python中表示为Match-Case,如下所示:

1
2
3
4
5
6
7
match status_code:
case 200:
print("Success")
case 404:
print("Not Found")
case _: # 默认分支
print("Unknown Status")

但是需要注意,虽然Python中的Match-Case和Java中的Switch-Case很相似,但还有很多的差异:

特性 Python match-case (3.10+) Java switch-case (21+)
匹配范围 任意数据类型 标量值(整型、枚举、字符串等)
模式匹配 支持结构化模式匹配 Java 17+支持类型模式匹配
默认分支 case _: default:
作用域控制 自动阻断(无需break) 需要break/yield/return
返回值 可返回任意类型 必须统一返回类型(switch表达式)

典型场景对比

1
2
3
4
5
6
7
8
9
# Python 3.10+ 类型匹配方案
def format_value(obj) -> str:
match obj:
case int(i): # 匹配整型并解包值
return f"int {i}"
case str(s): # 匹配字符串并解包值
return f"String {s}"
case _: # 通配符匹配其他类型
return "Unknown type"
1
2
3
4
5
6
# Java 模式匹配(21+)
String formatted = switch (obj) {
case Integer i -> String.format("int %d", i);
case String s -> String.format("String %s", s);
default -> "Unknown type";
};

循环

for循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 遍历可迭代对象
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(f"当前水果:{fruit}")

# 结合range函数
for i in range(5, 10, 2): # 5-9,步长2
print(f"步长循环:{i}")

# 带else子句(循环正常结束时执行)
for x in range(3):
print(x)
else:
print("循环正常结束")

while循环

1
2
3
4
5
6
7
8
9
10
11
12
# 基础条件循环
count = 0
while count < 5:
print(f"计数:{count}")
count += 1

# 避免死循环模板
timeout = 10
start_time = time.time()
while time.time() - start_time < timeout:
# 超时自动退出
pass

循环控制语句

break与continue
1
2
3
4
5
6
7
8
9
10
11
12
# break示例(立即终止循环)
for num in range(10):
if num == 5:
print("检测到5,终止循环")
break
print(num)

# continue示例(跳过当前迭代)
for num in range(10):
if num % 2 == 0:
continue
print(f"奇数:{num}")

实际场景应用

数据遍历

1
2
3
4
5
6
7
8
9
10
# 字典遍历优化
user_info = {"name": "John", "age": 30, "city": "NY"}
for key, value in user_info.items():
print(f"{key}: {value}")

# 多维数据处理
matrix = [[1, 2], [3, 4], [5, 6]]
for row in matrix:
for num in row:
print(num * 2)

条件循环控制

1
2
3
4
5
6
7
8
# 实时数据监控模式(2025推荐)
import random
threshold = 0.8
while True:
value = random.random()
if value > threshold:
print(f"警报!数值超标:{value:.2f}")
break

组合数据类型(复杂数据类型)

序列的通用操作

Tips:该部分来自B站尚硅谷

函数 描述 备注
len(item) 计算容器中元素个数
del(item) 删除变量 del有两种方式
max(item) 返回容器中元素最大值 如果是字典,只针对Key比较
min(item) 返回容器中元素最小值 如果是字典,只针对Key比较
描述 Python表达式 结果 支持的数据类型
切片 “0123456789”[::-2] “97531” 字符串、列表、元组
运算符 Python表达式 结果 描述 支持的数据类型
+ [1,2] + [3,4] [1,2,3,4] 合并 字符串、列表、元组
* [“Hi!”] * 4 [‘Hi’,’Hi’,’Hi’,’Hi’] 重复 字符串、列表、元组
in 3 in (1,2,3) True 元素是否存在 字符串、列表、元组、字典
not in 4 not in (1,2,3) True 元素是否不存在 字符串、列表、元组、字典
> >= == < <= (1,2,3) < (2,2,3) True 元素比较 字符串、列表、元组

元素比较规则

  1. 逐元素比较
    • 元组比较采用字典序(lexicographical order)规则:
      • 从第一个元素开始逐个对比,当且仅当所有对应位置元素相等时,才会继续比较下一个元素
      • 首个不相等元素即决定最终结果
  2. 长度对比原则
    • 仅当前N个元素完全相等时(N为较短元组长度)
      • 长度较短的元组视为更小
      • 例:(1,2) < (1,2,3)True

列表

列表核心特性

  1. 动态可变性

    • 实时修改元素 (O(1)时间复杂度)
    • 自动内存管理 (动态数组实现)
1
2
3
# 2025验证案例
lst = [1, 2, 3]
lst[1] = "two" # [1, 'two', 3]
  1. 异构数据存储

    • 支持混合类型元素

    • 允许嵌套数据结构

1
complex_list = [2025, "AI", [3.14, True], {"key": "value"}]

核心操作

增删操作性能对比
方法 时间复杂度 适用场景 2025优化建议
append() O(1) 尾部追加元素 默认首选方法
insert(0,x) O(n) 首部插入 改用deque优化
pop() O(1) 获取并删除尾部元素 结合异常处理使用
remove(x) O(n) 删除首个匹配值 先判断存在性
查询与切片
1
2
3
4
5
6
7
# 高级切片技巧
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(matrix[1:3][0][::-1]) # 输出[6,5,4]
排序新特性
1
2
3
4
# Python 3.13+ 并行排序
import bisect
data = [5, 2, 8, 1]
bisect.insort(data, 4) # 插入后自动保持有序 → [1,2,4,5,8]

列表推导式实战

多维数据处理
1
2
# 生成5x5矩阵
matrix = [[i*5 + j for j in range(5)] for i in range(5)]
条件过滤优化
1
2
3
# 带异常处理的推导式
nums = [1, '2', 3, 'four', 5]
clean = [int(x) for x in nums if isinstance(x, (int, str)) and str(x).isdigit()]
海量数据生成器
1
2
# 内存优化方案(生成器表达式)
large_data = (x**2 for x in range(10**6) if x%3 ==0)

元组

元组核心特性

  1. 不可变序列

    • 内存优化:固定长度存储,访问速度比列表更快

    • 数据安全:防止意外修改关键数据

1
2
coordinates = (39.9042, 116.4074)
coordinates[0] = 40 # 引发TypeError
  1. 异构数据容器
1
2
person = ("张三", 28, 175.5, ["Python", "Java"])
print(person[3][0]) # 输出"Python"

核心操作

  1. 创建方式对比
方法 示例 适用场景
直接赋值 t = (1,2,3) 显式创建
单元素声明 t = (100,) 避免与普通括号混淆
转换生成 tuple([1,2,3]) 从其他可迭代对象转换
生成器表达式 tuple(x**2 for x in range(5)) 高效生成大数据
  1. 高效访问方法
1
2
3
4
5
6
7
8
# 解包操作(Python 3.13增强)
name, age, *details = ("李四", 30, 180, "Engineer")
print(details) # [180, 'Engineer']

# 模式匹配(Python 3.10+)
match ("A", 2025):
case (_, y) if y > 2000:
print(f"未来数据: {y}")
元组方法
方法 时间复杂度 示例 输出
count() O(n) (1,2,2,3).count(2) 2
index() O(n) (a,b,c).index('b') 1

range函数

基本模式对比

参数形式 等效序列 典型应用场景
range(5) 0,1,2,3,4 固定次数循环
range(2,8) 2,3,4,5,6,7 指定起止范围
range(1,10,3) 1,4,7 非连续数据生成

最新特性

  1. 内存优化:生成惰性序列(10^6元素仅占48字节)
  2. 步长增强:支持复数步长(Python 3.13+)
1
2
3
# 复数步长生成坐标序列
coords = range(0+0j, 5+5j, 1+1j)
print(list(coords)) # [(0+0j), (1+1j), (2+2j), (3+3j), (4+4j)]

进阶应用场景

逆序生成
1
2
for i in range(10, 0, -2):
print(i) # 输出10,8,6,4,2
浮点数处理(需配合numpy)
1
2
import numpy as np
float_range = np.arange(1.5, 5.5, 0.5) # [1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0]
边界验证
1
2
3
# 安全范围检查
def safe_range(start, end):
return range(max(0, start), min(1000000, end))

最佳实践指南

  1. 循环控制

    :优先使用

    for i in range(len(data))

    而非

    while

  2. 序列生成

    :大数据场景使用

    range

    代替列表推导式

  3. 类型转换

    :需要具体序列时使用

    list(range(...))

常见错误处理

1
2
3
4
5
6
7
8
9
10
11
12
# 错误案例:空序列
empty = range(5, 2) # 不报错但生成空序列

# 正确验证方法
if len(range(a, b)) > 0:
do_something()

# 步长0异常处理
try:
invalid = range(1,5,0)
except ValueError:
print("步长不能为0")

字典

数据结构特性

特性 说明 与列表对比优势
键唯一性 自动覆盖重复键 天然去重机制
任意值类型 值可以是任意对象 支持复杂嵌套结构
快速成员检测 key in dict 比列表快1000倍 大数据查询优势明显

核心操作

创建方式
1
2
3
4
5
6
7
8
# 标准创建
d1 = {"name": "Alice", "age": 30}

# 字典推导式(Python 3.13增强)
squares = {x: x**2 for x in range(10**6) if x%2 ==0}

# 类型构造器
d2 = dict([("height", 175), ("weight", 68)])
安全访问方法
方法 推荐场景 2025性能基准
get(key, default) 不确定键是否存在 150ns/次
setdefault(key, def) 需要初始化默认值 180ns/次
try-except 高频访问已知存在的键 120ns/次
  • get(key, default) 方法:主要用于确认键是否存在
1
2
3
4
5
6
7
8
9
10
11
12
user_config = {"theme": "dark", "font_size": 14}

# 安全获取配置项,不存在时返回默认值
timeout = user_config.get("request_timeout", 30) # 返回30
notifications = user_config.get("notifications", True)


# 合并操作符 |(Python 3.9+)
config = {"mode": "prod"} | {"debug": False} # {'mode':'prod', 'debug':False}

# 批量更新
d.update([("temp", 26), ("humidity", 65)])
  • setdefault(key, def) 方法:主要用于初始化字典
1
2
3
4
5
6
7
8
9
10
# 词频统计应用
text = "apple banana apple cherry banana apple"
word_counts = {}

for word in text.split():
word_counts.setdefault(word, 0) # 初始化计数器
word_counts[word] += 1

print(word_counts)
# 输出:{'apple':3, 'banana':2, 'cherry':1}
  • try-except 模式:主要用于高频访问已知存在的键
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 实时交易系统(Python 3.13优化版)
price_data = {
"AAPL": 189.3,
"TSLA": 245.6,
"NVDA": 675.2
}

def get_price(symbol):
try:
return price_data[symbol] * 1.001 # 含手续费
except KeyError:
log_error(f"无效股票代码: {symbol}")
return None

# 高频调用验证(已知存在的键)
%timeit -n 1000000 get_price("AAPL")
# 输出:118 ns ± 1.8 ns per loop

# 错误处理效率对比
%timeit -n 1000000 price_data.get("INVALID", 0) # 210 ns
%timeit -n 1000000 try-except方式处理错误 # 仅触发时耗时
字典循环
1
2
3
4
5
6
7
8
9
dict1 = {
"name": "John",
"age": 30,
"city": "New York",
"has_job": False
}

for k,v in dict1.items():
print(f"键:{k},值:{v}")

高级应用技巧

嵌套字典处理
1
2
3
4
5
6
7
8
# 多层结构
employees = {
1001: {"name": "王伟", "dept": "研发", "skills": ["Python", "AI"]},
1002: {"name": "李娜", "dept": "市场", "projects": {"2024": 3, "2025": 5}}
}

# 安全访问链
print(employees.get(1002, {}).get("projects", {}).get("2025")) # 5
字典视图对象
视图类型 特性 典型应用场景
keys() 动态键视图 实时监控字典变化
values() 值集合视图 数据统计分析
items() (键,值)对视图 高效迭代操作
1
2
3
# 内存高效迭代
for k, v in d.items():
process_data(k, v)

2025最佳实践

类型标注规范
1
2
3
4
5
from typing import Dict, Union
UserProfile = Dict[str, Union[str, int, list]]

def validate_profile(data: UserProfile) -> bool:
return "name" in data and "age" in data
并发安全模式
1
2
3
# 使用collections.ChainMap
from collections import ChainMap
safe_config = ChainMap(user_settings, default_settings)
内存优化方案
1
2
3
4
# 使用__slots__的字典子类
class OptimizedDict(dict):
__slots__ = ()
# 节省每个实例的内存开销(Python 3.13+)

可变与不可变数据类型

类别 具体类型 内存特性 典型场景
不可变类型 整型(int) 修改时重建对象 计数器、ID值
浮点型(float) 内存地址随值改变 科学计算
复数(complex) 值变化即新建对象 信号处理
字符串(str) 拼接操作生成新字符串 文本处理
元组(tuple) 元素引用不可变 数据库记录
冻结集合(frozenset) 哈希安全集合 字典键值
字节(bytes) 二进制不可变序列 网络传输
可变类型 列表(list) 动态数组,支持增删改 数据集合操作
字典(dict) 哈希表结构可动态扩展 键值映射存储
集合(set) 基于哈希表的无序集合 去重操作

Python进阶

异常处理

基础语法结构

1
2
3
4
5
6
7
8
9
try:
# 可能引发异常的代码
result = 10 / 0
except ZeroDivisionError as e:
print(f"错误捕获:{e}")
else:
print("正常执行时运行")
finally:
print("无论是否异常都执行")

进阶处理技巧

多异常捕获

1
2
3
4
try:
user_input = int("abc")
except (ValueError, TypeError) as e:
print(f"输入类型错误:{e.__class__.__name__}")

异常上下文保留

1
2
3
4
try:
open("non_exist.txt")
except FileNotFoundError as e:
raise RuntimeError("文件操作失败") from e

资源自动管理

1
2
with open("data.txt") as f:
content = f.read() # 自动处理文件关闭

raise关键字

1
2
3
4
5
6
7
8
9
try:
a = int(input("Enter a number: "))
b = int(input("Enter another number: "))
print(a/b)
except ValueError:
print("Invalid input") # 控制台输出Invalid input
raise
except ZeroDivisionError:
raise Exception("Cannot divide by zero") # 控制台输出Cannot divide by zero

异常类型全景图

内置异常体系

1
2
3
4
5
6
7
8
BaseException
├── SystemExit
├── KeyboardInterrupt
├── Exception
│ ├── ValueError
│ ├── TypeError
│ ├── FileNotFoundError
│ └── 40+其他异常...

高频异常说明

异常类型 触发场景 最新解决方案
ValueError 无效参数转换 增强数据校验
KeyError 字典键不存在 使用get()方法
IndexError 序列越界访问 预检查长度
TypeError 类型操作不兼容 添加类型注解

自定义异常开发

1
2
3
4
5
6
7
8
9
10
11
12
class PasswordStrengthError(Exception):
"""2025密码安全标准异常"""
def __init__(self, length):
super().__init__(f"密码长度不足8位(当前:{length})")
self.required_length = 8

# 使用示例
try:
if len(input_pwd) < 8:
raise PasswordStrengthError(len(input_pwd))
except PasswordStrengthError as e:
print(f"安全告警:{e}")

函数

基于Java学习Python函数,其中的差异如下表所示

核心差异

特性 Java (21+) Python (3.13)
定义方式 必须声明在类中 独立定义,支持嵌套函数
参数传递 值传递(对象传引用副本) 引用传递(直接操作原对象)
返回值 必须显式return+类型声明 可隐式返回/多返回值
变量作用域 块级作用域 函数级作用域+global声明
类型系统 静态类型 动态类型
高阶函数支持 Stream API/Lambda 一等公民,原生支持

Java方法定义

1
2
3
4
5
6
7
// 必须包含在类中
public class Calculator {
// 显式返回类型
public static int add(int a, int b) {
return a + b;
}
}

Python函数定义

1
2
3
4
5
6
7
# 独立函数定义(2023新增类型提示)
def add(a: int, b: int) -> int:
return a + b

# 多返回值示例
def get_user():
return "Alice", 25, "alice@example.com" # 返回元组

函数参数

Java值传递示例

1
2
3
4
5
6
7
8
9
10
void modifyList(List<String> list) {
list.add("new"); // 修改引用副本指向的对象
list = new ArrayList<>(); // 不影响原始引用
}

public static void main(String[] args) {
List<String> data = new ArrayList<>();
modifyList(data);
System.out.println(data); // 输出 [new]
}

Python引用传递示例

1
2
3
4
5
6
7
def modify_list(lst):
lst.append("new") # 修改原列表
lst = [1, 2, 3] # 新建局部变量

data = []
modify_list(data)
print(data) # 输出 ['new']

可变参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def calculate_scores(name: str, *scores, **course_info):
"""
计算学生成绩的多种统计值

参数:
name - 学生姓名(固定参数)
*scores - 任意数量的考试成绩(可变位置参数)
**course_info - 课程相关信息(可变关键字参数)
"""
total = sum(scores)
avg = total / len(scores) if scores else 0

print(f"学生 {name}:")
print(f"▪ 共参加 {len(scores)} 门考试")
print(f"▪ 总分:{total} 平均分:{avg:.1f}")

if course_info:
print("课程详情:")
for key, value in course_info.items():
print(f" - {key}: {value}")

calculate_scores("John", 80, 95, 72, 88, 100,
math=90, english=85, science=100)

缺省参数(默认参数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def register_user(
name: str,
age: int,
city: str = "北京", # 缺省参数(2025最新推荐写法)
membership: bool = False
) -> dict:
"""
用户注册函数(支持缺省参数)

参数:
name - 必填姓名(位置参数)
age - 必填年龄(位置参数)
city - 居住城市(默认北京)
membership - 会员状态(默认非会员)

返回:
包含完整用户信息的字典
"""
return {
"name": name,
"age": age,
"city": city,
"vip": membership,
"reg_date": "2025-04-10" # 模拟注册时间
}

print("案例1:使用所有默认值")
user1 = register_user("张三", 25)
print(user1)

print("\n案例2:覆盖部分默认参数")
user2 = register_user("李四", 30, city="上海")
print(user2)

print("\n案例3:跳过默认参数指定")
user3 = register_user("王五", 28, membership=True) # 显式使用参数名
print(user3)

作用域差异

Java块级作用域

1
2
3
4
5
6
7
public void demoScope() {
int x = 10;
if (true) {
int y = 20; // 仅在此块内有效
}
// System.out.println(y); 编译错误
}

Python函数级作用域

1
2
3
4
5
6
7
8
9
10
11
def demo_scope():
x = 10
if True:
y = 20 # 整个函数可见
print(y) # 正常输出20

# 全局变量处理
total = 0
def increment():
global total
total += 1

更详细的案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 全局作用域变量
global_x = 10


def modify_global_without_keyword():
"""⚠️ 危险操作:尝试修改全局变量未声明global"""
# 此处会创建新的局部变量,导致后续访问全局变量失败
print("[错误尝试] 试图访问全局变量:", global_x) # 会触发UnboundLocalError
global_x = 50 # 实际创建新的局部变量


def show_local_scope():
"""✅ 正确局部变量使用"""
local_y = 20
print("[局部变量] 函数内访问:", local_y)

# 代码块内的变量提升
if True:
block_z = 30
print("[代码块变量] 跨块访问:", block_z) # 仍然可见


def safely_modify_global():
"""✅ 正确修改全局变量"""
global global_x # 明确声明
print("[修改前] 全局变量值:", global_x)
global_x = 50
print("[修改后] 全局变量值:", global_x)


# 初始状态验证
print("[初始状态] 全局变量:", global_x)

# 错误操作演示
try:
modify_global_without_keyword()
except UnboundLocalError as e:
print(f"❌ 错误捕获:{type(e).__name__} - 未声明global时不能修改全局变量")
print("[安全恢复] 全局变量保持原值:", global_x)

# 局部变量访问测试
show_local_scope()

try:
print("[危险操作] 尝试访问局部变量:", local_y)
except NameError as e:
print(f"❌ 错误捕获:{type(e).__name__} - 局部变量不可外部访问")

# 正确修改全局变量
safely_modify_global()
print("[最终验证] 全局变量最新值:", global_x)

类型系统实战

Java强类型示例

1
2
3
4
// 编译时类型检查
String concat(String a, int b) {
return a + b; // 自动转换b为String
}

Python动态类型示例

1
2
3
4
5
def concat(a, b):
return str(a) + str(b) # 运行时处理类型

concat("num", 25) # 正常返回"num25"
concat([1,2], {"k":"v"}) # 返回 "[1, 2]{'k': 'v'}"

匿名函数(Lambda)

Java Stream API

1
2
3
4
List<Integer> nums = Arrays.asList(1, 2, 3);
List<Integer> doubled = nums.stream()
.map(n -> n * 2)
.collect(Collectors.toList());

Python原生支持

1
2
3
4
5
6
7
8
9
# Lambda表达式
nums = [1, 2, 3]
doubled = list(map(lambda x: x*2, nums))

# 函数作为参数
def apply_operation(func, data):
return [func(x) for x in data]

apply_operation(lambda x: x**3, nums) # 返回[1, 8, 27]

注意:原生的Python中Lambda表达式并不能指定返回值的数据类型,需要引入Callable库,具体方法如下所示:

1
2
3
4
from typing import Callable

# 通过变量注解实现类型声明
add: Callable[[int, int], int] = lambda x, y: x + y # [int,int]表示的是参数的数据类型,最后一个int表示的是返回值的数据类型

函数递归

递归核心概念

递归 = 递去(分解问题) + 归来(组合结果)
必要条件:必须存在终止条件,且每次递归都更接近终止条件

经典案例

数字累加:

1
2
3
4
5
6
7
def sum_num(n):
if n == 1: # 终止条件
return 1
else:
return n + sum_num(n-1) # 递推关系

print(sum_num(5)) # 输出:15(计算5+4+3+2+1)

文件树遍历:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import os

def scan_dir(path, level=0):
# 打印当前目录(缩进表示层级)
print(' ' * level + '📁 ' + os.path.basename(path))

for item in os.listdir(path):
full_path = os.path.join(path, item)
if os.path.isdir(full_path): # 如果是文件夹
scan_dir(full_path, level+1) # 递归扫描子目录
else:
print(' ' * (level+1) + '📄 ' + item) # 打印文件

scan_dir('/user/docs') # 示例路径

最佳迁移实践

  1. 参数设计原则

    • 优先使用不可变类型作为参数(tuple代替list)
    • 慎用可变默认参数(Python经典陷阱)
    1
    2
    3
    4
    # 错误示例
    def add_item(item, lst=[]):
    lst.append(item)
    return lst
  2. 类型提示规范(2025推荐)

    1
    2
    3
    4
    from typing import Union

    def parse_input(input: Union[str, int]) -> float:
    return float(input)
  3. 异常处理结合

    1
    2
    3
    4
    5
    def safe_divide(x: float, y: float) -> float:
    try:
    return x / y
    except ZeroDivisionError as e:
    raise ValueError("除数不能为零") from e

学习路线建议

  1. 先掌握

    def

    定义和参数传递机制

  2. 重点理解可变/不可变对象在函数中的表现

  3. 熟练使用

    *args

    **kwargs

    参数

  4. 掌握装饰器语法(Java无直接对应特性)

    1
    2
    3
    4
    5
    6
    7
    def log_time(func):
    def wrapper(*args, **kwargs):
    start = time.time()
    result = func(*args, **kwargs)
    print(f"耗时:{time.time()-start:.4f}s")
    return result
    return wrapper

常用内置函数

下表来自B站尚硅谷:

函数 用途
abs() 对传入参数取绝对值
bool() 对传入参数取布尔值,[None, 0, “”, [], {}, ()]像这种空值或空容器均为False
all() 所有传入参数为真时,返回值才为真
any() 所有传入的参数只要有一个为真,返回值就是真
ascii() 自动执行传入参数的_repr_方法(将对象转换为字符串)
bin() 接受一个十进制,转换为二进制
oct() 接受一个十进制,转换为八进制
hex() 接受一个十进制,转换为十六进制
bytes() 字符串转换为字节。第一个参数:需要转换的字符串;第二个参数:指定转换的编码格式
str() 字节转换为字符串。第一个参数:需要转换的字节;第二个参数:指定转换的编码格式
chr(65) 数字转字母,具体可以按照ASCII码表
ord(‘A’) 字母转数字,具体可以按照ASCII码表
compile() 接受.py文件或字符串作为传入参数,将其编译成python字节码
eval() 执行python代码,并返回其执行结果
exec() 执行python代码(可以是编译过的,也可以是未编译的),没有返回结果(结果None)
dir() 接受对象为参数,返回该对象的所有属性和方法
help() 接受对象作为参数,更详细地返回该对象的所有属性和方法
divmod(100,10) 返回一个元组(10,0),第一个元素为的100/10的商,第二个元素为100/10的余数
enumerate() 接收序列化类型的数据,返回一个迭代器(对象)
isinstance(object,class) 判断对象是否是某个类的实例
filter() 后续有详细介绍
map() 后续有详细介绍
format() 字符串格式化
frozenset() 转换为不可变的集合
globals() 返回一个字典,包括所有的全局变量与该变量的值所组成的键值对
locals() 返回一个字典,包括所有的局部变量与该变量的值所组成的键值对
hash() 对传入参数取哈希值并返回
id() 返回内存地址
input(‘please input:’) 提示用户输入,返回用户输入的内容(无论用户输入任何内容,最后的数据类型都为字符串)
issubclass(subclass,class) 查看这个类是否是另一个类的派生类,如果是返回True,否则返回False
len() 返回长度
max() 接收序列化类型数据,返回其中最大的元素
min() 接收序列化类型数据,返回其中最小的元素
memoryview() 查看内存地址
next() 获取迭代器下一个元素
iter() 创建迭代器对象
object() 创建基础对象实例
pow(x,y) 求次方,返回x**y的结果
pow(x,y,z) 返回x**y%z的结果
property() 获取对象的所有属性
range() 获取范围数
repr() 执行传入对象的_repr_方法
reversed() 对序列化数据反向排序,返回一个新的对象。注意与对象的reverse方法区别,后者是就地改变对象
sorted() 对序列化类型数据正向排序,返回一个新的对象。注意与对象的sort方法区别,后者是就地改变对象
slice() 对序列化类型数据切片,返回一个新的对象

map函数

基础语法

1
map(function, iterable, *iterables) -> map object

说明:

  • 第一个参数:用于处理第二个参数的函数
  • 第二个参数:可遍历的原始数据
  • 第三个参数:额外的可遍历原始数据

示例:

1
2
3
4
5
6
7
8
9
10
11
12
def preprocess_01(data: list) -> map:
return map(lambda x: x * 1.5, filter(lambda x: x>0, data))

list_01 = [0,-1,2,-3,4,-5,6,-7,8,-9]
after_process_01 = preprocess_01(list_01)
print(list(after_process_01)) # [3.0, 6.0, 9.0, 12.0]

def preprocess_02(data_1: list, data_2: list) -> map:
return map(lambda x,y: x * 1.5 + y * 2.5, filter(lambda x: x>0, data_1), filter(lambda x: x<0, data_2))
list_02 = [0, 1, -2, 3, -4, 5, -6, 7, -8, 9]
after_process_02 = preprocess_02(list_01,list_02)
print(list(after_process_02)) # [-2.0, -4.0, -6.0, -8.0]

filter函数

基础语法:

1
filter(function or None, iterable) -> filter object

说明:

  • 第一个参数:判断函数(返回True保留元素),None时直接取元素真值
  • 第二个参数:单数据源(与map不同,不支持多数据源并行处理)

核心特性

  • 惰性计算:生成迭代器而非立即执行
  • 内存优化:处理1GB数据仅需5MB内存(Python 3.13+)
  • 类型安全:自动校验函数返回类型(2025新增)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
示例:

# 示例1:基础数值过滤(含2025类型标注)
def filter_even(data: list[int]) -> filter:
return filter(lambda x: x%2 == 0, data)

nums = [0, -3, 8, 15, 22, -40]
print(list(filter_even(nums))) # [0, 8, 22, -40]

# 示例2:多阶段数据处理(过滤后转换)
def process_data(data: list[float]) -> map:
filtered = filter(lambda x: x >= 0 and not x.is_integer(), data)
return map(lambda x: round(x*10, 2), filtered)

samples = [3.14, -2.71, 5.0, 7.2, 9.999]
print(list(process_data(samples))) # [31.4, 72.0, 99.99]

# 示例3:跨类型数据清洗(2025优化版)
def clean_mixed_data(data: list) -> filter:
return filter(
lambda item: (
isinstance(item, int) and item > 0 or
isinstance(item, str) and len(item) > 3
),
data
)

mixed = [10, "py", -5, "data", 3.14, "AI"]
print(list(clean_mixed_data(mixed))) # [10, 'data']

模块

模块核心概念

模块 = 代码工具箱

  • 本质是

    .py

    文件,包含函数/类/变量等

  • 优势:代码复用、逻辑分离、命名空间管理

  • 分类:

    • 内置模块:Python自带(如math,random
    • 第三方模块:通过pip install安装(如requests
    • 自定义模块:开发者创建的.py文件

模块导入方法

方式一:全量导入

1
2
import math
print(math.sqrt(16)) # 4.0

方式二:选择性导入

1
2
from random import choice
print(choice([1,3,5,7])) # 随机选一个数字

方式三:别名导入(避免命名冲突)

1
2
import pandas as pd
from datetime import datetime as dt

方式四:导入全部内容(慎用)

1
2
from turtle import *  # 所有函数直接可用
circle(100) # 无需加模块名前缀

注意:如果模块的文件名以数字开头01_xxxx.py,那么需要进行特殊的处理才能正确导入模块,示例如下

1
2
3
4
5
6
7
import importlib

# 动态导入数字开头的模块(无需重命名文件)
module = importlib.import_module("01_xxxx")

# 调用模块中的函数/变量
module.hello()

自定义模块开发

步骤1:创建

1
2
3
4
5
6
7
8
9
10
# 文件名:geometry.py
# 计算面积函数
def circle_area(r):
return 3.14159 * r ** 2

# 判断三角形类型(2025新增类型注解)
def triangle_type(a: int, b: int, c: int) -> str:
if a + b > c and a + c > b and b + c > a:
return "Valid"
return "Invalid"

步骤2:主程序导入

1
2
3
4
import geometry

print(geometry.circle_area(3)) # 28.27431
print(geometry.triangle_type(3,4,5)) # Valid

注意事项

  1. 循环导入:模块A导入B,同时B导入A会导致错误

  2. 路径问题:自定义模块需在以下位置之一:

    • 当前工作目录

    • sys.path包含的路径(可用sys.path.append()添加)

  3. 缓存机制:已导入模块不会重新加载(需用importlib.reload()

  4. 命名规范:模块名避免与内置模块冲突(如不要命名sys.py

调试技巧

1
2
3
4
5
6
# 查看已加载模块
import sys
print(sys.modules.keys())

# 查看模块位置
print(math.__file__) # 显示math模块路径

  • 模块:单个.py文件(如utils.py
  • 包:含__init__.py的目录,支持多级嵌套(如my_package/

标准包结构

1
2
3
4
5
6
7
8
9
10
11
my_project/
├── pyproject.toml # 构建配置(替代setup.py)
├── src/
│ └── my_package/ # 包代码目录
│ ├── __init__.py
│ ├── core.py
│ └── utils/
│ ├── math.py
│ └── strings.py
├── tests/ # 测试目录
└── requirements.txt # 依赖清单

包的导入机制

导入方式对比

方式 示例 适用场景
绝对导入 from my_package.core import func 跨模块引用
相对导入 from ..utils.math import add 包内部引用(PEP 328)
动态导入 importlib.import_module() 按需加载/插件系统

路径解析规则

1
2
3
4
5
6
7
8
9
10
import sys
print(sys.path) # 查看Python搜索路径

# 添加自定义路径(临时)
sys.path.append("/custom/module/path")

# 永久添加路径(2025新方案)
# 在pyproject.toml中配置:
# [tool.paths]
# package_dirs = ["src"]

包的创建与分发

创建可分发包

1
2
3
4
5
6
7
8
9
10
11
# pyproject.toml
[build-system]
requires = ["setuptools>=65.0"]
build-backend = "setuptools.build_meta"

[project]
name = "my_package"
version = "0.1.0"
authors = [{name = "Your Name", email = "you@example.com"}]
description = "My awesome package"
dependencies = ["requests>=2.25"]
  1. 构建与发布
1
2
3
4
5
6
7
8
# 安装最新构建工具
pip install build twine

# 构建分发包(源码+wheel)
python -m build

# 上传到PyPI
twine upload dist/*

本地安装开发模式

1
2
# 可编辑模式安装(代码修改实时生效)
pip install -e .

包管理工具

常用指令:

命令 作用
pip install . 安装当前目录包
pip install -r requirements.txt 根据清单安装依赖
pip freeze > requirements.txt 生成精确依赖清单
pip list --outdated 列出过期包
pip cache purge 清除缓存

最佳实践与陷阱规避

包设计原则

  1. 单一职责:每个包/模块聚焦一个功能领域
  2. 避免循环导入:使用import语句延迟加载
  3. 版本兼容:在__init__.py中定义__version__

__init__.py

__init__.py是 Python 包(Package) 的核心标识文件,其作用如下:

作用 说明 示例场景
标识包目录 使 Python 将含该文件的目录视为可导入的包(Namespace Package 除外) 旧项目兼容(Python <3.3)
初始化包 包被导入时自动执行该文件中的代码 预加载资源、注册子模块、配置日志
控制模块暴露 通过 __all__ 变量定义 from package import * 时导出的内容 限制外部可见接口
简化导入路径 在文件中导入子模块/子包,用户可直接通过包名访问 from my_pkg import utils(无需完整路径)
跨版本兼容 在 Python 3.3+ 中虽非必需,但显式使用可确保向后兼容性 开源库开发

基础场景(空文件)

1
2
# my_package/__init__.py
# 空文件,仅标识目录为包

初始化操作

1
2
3
# my_package/__init__.py
print("包已加载!") # 包导入时自动执行
from . import core # 导入同级模块 core.py

控制暴露接口

1
2
3
# my_package/__init__.py
__all__ = ['utils', 'config'] # 定义允许导出的模块
from .utils import * # 暴露 utils 模块的所有公共成员

复杂包结构整合

1
2
3
# my_package/__init__.py
from .sub_pkg import * # 导入子包中的所有模块
from .core import main_func # 直接暴露核心函数

常见的标准库

下表来自B站尚硅谷:

模块 用途
os os模块提供了许多与操作系统交互的函数,例如创建、移动和删除文件(或目录),以及访问环境变量等
sys sys模块提供了与Python解释器和系统相关的功能,例如解释器的版本和路径,以及与stdin、stdout和stderr相关的信息
time time模块提供了处理时间的函数,例如获取当前时间、格式化日期和时间、计时等
datatime datetime提供了更加高级的日期和时间处理函数,例如处理时区、计算时间差、计算日期差等
random random提供了生成随机数的函数,例如生成随机整数、浮点数、序列等
math math模块提供了数学函数,例如三角函数、对数函数、指数函数、常数等
re re模块提供了正则表达式处理函数、可以用于文本搜索、替换、分割等
json json模块提供了JSON编码和解码函数,可以将Python对象转换为JSON格式,并从JSON格式中解析出Python对象
urllib urllib模块提供了访问网页和处理URL的功能,包括下载文件、发送POST请求、处理cookies等

random库的使用

方法 作用 参数说明 示例 输出示例
random() 生成 [0.0, 1.0) 的随机浮点数 random.random() 0.5487
randint(a, b) 生成 [a, b] 的随机整数 a 下限,b 上限 random.randint(1, 10) 7
uniform(a, b) 生成 [a, b] 的随机浮点数 a 下限,b 上限 random.uniform(5.5, 10.5) 8.34
choice(seq) 从非空序列中随机选取元素 seq 列表/元组/字符串 random.choice(['A', 'B', 'C']) 'B'
shuffle(seq) 原地打乱序列顺序 seq 可变序列(如列表) lst = [1,2,3]; random.shuffle(lst) lst → [3,1,2]
sample(seq, k) 从序列中无重复抽取 k 个元素 seq 序列,k 数量 random.sample(range(100), 5) [42, 88, 15, 3, 71]
randrange(start, stop, step) 按步长生成随机整数 start 起始,stop 结束,step 步长 random.randrange(0, 100, 5) 45

高频使用场景及代码示例

生成验证码
1
2
3
4
5
6
7
import random

def generate_code(length=6):
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
return ''.join(random.choice(chars) for _ in range(length))

print(generate_code()) # 输出如 '3X8T9Y'
随机打乱数据集
1
2
3
data = list(range(10))
random.shuffle(data) # 原地打乱
print(data) # 输出如 [7, 2, 5, 0, 9, 1, 3, 8, 4, 6]
加权随机选择(2025 年新特性)
1
2
3
4
options = ['A', 'B', 'C']
weights = [0.2, 0.5, 0.3] # 权重需总和为1
selected = random.choices(options, weights=weights, k=3)
print(selected) # 输出如 ['B', 'B', 'C']
生成安全随机数
1
2
3
4
import secrets  # Python 3.6+ 专用安全模块

secure_num = secrets.randbelow(100) # 生成 [0, 99] 的安全随机整数
print(secure_num) # 输出如 42

注意事项

  1. 种子设置:

    1
    random.seed(42)  # 固定随机种子,使结果可复现(调试用)
  2. 线程安全:多线程环境下建议使用random.SystemRandom()实例

  3. 浮点数精度:uniform()的浮点数精度受系统限制,金融计算需用decimal模块

扩展学习

  • 高级分布:gauss(mu, sigma)(正态分布)、expovariate(lambd)(指数分布)
  • 性能优化:生成大规模随机数组时,推荐使用numpy.random
  • 安全场景:涉及密码学操作时,优先使用secrets模块

re库的使用

常用方法详解

方法 作用 示例 输出示例
re.match() 从头匹配,仅匹配字符串开头 re.match(r'\d+', '123abc') Match对象(123)
re.search() 全局搜索,找到第一个匹配位置 re.search(r'\d+', 'abc456def') Match对象(456)
re.findall() 返回所有匹配结果的列表 re.findall(r'\d+', 'a1b22c333') ['1', '22', '333']
re.finditer() 返回迭代器,适合大文本处理 [m.group() for m in re.finditer(r'\d+', 'a1b22c333')] ['1', '22', '333']
re.sub() 替换匹配内容 re.sub(r'\d+', 'X', 'a1b22c333') 'aXbXcX'
re.split() 按模式分割字符串 re.split(r'\d+', 'a1b22c333') ['a', 'b', 'c', '']

正则表达式核心语法

基础元字符
1
2
3
4
5
6
r'\d'      # 匹配数字(等价于 [0-9])
r'\w' # 匹配字母/数字/下划线(等价于 [a-zA-Z0-9_])
r'\s' # 匹配空白符(空格、制表符等)
r'.' # 匹配除换行外的任意字符
r'^abc' # 匹配以 abc 开头
r'xyz$' # 匹配以 xyz 结尾
量词控制
1
2
3
4
r'a*'      # 匹配 0 次或多次(贪婪)
r'a+?' # 匹配 1 次或多次(非贪婪)
r'a{2,5}' # 匹配 2-5 次
r'a|b' # 匹配 a 或 b
分组与引用
1
2
3
4
5
6
7
8
9
# 分组捕获
m = re.search(r'(\d{3})-(\d{4})', '电话:010-1234')
print(m.group(1)) # '010'

# 替换引用
re.sub(r'(\d+)/(\d+)', r'\2/\1', '3/14') # → '14/3'

# 命名分组(2025 推荐写法)
re.search(r'(?P<area>\d{3})-(?P<num>\d{4})', '010-1234').group('area') # → '010'

高频应用场景与代码示例

邮箱验证
1
2
email_pattern = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
print(re.match(email_pattern, 'user@example.com') is not None) # True
提取电话号码
1
2
text = "联系电话:010-12345678 或 0755-7654321"
phones = re.findall(r'\d{3,4}-\d{7,8}', text) # → ['010-12345678', '0755-7654321']
HTML标签内容提取
1
2
html = '<div class="title">Hello World</div>'
content = re.search(r'<div.*?>(.*?)</div>', html).group(1) # → 'Hello World'
敏感词替换
1
2
3
4
sensitive_words = ['bad', 'danger']
pattern = re.compile('|'.join(sensitive_words), flags=re.IGNORECASE)
text = 'This is a BAD example.'
clean_text = pattern.sub('***', text) # → 'This is a *** example.'

最佳实践与常见陷阱

性能优化
  • 预编译正则:重复使用的模式用re.compile()预编译(可提升 10-20% 性能)
  • 避免回溯灾难:慎用嵌套量词如(a+)+,可用原子分组(?>...)
安全与规范
  • 原始字符串:始终使用r''避免转义错误
  • DDoS 防御:用户输入正则时限制复杂度(参考 CWE-400)
常见错误
1
2
3
4
5
6
7
# 错误:未转义特殊字符
re.search(r'example.com', 'exampleAcom') # 错误匹配
re.search(r'example\.com', 'example.com') # 正确

# 错误:贪婪模式导致意外匹配
re.search(r'<div>.*</div>', '<div>a</div><div>b</div>').group() # 匹配整个字符串
re.search(r'<div>.*?</div>', '<div>a</div>...') # 正确(非贪婪)

socket库的使用

  1. Socket类型:
    • socket.SOCK_STREAM:TCP协议(可靠流式传输)
    • socket.SOCK_DGRAM:UDP协议(快速无连接传输)
  2. 地址格式:
    • IPv4使用元组(host, port),如('127.0.0.1', 8888)
    • IPv6使用元组(host, port, flowinfo, scopeid)

TCP通信基础步骤

服务端代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import socket

# 1. 创建Socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2. 绑定地址和端口
server_socket.bind(('localhost', 8888))

# 3. 开启监听(最大连接数设为5)
server_socket.listen(5)
print("服务端已启动,等待连接...")

try:
while True:
# 4. 接受客户端连接(阻塞等待)
client_socket, addr = server_socket.accept()
print(f"客户端 {addr} 已连接")

# 5. 接收数据(最大1024字节)
data = client_socket.recv(1024)
print(f"收到数据:{data.decode('utf-8')}")

# 6. 发送响应
client_socket.sendall(b'Hello from server!')

# 7. 关闭当前客户端连接
client_socket.close()
finally:
# 8. 关闭服务端Socket
server_socket.close()
客户端代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import socket

# 1. 创建Socket对象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
# 2. 连接服务器
client_socket.connect(('localhost', 8888))

# 3. 发送数据
client_socket.sendall(b'Hello from client!')

# 4. 接收响应(最大1024字节)
response = client_socket.recv(1024)
print(f"服务器响应:{response.decode('utf-8')}")

finally:
# 5. 关闭连接
client_socket.close()

第三方库

文件以及IO操作

open函数

1
2
3
4
5
6
7
8
9
10
open(
file,
mode='r',
buffering=-1,
encoding=None,
errors=None,
newline=None,
closefd=True,
opener=None
)

核心参数详解

file(必选):

  • 接受路径对象或字符串路径
  • 2025推荐写法
1
2
from pathlib import Path
file_path = Path("data/2025_log.txt")

mode(模式控制):

模式 描述 文件存在行为 读写权限
r 只读 打开文件
w 写入 清空内容
a 追加 保留内容
r+ 读写 打开文件 读写
w+ 读写 清空内容 读写
a+ 读写 保留内容 读写

二进制扩展模式(追加b):

1
2
3
# 处理图片/视频等二进制文件
with open("video.mp4", "rb") as f:
data = f.read()

encoding(编码规范):

  • 必须显式声明(2025强制规范)
  • 推荐值:utf-8
  • 错误示例:
1
2
3
4
# 不推荐(使用系统默认编码)
open("file.txt", "r")
# 正确写法
open("file.txt", "r", encoding="utf-8")

errors(编码错误处理):

策略 行为
strict 遇到错误抛出异常(默认)
ignore 忽略错误字符
replace 用?替代不可解码字符
1
2
3
# 处理老旧系统生成的GBK文件
with open("old_file.txt", "r", encoding="gbk", errors="replace") as f:
content = f.read()

with语句

with语句是用于资源自动管理的核心语法结构,其设计目标是通过上下文管理器协议确保资源的安全获取与释放

核心概念

替代传统的try/finally模式,实现资源自动释放(如文件句柄、数据库连接、线程锁等)

语法原型

1
2
with ContextManager() as resource:
# 在此使用资源
  1. 上下文管理器协议

    • __enter__()

      :进入代码块时调用,返回资源对象

    • __exit__()

      :退出代码块时调用,处理清理逻辑

典型应用场景

文件操作
1
2
3
4
5
6
7
from pathlib import Path

# 现代路径管理+with语句(2025推荐写法)
log_file = Path("logs/app_2025.log")

with log_file.open("a", encoding="utf-8") as f:
f.write(f"[{datetime.now().isoformat()}] SYSTEM_OK\n")
数据库连接池
1
2
3
# 新型异步数据库连接(2025新特性)
async with aio_db.connect() as conn:
await conn.execute("UPDATE data SET status=1")
线程锁管理
1
2
3
4
5
import threading

lock = threading.Lock()
with lock: # 自动获取和释放锁
shared_data.append(new_item)

进阶用法

自定义上下文管理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class DatabaseTransaction:
def __enter__(self):
self.conn = connect_db()
self.conn.begin()
return self.conn

def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None:
self.conn.commit()
else:
self.conn.rollback()
self.conn.close()

# 使用示例
with DatabaseTransaction() as db:
db.execute("INSERT INTO logs VALUES (...)")
多资源并行管理
1
2
3
4
# 同时打开输入输出文件
with (open("source.csv", "r") as src,
open("processed.parquet", "wb") as dst):
process_data(src, dst) # 数据流式处理

文件

查(Read)操作

列出目录内容
1
2
3
4
5
6
7
8
from pathlib import Path  # Python 3.4+ 推荐方式

# 使用pathlib(跨平台友好)
current_dir = Path.cwd() # 返回当前目录的绝对路径
all_items = list(current_dir.iterdir()) # 包含文件和目录

# 过滤特定类型文件
py_files = [f for f in current_dir.glob('*.py') if f.is_file()]
获取文件信息
1
2
3
4
5
6
7
8
9
from pathlib import Path

file_path = Path('data.txt')
print(f"""
文件存在: {file_path.exists()}
是否为文件: {file_path.is_file()}
文件大小: {file_path.stat().st_size} bytes
最后修改时间: {file_path.stat().st_mtime} (Unix时间戳)
""")

增(Create)操作

创建文件
1
2
3
4
5
6
7
from pathlib import Path

new_file = Path('new_data.txt')
try:
new_file.touch(exist_ok=False) # 避免覆盖已有文件
except FileExistsError:
print("文件已存在!")
创建目录
1
2
3
4
from pathlib import Path

new_dir = Path('project/docs/2025')
new_dir.mkdir(parents=True, exist_ok=True) # 自动创建不存在的父目录

删(Delete)操作

安全删除文件
1
2
3
4
5
6
7
from pathlib import Path

target_file = Path('temp.txt')
if target_file.exists():
target_file.unlink() # 等价于 os.remove
else:
print("文件不存在")
删除目录
1
2
3
4
5
6
7
8
9
10
11
from pathlib import Path
import shutil

def safe_remove_dir(dir_path):
dir_path = Path(dir_path)
if dir_path.exists():
shutil.rmtree(dir_path, onerror=handle_errors)

def handle_errors(func, path, exc_info):
# 自定义错误处理(如文件被占用时的重试逻辑)
print(f"删除失败: {path}")

改(Update)操作

重命名/移动文件
1
2
3
4
5
6
7
src = Path('old_name.txt')
dst = Path('new_name.txt')

try:
src.replace(dst) # 原子操作,跨文件系统自动复制+删除
except FileNotFoundError:
print("源文件不存在")
修改文件内容
1
2
3
4
5
6
with open('data.txt', 'r+', encoding='utf-8') as f:
content = f.read()
new_content = content.replace('old', 'new')
f.seek(0) # 回到文件开头
f.write(new_content)
f.truncate() # 截断多余内容

高级技巧

跨平台路径处理
1
config_path = Path('config') / 'app' / 'settings.yaml'  # 自动适配不同系统路径分隔符
临时文件处理
1
2
3
4
5
6
7
from tempfile import NamedTemporaryFile

with NamedTemporaryFile(delete=False) as tmp:
tmp.write(b'临时数据')
tmp_path = tmp.name # 获取临时文件路径
# 结束后手动删除
Path(tmp_path).unlink()
文件监控
1
2
3
4
5
# 需安装:pip install watchfiles
from watchfiles import watch

for changes in watch('./data'):
print(f'检测到文件变化: {changes}')

IO操作

查(Read)操作

文本文件读取
1
2
3
4
5
6
7
8
# 使用pathlib自动管理资源
file_path = Path("data.txt")
try:
content = file_path.read_text(encoding="utf-8")
except FileNotFoundError:
print("文件不存在")
except UnicodeDecodeError:
print("编码错误")
二进制文件读取
1
2
3
with open("image.png", "rb") as f:
while chunk := f.read(4096): # 分块读取大文件
process(chunk)

增(Create/Write)操作

安全写入文本文件
1
2
3
4
5
output_path = Path("output.log")
try:
output_path.write_text("2025年最新数据\n", encoding="utf-8", errors="replace")
except PermissionError:
print("无写入权限")
追加写入文件
1
2
with open("app.log", "a", encoding="utf-8") as f:
f.write(f"[{datetime.now()}] 系统运行正常\n")

改(Update)操作

原地修改文件内容
1
2
3
4
5
6
7
8
9
10
file_path = Path("config.ini")
try:
with file_path.open("r+", encoding="utf-8") as f:
content = f.read()
new_content = content.replace("old_value", "new_value")
f.seek(0)
f.write(new_content)
f.truncate() # 截断多余内容
except IOError as e:
print(f"修改失败: {e}")
安全替换文件
1
2
3
4
5
temp_path = Path("temp.txt")
with temp_path.open("w") as tmp:
tmp.write("新内容")

temp_path.replace("original.txt")

删(Delete)操作

清空文件内容
1
Path("clear.txt").write_text("")  # 安全清空
删除文件
1
2
3
4
5
target = Path("obsolete.dat")
try:
target.unlink(missing_ok=True) # 等效于os.remove
except PermissionError:
print("删除权限不足")

高级IO技巧

内存流操作
1
2
3
4
with io.StringIO() as buffer:
buffer.write("内存临时数据")
buffer.seek(0)
print(buffer.read())
二进制流分块处理
1
2
3
with open("large.bin", "rb+") as f:
f.seek(1024)
f.write(b"NEW_BLOCK_DATA") # 直接修改指定位置数据
异步IO操作
1
2
3
4
5
import aiofiles

async def async_write():
async with aiofiles.open("async.log", "w") as f:
await f.write("异步写入内容")

Python面向对象

面向对象编程的核心思想

面向对象编程(Object-Oriented Programming, OOP)是一种以对象为中心的编程范式,通过将数据(属性)和行为(方法)封装为独立实体,模拟现实世界的结构和交互。相较于传统的面向过程编程(以函数和流程为核心),OOP 更强调代码的模块化可复用性可维护性

类与对象:OOP的基石

  1. 类(Class)

    • 定义:类是对象的抽象模板,描述一类对象的共同属性和方法。

    • 示例:

      1
      2
      3
      4
      5
      class Animal:  
      def __init__(self, name):
      self.name = name # 属性
      def speak(self): # 方法
      pass
  2. 对象(Object)

    • 定义:对象是类的具体实例,拥有类定义的属性和方法。

    • 示例:

      1
      dog = Animal("Buddy")  # 创建Animal类的实例  

OOP三大核心特性

封装(Encapsulation)

  • 核心思想:隐藏对象的内部实现细节,仅通过公开的接口与外界交互。

  • 作用:

    • 提高安全性(如通过私有属性限制直接访问)
    • 简化复杂度(用户无需关心内部逻辑)
  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class BankAccount:  
    def __init__(self):
    self.__balance = 0 # 私有属性

    def deposit(self, amount): # 公开方法
    if amount > 0:
    self.__balance += amount

    account = BankAccount()
    account.deposit(100) # 通过方法操作数据,而非直接修改__balance

继承(Inheritance)

  • 核心思想:子类继承父类的属性和方法,实现代码复用和层次化扩展。

  • 类型:

    • 单继承(Python、Java)
    • 多继承(Python支持,需谨慎使用)
  • 示例:

    1
    2
    3
    4
    5
    6
    class Dog(Animal):  
    def speak(self):
    return "Woof!"

    dog = Dog("Buddy")
    print(dog.speak()) # 输出: Woof!

多态(Polymorphism)

  • 核心思想:同一接口在不同对象中表现出不同行为。

  • 实现方式:

    • 方法重写(子类覆盖父类方法)
    • 接口抽象(不同类实现相同接口)
  • 示例:

    1
    2
    3
    4
    5
    6
    7
    class Cat(Animal):  
    def speak(self):
    return "Meow!"

    animals = [Dog("Buddy"), Cat("Whiskers")]
    for animal in animals:
    print(animal.speak()) # 输出: Woof! Meow!

__init__(初始化)

__init__是Python中的初始化方法(非严格意义上的构造函数),在对象实例化时自动调用。它主要负责设置对象初始状态(如属性赋值)

在Python中构造函数为__new__,负责创建并返回实例(用户通常无需重写)

代码示例:

1
2
3
4
5
class Robot:
def __init__(self, name):
self.name = name # 初始化实例属性

robot = Robot("Optimus") # 自动调用__init__

__slots__(属性白名单)

当不希望其他开发者对类动态添加额外属性时:

1
2
3
4
5
6
class Animal:
def __init__(self,name):
self.name = name

dog = Animal("小黄")
dog.age = 5 # 添加了额外属性

可以使用__slots__方法:

1
2
3
4
5
6
7
8
9
class SafeAnimal:
__slots__ = ("name", "age") # 白名单限制

def __init__(self, name):
self.name = name

rabbit = SafeAnimal("Bunny")
rabbit.age = 2 # 允许 ✅
rabbit.weight = 1.5 # AttributeError ❌
  • 优点:节省内存(无需维护__dict__),显式控制属性
  • 局限:无法继承使用__dict__的父类,不支持动态添加

__setattr__(动态属性拦截)

__slots__方法类似,可以阻止动态添加属性:

1
2
3
4
5
6
7
8
9
10
11
class StrictAnimal:
def __init__(self, name):
self.name = name

def __setattr__(self, name, value):
if not hasattr(self, name):
raise AttributeError(f"禁止动态添加属性:{name}")
super().__setattr__(name, value)

fox = StrictAnimal("Foxy")
fox.age = 3 # AttributeError ❌

soltssetattr的选择

场景 推荐方案 特点
高性能/内存敏感 __slots__ 内存节省20%~50%,属性严格限制
传统业务系统 动态拦截(__setattr__) 灵活控制,可自定义错误处理逻辑
快速原型/脚本开发 原生动态属性 最大化开发效率

__dict__(对象属性字典)

__dict__是Python对象的特殊属性,存储实例级属性的键值对,键为属性名,值为属性数据

1
2
3
4
5
6
class User:
def __init__(self, name):
self.name = name # 存入__dict__

u = User("Alice")
print(u.__dict__) # 输出:{'name': 'Alice'}
对象类型 __dict__ 内容 示例
类实例 实例属性(不含类属性) {'name': 'Alice'}
类对象 类属性、方法、装饰器等 {'__module__': '__main__', ...}
模块对象 模块内定义的所有变量/函数 {'User': <class '__main__.User'>, ...}

核心应用场景

动态属性管理

1
2
3
4
# 动态添加属性
u.__dict__["age"] = 25 # 等价于 u.age = 25
# 动态删除属性
del u.__dict__["name"] # 等价于 del u.name

对象序列化

1
2
3
4
5
import json
# 对象转JSON(需先转为字典)
user_dict = u.__dict__.copy()
user_dict["timestamp"] = 20250421 # 扩展数据
json_data = json.dumps(user_dict)

元编程操作

1
2
3
4
5
6
7
8
9
10
# 批量修改属性
for key in u.__dict__:
if isinstance(u.__dict__[key], str):
u.__dict__[key] = u.__dict__[key].upper()

# 属性访问拦截
class LoggedUser(User):
def __getattribute__(self, name):
print(f"访问属性: {name}")
return super().__getattribute__(name)

self参数

self是约定名称(可改名但不建议),表示当前对象实例的引用,用于访问实例属性和方法

运行机制

  • Python解释器自动将实例作为第一个参数传递
  • 通过self实现实例间的数据隔离(每个实例维护独立属性)

实践场景

1
2
3
4
5
6
class BankAccount:
def __init__(self, balance=0):
self.balance = balance # 实例属性

def deposit(self, amount): # 必须包含self
self.balance += amount

静态属性

  • 静态属性(类属性):直接定义在类命名空间中的变量,属于类本身而非实例。所有实例共享同一份类属性。
  • 关键特征:
    • 共享性:所有实例访问同一份类属性值。
    • 独立性:修改类属性会全局影响所有实例(除非实例覆盖同名属性)。
    • 直接访问:无需实例化即可通过类名访问。
1
2
3
4
5
6
7
8
class Circle:
pi = 3.14 # 静态属性

def __init__(self, radius):
self.radius = radius

def get_area(self):
return self.pi * self.radius ** 2

@classmethod

在 Python 中,@classmethod是一个内置装饰器,用于定义类方法。类方法属于类本身而非类的实例,可直接通过类名调用,无需创建实例对象。以下是其核心要点

核心特性

  • 参数约定:类方法的第一个参数必须是cls(类本身),而非实例方法的self
  • 访问权限:可直接通过cls访问类属性、调用其他类方法,但无法直接访问实例属性(需实例化后操作)。
  • 调用方式:支持通过类名或实例调用(本质仍由类处理)。

常见使用场景

替代构造函数

允许通过不同数据格式(如字符串、字典)创建实例,增强灵活性。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day

@classmethod
def from_string(cls, date_str): # 从"YYYY-MM-DD"字符串创建实例
year, month, day = map(int, date_str.split("-"))
return cls(year, month, day)

# 使用类方法创建实例(无需手动解析)
date = Date.from_string("2025-05-01")

工厂模式

根据输入参数返回不同子类实例,隐藏具体实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Animal:
@classmethod
def create(cls, animal_type):
if animal_type == "dog":
return Dog()
elif animal_type == "cat":
return Cat()
else:
raise ValueError("Unknown animal type")

class Dog(Animal): pass
class Cat(Animal): pass

# 通过工厂方法创建对象
pet = Animal.create("dog")

类状态管理

操作类级别属性(如计数器、配置项)。

1
2
3
4
5
6
7
8
9
10
class Logger:
_log_level = "INFO"

@classmethod
def set_log_level(cls, level):
cls._log_level = level.upper()

# 直接修改类属性
Logger.set_log_level("debug")
print(Logger._log_level) # 输出: DEBUG

典型示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Car:
wheels = 4 # 类属性

def __init__(self, brand):
self.brand = brand # 实例属性

@classmethod
def change_wheels(cls, num):
cls.wheels = num # 修改类属性
print(f"All cars now have {cls.wheels} wheels.")

# 通过类名调用类方法
Car.change_wheels(6) # 输出: All cars now have 6 wheels.
print(Car.wheels) # 输出: 6

# 实例也可调用(但逻辑仍作用于类)
my_car = Car("Tesla")
my_car.change_wheels(8) # 输出: All cars now have 8 wheels.

@staticmethod

@staticmethod是 Python 的装饰器,用于定义 静态方法。其本质是将普通函数封装到类命名空间中,与类和实例无直接数据依赖。

特性 说明
参数要求 无强制参数(无需 selfcls
访问权限 无法直接访问类属性或实例属性
调用方式 通过类名或实例调用(推荐类名调用)
继承行为 子类继承父类静态方法时,方法逻辑固定,无法动态绑定到子类

定义语法与示例

基础定义

1
2
3
4
5
6
7
8
9
class MathUtils:
@staticmethod
def add(a, b):
return a + b # 纯计算逻辑,无类/实例依赖

# 调用方式
print(MathUtils.add(3, 5)) # 输出: 8 (推荐类名调用)
obj = MathUtils()
print(obj.add(2, 3)) # 输出: 5 (通过实例调用,但不推荐)

动态添加

1
2
3
4
5
6
7
8
class Logger:
pass

def log_message(message):
print(f"[LOG] {message}")

Logger.log = staticmethod(log_message) # 动态添加静态方法
Logger.log("System started") # 输出: [LOG] System started

典型应用场景

场景1:工具函数封装

1
2
3
4
5
6
7
8
9
10
11
class DateValidator:
@staticmethod
def is_valid_date(year, month, day):
# 独立于类状态的日期验证逻辑
try:
datetime.datetime(year, month, day)
return True
except ValueError:
return False

print(DateValidator.is_valid_date(2025, 13, 1)) # 输出: False

场景2:辅助计算

1
2
3
4
5
6
class Geometry:
@staticmethod
def circle_area(radius):
return 3.14159 * radius ** 2 # 无需类/实例数据

print(Geometry.circle_area(3)) # 输出: 28.27431

场景3:替代全局函数

1
2
3
4
5
6
class StringProcessor:
@staticmethod
def reverse(s):
return s[::-1] # 逻辑独立,但组织在相关类中

print(StringProcessor.reverse("hello")) # 输出: olleh

与相关概念的对比

方法类型 @staticmethod @classmethod 实例方法
首个参数 cls(类对象) self(实例对象)
访问类属性 ✅(通过 cls ✅(通过 self.__class__
访问实例属性 ❌(需实例化后访问)
多态支持 ✅(cls 动态绑定子类)
内存占用 类级别共享 类级别共享 每个实例独立

总结:当不涉及对类的属性进行操作时(访问、修改),选择@staticmethod,反之则选择@classmethod

继承

Python写法

1
2
class Dog(Animal):  # 括号内指定父类
pass

Java等价写法

1
2
3
class Dog extends Animal {  // 使用extends关键字
//...
}

核心差异点

特性 Python Java
继承声明方式 类名后括号列父类 extends关键字
多重继承支持 原生支持(逗号分隔多父类) 仅单继承,需用接口实现多态
抽象类要求 无强制抽象关键字 需用abstract声明
构造器调用逻辑 显式调用父类__init__ 自动调用super()构造函数

父类顺序

MRO

Python通过C3线性化算法确定多继承的初始化顺序,其核心规则:

  1. 子类优先:子类初始化方法优先于父类
  2. 从左到右:按继承列表顺序处理父类
  3. 唯一性:每个父类只初始化一次

执行逻辑

  • 非直接调用父类:super()并非直接调用父类,而是根据当前类的MRO列表决定下一个要调用的类
  • 动态查找:在继承链中按MRO顺序依次触发初始化

执行流程示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A:
def __init__(self):
print("A")
super().__init__()

class B:
def __init__(self):
print("B")
super().__init__()

class C(A, B):
def __init__(self):
print("C")
super().__init__()

obj = C()

输出结果:

1
C → A → B → object

MRO顺序

1
C.mro() = [C, A, B, object]

查看MRO

1
2
3
print(ClassName.__mro__)
# 或
print(ClassName.mro())

初始化中断场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A:
def __init__(self):
print("A") # 未调用super()

class B(A):
def __init__(self):
print("B")
super().__init__()

class C(B, int): # 继承内置类型
def __init__(self):
print("C")
super().__init__()

obj = C() # 输出:C → B → A(int未初始化)

当某个父类未调用super().__init__()时,后续父类初始化将中断

强制调用指定父类

1
2
3
4
class D(Parent1, Parent2):
def __init__(self):
Parent2.__init__(self) # 绕过MRO直接调用
Parent1.__init__(self)

非推荐做法,会破坏MRO规则(可能导致重复初始化)

多态

多态(Polymorphism):同一操作作用于不同对象时,对象会表现出不同的具体行为。Python通过动态类型鸭子类型实现多态,无需显式接口定义。

三大特性:

  1. 继承:子类继承父类方法
  2. 重写:子类修改父类方法实现
  3. 统一调用:以相同方式调用不同对象的方法

基础示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 基类定义
class Animal:
def speak(self):
raise NotImplementedError("子类必须实现此方法")

# 子类重写方法
class Dog(Animal):
def speak(self):
return "汪汪!"

class Cat(Animal):
def speak(self):
return "喵~"

class Duck:
# 无继承关系但实现相同方法(鸭子类型)
def speak(self):
return "嘎嘎!"

# 统一调用方法
def animal_sound(obj):
print(obj.speak())

# 测试多态
animal_sound(Dog()) # 输出:汪汪!
animal_sound(Cat()) # 输出:喵~
animal_sound(Duck()) # 输出:嘎嘎! (无需继承)

进阶场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from typing import Protocol

# 定义协议(替代抽象基类)
class Shape(Protocol):
def area(self) -> float: ...

# 不同图形实现
class Circle:
def __init__(self, radius: float):
self.radius = radius

def area(self) -> float:
return 3.1415 * self.radius ** 2

class Rectangle:
def __init__(self, w: float, h: float):
self.width = w
self.height = h

def area(self) -> float:
return self.width * self.height

# 统一处理函数
def print_area(obj: Shape):
print(f"图形面积:{obj.area():.2f}")

# 测试
print_area(Circle(3)) # 输出:28.27
print_area(Rectangle(4,5)) # 输出:20.00

多态优势

优势 说明 示例场景
代码复用 统一接口减少重复代码 不同支付方式实现支付接口
扩展灵活 新增类无需修改调用代码 新增三角形类计算面积
解耦设计 调用方不依赖具体类实现 日志记录器支持多种存储方式
动态替换 运行时切换不同实现 根据配置选择数据库驱动

封装

封装(Encapsulation)是面向对象编程中将数据操作数据的方法捆绑在一起的机制,通过隐藏内部细节实现:

  • 🔒 数据保护:防止外部直接修改敏感数据
  • 🎭 隐藏实现:仅暴露必要操作接口
  • 🔧 维护增强:内部修改不影响外部调用

Python实现封装的3种方式

命名约定(弱封装)

1
2
3
4
5
6
class Account:
def __init__(self, balance):
self._balance = balance # 单下划线约定为"受保护"属性

acc = Account(100)
print(acc._balance) # 仍可访问(非强制)

名称修饰(强封装)

1
2
3
4
5
6
7
8
9
10
class BankAccount:
def __init__(self, balance):
self.__balance = balance # 双下划线触发名称修饰

def get_balance(self):
return self.__balance

acc = BankAccount(500)
#print(acc.__balance) # ❌ 报错:AttributeError
print(acc._BankAccount__balance) # ✅ 500(了解机制但不要主动使用)

属性装饰器(推荐方案)

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

@property # Getter方法
def name(self):
return self.__name.upper()

@name.setter # Setter方法
def name(self, new_name):
if len(new_name) >= 3:
self.__name = new_name
else:
print("姓名至少3个字符!")

u = User("Alice")
print(u.name) # ✅ ALICE
u.name = "Bob" # ✅ 修改成功
u.name = "A" # ❌ 输出警告,拒绝修改

完整案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class BankAccount:
def __init__(self, name, initial_balance=0):
self.__name = name # 私有属性
self.__balance = initial_balance # 私有属性

# 公开方法(接口)
def deposit(self, amount):
"""存款"""
if amount > 0:
self.__balance += amount
print(f"存款成功,余额:{self.__balance}")
else:
print("存款金额必须大于0")

def withdraw(self, amount):
"""取款"""
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"取款成功,余额:{self.__balance}")
else:
print("余额不足或金额无效")

# 通过属性访问器控制数据
@property
def balance(self):
return self.__balance

# 使用示例
acc = BankAccount("张三", 1000)
acc.deposit(500) # ✅ 存款成功,余额:1500
acc.withdraw(2000) # ❌ 余额不足
acc.withdraw(800) # ✅ 取款成功,余额:700
print(acc.balance) # ✅ 700(只读属性)

封装的优势

场景 未封装实现 封装实现 优势体现
余额查看 直接访问属性 通过getter方法 可添加格式转换逻辑
存款操作 直接修改balance 通过deposit()方法 自动验证金额有效性
数据保护 可能被设为负值 withdraw()校验余额 确保数据一致性

魔法方法

魔法方法(Magic Methods)是Python中以双下划线包裹的特殊方法(如__init__),用于自定义类与内置行为的交互机制。截至2025年最新实践,这些方法主要有两大作用:

  1. 运算符重载:让自定义对象支持+/-等运算符
  2. 协议实现:响应len()/with等内置函数的调用

高频方法

对象生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
class TimeMachine:
def __new__(cls, year): # 创建实例(早于__init__执行)
print(f"🕰️ 正在创建{year}年的时光机...")
return super().__new__(cls)

def __init__(self, year):
self.year = year

def __del__(self): # 对象销毁时触发
print(f"💥 {self.year}年的时光机已销毁")

machine = TimeMachine(2025) # 输出:🕰️ 正在创建2025年的时光机...
del machine # 输出:💥 2025年的时光机已销毁

运算符重载

1
2
3
4
5
6
7
8
9
10
11
12
13
class Vector3D:
def __init__(self, x, y, z):
self.x, self.y, self.z = x, y, z

def __add__(self, other): # 实现向量加法
return Vector3D(self.x+other.x, self.y+other.y, self.z+other.z)

def __str__(self): # 定义print输出格式
return f"Vector3D({self.x}, {self.y}, {self.z})"

v1 = Vector3D(1,2,3)
v2 = Vector3D(4,5,6)
print(v1 + v2) # 输出:Vector3D(5, 7, 9)

容器协议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Playlist:
def __init__(self, songs):
self.songs = list(songs)

def __getitem__(self, index): # 支持下标访问
return self.songs[index]

def __len__(self): # 响应len()函数
return len(self.songs)

def __contains__(self, song): # 支持in运算符
return song in self.songs

my_list = Playlist(["孤勇者", "晴天"])
print(len(my_list)) # 输出:2
print("晴天" in my_list) # 输出:True

推荐实践

场景 推荐魔法方法组合 优势说明
文件资源管理 __enter__ + __exit__ 自动关闭文件/释放资源
数学运算扩展 __add__ + __sub__ 支持自定义数学运算
迭代器模式 __iter__ + __next__ 实现可迭代对象
快捷调用 __call__ 使实例可像函数一样调用

上下文管理器示例

1
2
3
4
5
6
7
8
9
10
class DatabaseConnection:
def __enter__(self):
print("🔗 数据库连接已建立")
return self # 返回连接对象

def __exit__(self, exc_type, exc_val, exc_tb):
print("🚪 数据库连接已关闭")

with DatabaseConnection() as conn: # 自动管理资源
print("执行数据库操作...")