Python
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()一样,主要是用于在控制台中输出结果的,基础用法如下所示:
print("Hello World") # 输出字符串
print(2025) # 输出数字
print([1, 2, 3]) # 输出列表
多对象输出(sep参数)
当print函数中有多个参数时,使用sep参数可以为每个参数之间添加相关的间隔符,如下所示:
name = "Alice"
age = 25
print(name, "年龄", age, sep="->") # 输出:Alice->年龄->25
格式化输出
f-string
pi = 3.1415926
print(f"圆周率:{pi:.3f}") # 输出:圆周率:3.142
format
print("坐标:({x}, {y})".format(x=10, y=20))
传统占位符
print("CPU使用率:%.1f%%" % 75.5)
进阶控制参数
换行控制(end参数)
print("Loading", end='')
print("...", end='') # 输出:Loading...
实时刷新(flush参数)
import time
for i in range(5):
print(".", end='', flush=True)
time.sleep(1) # 每秒输出一个点
多行文本(三引号)
print('''
第一行
第二行
第三行
''')
特殊场景处理
转义字符处理
print("换行符:\\n") # 输出:换行符:\n
print(r"原始字符串:C:\new_dir") # 使用r前缀不转义
输出调试信息
data = {"status": 200}
print(f"{data=}") # 输出:data={'status': 200}
输入函数——Input
基础用法
同Java中的Scanner类,主要的作用是提供开发人员在控制台中输入内容,使用方法如下所示:
user_input = input("请输入内容:")
print(f"您输入的是:{user_input}(类型:{type(user_input)})")
需要注意的是,input方法会阻塞执行(代码停留在input函数处不会继续向下执行)
类型转换机制
# 必须显式转换类型
age = int(input("请输入年龄:")) # 输入25 → 类型int
price = float(input("请输入价格:")) # 输入19.9 → 类型float
进阶使用技巧
多值接收处理
# 解包赋值(需保证输入格式)
x, y = map(int, input("输入两个数字(空格分隔):").split())
print(f"x+y={x+y}") # 输入"10 20" → 输出30
安全输入验证
while True:
try:
num = int(input("请输入整数:"))
break
except ValueError:
print("输入无效,请重新输入!")
特殊场景处理
多行输入处理
print("输入多行内容(空行结束):")
lines = []
while (line := input()) != '':
lines.append(line)
print(f"总行数:{len(lines)}")
:=是海象运算符,是python语言独有的运算符
密码输入隐藏(需安装getpass)
from getpass import getpass
password = getpass("输入密码:") # 输入时无回显
海象运算符——:=
基本定义
-
官方名称:赋值表达式运算符 (Assignment Expressions)
-
符号:
:=(形似海象眼睛和牙齿而得名) -
版本要求:Python 3.8+(2020年9月正式发布)
-
核心功能:在表达式内部进行变量赋值
基本语法
传统赋值
n = len(data)
if n > 10:
print(n)
海象运算符写法
if (n := len(data)) > 10:
print(n)
典型应用场景
循环控制
# 读取文件直到空行
lines = []
while (line := input()) != '':
lines.append(line)
# 等效传统写法
while True:
line = input()
if line == '': break
lines.append(line)
列表推导式优化
# 避免重复计算
data = [1, 2, 3, 4, 5]
doubled = [y for x in data if (y := x*2) < 8]
# 结果:[2, 4, 6]
正则匹配
import re
text = "2025-04-06更新日志"
if (match := re.search(r'\d{4}-\d{2}-\d{2}', text)):
print(f"找到日期:{match.group()}")
运行原理
graph TD A[表达式开始] --> B[执行右侧运算] B --> C[赋值给左侧变量] C --> D[返回赋值结果] D --> E[参与表达式运算]
类型判断——Type和Isinstance
Type方法
基础使用
num = 42
print(type(num)) # <class 'int'>
lst = [1,2,3]
print(type(lst)) # <class 'list'>
进阶使用
Dog = type('Dog', (), {'bark': lambda self: print("Woof!")})
d = Dog()
d.bark() # 输出: Woof!
Isinstance方法
基础使用
# 类型检查
num = 3.14
print(isinstance(num, float)) # True
print(isinstance(num, (int, float))) # True
继承关系处理
class Animal: pass
class Dog(Animal): pass
d = Dog()
print(isinstance(d, Animal)) # True
典型应用场景
# 安全类型检查
def safe_divide(a, b):
if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
raise TypeError("参数必须是数字类型")
return a / b
核心差异对比
flowchart TD A((22)) A --> B((18)) A --> C((26)) B --> D((16)) B --> E((20)) D --> F((15)) D --> G((17)) E --> N((19)) E --> O((21)) C --> H((24)) C --> I((28)) H --> J((23)) H --> K((25)) I --> L((27)) I --> M((29))
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()) |
基础切片
s = "Python切片特性"
print(s[2:5]) # 输出: tho
print(s[::2]) # 输出: Pto切性
反转黑科技
s = "ABCDE"
print(s[::-1]) # 输出: EDCBA(根据2024 Stack Overflow票选最佳技巧)
多维切片(Python独有)
matrix = [[1,2,3], [4,5,6], [7,8,9]]
print(matrix[1:][::-1]) # 输出:[[7,8,9], [4,5,6]]
快速理解
# 标准切片语法
sequence[start:end:step]
start:起始索引(包含,默认0)end:结束索引(不包含,默认序列长度)step:步长(默认1,可为负数)
边界自动校准机制
# 超出索引自动截断(2025 PyCon展示案例)
s = "Python"
print(s[2:100]) # 输出"thon"(实际end=5)
数据类型转换
| 转换方向 | 函数示例 | 典型应用场景 | 注意事项 |
|---|---|---|---|
| 转整型 | int() |
用户年龄输入处理 | 浮点转整型会截断小数 |
| 转浮点型 | float() |
商品价格计算 | 字符串需包含有效数字格式 |
| 转字符串 | str() |
日志信息拼接 | 支持所有数据类型转换 |
| 转列表 | list() |
JSON数据解析 | 字典转换会丢失键值对 |
| 转元组 | tuple() |
坐标点不可变存储 | 类似列表但不可修改 |
| 转字典 | dict() |
配置文件读取 | 需要键值对结构数据 |
| 转集合 | set() |
数据去重处理 | 自动排序且元素唯一 |
| 转布尔 | bool() |
条件判断预处理 | 非零/非空为True |
| 转字节 | bytes() |
网络数据传输 | 需指定编码方式 |
| 复数转换 | complex() |
科学计算场景 | 实部虚部需数字类型 |
容器类型转换
# 元组转列表(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实现) -
缓存目的:减少内存碎片,提高常用数值操作效率
内存分配原理
# 验证地址相同
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使用
&&
(短路)与
&
(非短路)区分
自增/自减运算
# Python(无此运算符)
i += 1 # 只能使用复合赋值
# Java(支持++/--)
i++; // 等效i = i + 1
除法运算
# Python(明确区分)
5 / 2 # 2.5(真除法)
5 // 2 # 2(整除)
# Java(统一行为)
5 / 2 // 2(自动取整)
(double)5 / 2 // 2.5
成员运算符
# Python特有语法
if 'a' in ['a', 'b', 'c']: ...
# Java需手动实现
List<String> list = Arrays.asList("a", "b", "c");
if (list.contains("a")) { ... }
条件判断
最基础的If条件判断书写格式如下所示:
if 条件1: # 必须包含冒号
代码块1 # 4空格缩进强制要求
elif 条件2: # 可多个elif分支
代码块2
else: # 最终兜底分支
代码块3
Java中的Switch-Case在Python中表示为Match-Case,如下所示:
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表达式) |
典型场景对比
# 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"
# 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循环
# 遍历可迭代对象
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循环
# 基础条件循环
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
# 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}")
实际场景应用
数据遍历
# 字典遍历优化
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)
条件循环控制
# 实时数据监控模式(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 | 元素比较 | 字符串、列表、元组 |
元素比较规则:
- 逐元素比较
- 元组比较采用字典序
(lexicographical order)规则:- 从第一个元素开始逐个对比,当且仅当所有对应位置元素相等时,才会继续比较下一个元素
- 首个不相等元素即决定最终结果
- 长度对比原则
- 仅当前N个元素完全相等时
(N为较短元组长度):- 长度较短的元组视为更小
- 例:
(1,2) < (1,2,3)→True
列表
列表核心特性
- 动态可变性
- 实时修改元素 (O(1)时间复杂度)
- 自动内存管理 (动态数组实现)
# 2025验证案例
lst = [1, 2, 3]
lst[1] = "two" # [1, 'two', 3]
- 异构数据存储
- 支持混合类型元素
- 允许嵌套数据结构
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) | 删除首个匹配值 | 先判断存在性 |
查询与切片
# 高级切片技巧
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(matrix[1:3][0][::-1]) # 输出[6,5,4]
排序新特性
# Python 3.13+ 并行排序
import bisect
data = [5, 2, 8, 1]
bisect.insort(data, 4) # 插入后自动保持有序 → [1,2,4,5,8]
列表推导式实战
多维数据处理
# 生成5x5矩阵
matrix = [[i*5 + j for j in range(5)] for i in range(5)]
条件过滤优化
# 带异常处理的推导式
nums = [1, '2', 3, 'four', 5]
clean = [int(x) for x in nums if isinstance(x, (int, str)) and str(x).isdigit()]
海量数据生成器
# 内存优化方案(生成器表达式)
large_data = (x**2 for x in range(10**6) if x%3 ==0)
元组
元组核心特性
- 不可变序列
- 内存优化:固定长度存储,访问速度比列表更快
- 数据安全:防止意外修改关键数据
coordinates = (39.9042, 116.4074)
coordinates[0] = 40 # 引发TypeError
- 异构数据容器
person = ("张三", 28, 175.5, ["Python", "Java"])
print(person[3][0]) # 输出"Python"
核心操作
- 创建方式对比
| 方法 | 示例 | 适用场景 |
|---|---|---|
| 直接赋值 | t = (1,2,3) |
显式创建 |
| 单元素声明 | t = (100,) |
避免与普通括号混淆 |
| 转换生成 | tuple([1,2,3]) |
从其他可迭代对象转换 |
| 生成器表达式 | tuple(x**2 for x in range(5)) |
高效生成大数据 |
- 高效访问方法
# 解包操作(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 | 非连续数据生成 |
最新特性
- 内存优化:生成惰性序列(10^6元素仅占48字节)
- 步长增强:支持复数步长(Python 3.13+)
# 复数步长生成坐标序列
coords = range(0+0j, 5+5j, 1+1j)
print(list(coords)) # [(0+0j), (1+1j), (2+2j), (3+3j), (4+4j)]
进阶应用场景
逆序生成
for i in range(10, 0, -2):
print(i) # 输出10,8,6,4,2
浮点数处理(需配合numpy)
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]
边界验证
# 安全范围检查
def safe_range(start, end):
return range(max(0, start), min(1000000, end))
最佳实践指南
- 循环控制
:优先使用
for i in range(len(data))
而非
while
2. 序列生成
:大数据场景使用
range
代替列表推导式 3. 类型转换
:需要具体序列时使用
list(range(...))
常见错误处理
# 错误案例:空序列
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倍 |
大数据查询优势明显 |
核心操作
创建方式
# 标准创建
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) 方法:主要用于确认键是否存在
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) 方法:主要用于初始化字典
# 词频统计应用
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 模式:主要用于高频访问已知存在的键
# 实时交易系统(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方式处理错误 # 仅触发时耗时
字典循环
dict1 = {
"name": "John",
"age": 30,
"city": "New York",
"has_job": False
}
for k,v in dict1.items():
print(f"键:{k},值:{v}")
高级应用技巧
嵌套字典处理
# 多层结构
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() | (键,值)对视图 | 高效迭代操作 |
# 内存高效迭代
for k, v in d.items():
process_data(k, v)
2025最佳实践
类型标注规范
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
并发安全模式
# 使用collections.ChainMap
from collections import ChainMap
safe_config = ChainMap(user_settings, default_settings)
内存优化方案
# 使用__slots__的字典子类
class OptimizedDict(dict):
__slots__ = ()
# 节省每个实例的内存开销(Python 3.13+)
可变与不可变数据类型
| 类别 | 具体类型 | 内存特性 | 典型场景 |
|---|---|---|---|
| 不可变类型 | 整型(int) | 修改时重建对象 | 计数器、ID值 |
| 浮点型(float) | 内存地址随值改变 | 科学计算 | |
| 复数(complex) | 值变化即新建对象 | 信号处理 | |
| 字符串(str) | 拼接操作生成新字符串 | 文本处理 | |
| 元组(tuple) | 元素引用不可变 | 数据库记录 | |
| 冻结集合(frozenset) | 哈希安全集合 | 字典键值 | |
| 字节(bytes) | 二进制不可变序列 | 网络传输 | |
| 可变类型 | 列表(list) | 动态数组,支持增删改 | 数据集合操作 |
| 字典(dict) | 哈希表结构可动态扩展 | 键值映射存储 | |
| 集合(set) | 基于哈希表的无序集合 | 去重操作 |
Python进阶
异常处理
基础语法结构
try:
# 可能引发异常的代码
result = 10 / 0
except ZeroDivisionError as e:
print(f"错误捕获:{e}")
else:
print("正常执行时运行")
finally:
print("无论是否异常都执行")
进阶处理技巧
多异常捕获
try:
user_input = int("abc")
except (ValueError, TypeError) as e:
print(f"输入类型错误:{e.__class__.__name__}")
异常上下文保留
try:
open("non_exist.txt")
except FileNotFoundError as e:
raise RuntimeError("文件操作失败") from e
资源自动管理
with open("data.txt") as f:
content = f.read() # 自动处理文件关闭
raise关键字
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
异常类型全景图
内置异常体系
BaseException
├── SystemExit
├── KeyboardInterrupt
├── Exception
│ ├── ValueError
│ ├── TypeError
│ ├── FileNotFoundError
│ └── 40+其他异常...
高频异常说明
| 异常类型 | 触发场景 | 最新解决方案 |
|---|---|---|
| ValueError | 无效参数转换 | 增强数据校验 |
| KeyError | 字典键不存在 | 使用get()方法 |
| IndexError | 序列越界访问 | 预检查长度 |
| TypeError | 类型操作不兼容 | 添加类型注解 |
自定义异常开发
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方法定义
// 必须包含在类中
public class Calculator {
// 显式返回类型
public static int add(int a, int b) {
return a + b;
}
}
Python函数定义
# 独立函数定义(2023新增类型提示)
def add(a: int, b: int) -> int:
return a + b
# 多返回值示例
def get_user():
return "Alice", 25, "alice@example.com" # 返回元组
函数参数
Java值传递示例
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引用传递示例
def modify_list(lst):
lst.append("new") # 修改原列表
lst = [1, 2, 3] # 新建局部变量
data = []
modify_list(data)
print(data) # 输出 ['new']
可变参数
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)
缺省参数(默认参数)
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块级作用域
public void demoScope() {
int x = 10;
if (true) {
int y = 20; // 仅在此块内有效
}
// System.out.println(y); 编译错误
}
Python函数级作用域
def demo_scope():
x = 10
if True:
y = 20 # 整个函数可见
print(y) # 正常输出20
# 全局变量处理
total = 0
def increment():
global total
total += 1
更详细的案例
# 全局作用域变量
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强类型示例
// 编译时类型检查
String concat(String a, int b) {
return a + b; // 自动转换b为String
}
Python动态类型示例
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
List<Integer> nums = Arrays.asList(1, 2, 3);
List<Integer> doubled = nums.stream()
.map(n -> n * 2)
.collect(Collectors.toList());
Python原生支持
# 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库,具体方法如下所示:
from typing import Callable
# 通过变量注解实现类型声明
add: Callable[[int, int], int] = lambda x, y: x + y# [int,int]表示的是参数的数据类型,最后一个int表示的是返回值的数据类型
函数递归
递归核心概念
递归 = 递去(分解问题) + 归来(组合结果)
必要条件:必须存在终止条件,且每次递归都更接近终止条件
经典案例
数字累加:
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)
文件树遍历:
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') # 示例路径
最佳迁移实践
- 参数设计原则
- 优先使用不可变类型作为参数(tuple代替list)
- 慎用可变默认参数(Python经典陷阱)
# 错误示例
def add_item(item, lst=[]):
lst.append(item)
return lst
2. 类型提示规范(2025推荐)
``` from typing import Union
def parse_input(input: Union[str, int]) -> float: return float(input) ``` 3. 异常处理结合
def safe_divide(x: float, y: float) -> float:
try:
return x / y
except ZeroDivisionError as e:
raise ValueError("除数不能为零") from e
学习路线建议
- 先掌握
def
定义和参数传递机制 2. 重点理解可变/不可变对象在函数中的表现 3. 熟练使用
*args
和
**kwargs
参数 4. 掌握装饰器语法(Java无直接对应特性)
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函数
基础语法:
map(function, iterable, *iterables) -> map object
说明:
- 第一个参数:用于处理第二个参数的函数
- 第二个参数:可遍历的原始数据
- 第三个参数:额外的可遍历原始数据
示例:
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函数
基础语法:
filter(function or None, iterable) -> filter object
说明:
- 第一个参数:判断函数(返回True保留元素),None时直接取元素真值
- 第二个参数:单数据源(与map不同,不支持多数据源并行处理)
核心特性:
- 惰性计算:生成迭代器而非立即执行
- 内存优化:处理1GB数据仅需5MB内存(Python 3.13+)
- 类型安全:自动校验函数返回类型(2025新增)
示例:
示例:
# 示例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文件
模块导入方法
方式一:全量导入
import math
print(math.sqrt(16)) # 4.0
方式二:选择性导入
from random import choice
print(choice([1,3,5,7])) # 随机选一个数字
方式三:别名导入(避免命名冲突)
import pandas as pd
from datetime import datetime as dt
方式四:导入全部内容(慎用)
from turtle import * # 所有函数直接可用
circle(100) # 无需加模块名前缀
注意:如果模块的文件名以数字开头01_xxxx.py,那么需要进行特殊的处理才能正确导入模块,示例如下
import importlib
# 动态导入数字开头的模块(无需重命名文件)
module = importlib.import_module("01_xxxx")
# 调用模块中的函数/变量
module.hello()
自定义模块开发
步骤1:创建
# 文件名: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:主程序导入
import geometry
print(geometry.circle_area(3)) # 28.27431
print(geometry.triangle_type(3,4,5)) # Valid
注意事项
- 循环导入:模块A导入B,同时B导入A会导致错误
- 路径问题:自定义模块需在以下位置之一:
- 当前工作目录
sys.path包含的路径(可用sys.path.append()添加) 3. 缓存机制:已导入模块不会重新加载(需用importlib.reload()) 4. 命名规范:模块名避免与内置模块冲突(如不要命名sys.py)
调试技巧
# 查看已加载模块
import sys
print(sys.modules.keys())
# 查看模块位置
print(math.__file__) # 显示math模块路径
包
- 模块:单个
.py文件(如utils.py) - 包:含
__init__.py的目录,支持多级嵌套(如my_package/)
标准包结构
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() |
按需加载/插件系统 |
路径解析规则
import sys
print(sys.path) # 查看Python搜索路径
# 添加自定义路径(临时)
sys.path.append("/custom/module/path")
# 永久添加路径(2025新方案)
# 在pyproject.toml中配置:
# [tool.paths]
# package_dirs = ["src"]
包的创建与分发
创建可分发包
# 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"]
- 构建与发布
# 安装最新构建工具
pip install build twine
# 构建分发包(源码+wheel)
python -m build
# 上传到PyPI
twine upload dist/*
本地安装开发模式
# 可编辑模式安装(代码修改实时生效)
pip install -e .
包管理工具
常用指令:
| 命令 | 作用 |
|---|---|
pip install . |
安装当前目录包 |
pip install -r requirements.txt |
根据清单安装依赖 |
pip freeze > requirements.txt |
生成精确依赖清单 |
pip list --outdated |
列出过期包 |
pip cache purge |
清除缓存 |
最佳实践与陷阱规避
包设计原则
- 单一职责:每个包/模块聚焦一个功能领域
- 避免循环导入:使用
import语句延迟加载 - 版本兼容:在
__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+ 中虽非必需,但显式使用可确保向后兼容性 | 开源库开发 |
基础场景(空文件)
# my_package/__init__.py
# 空文件,仅标识目录为包
初始化操作
# my_package/__init__.py
print("包已加载!") # 包导入时自动执行
from . import core # 导入同级模块 core.py
控制暴露接口
# my_package/__init__.py
__all__ = ['utils', 'config'] # 定义允许导出的模块
from .utils import * # 暴露 utils 模块的所有公共成员
复杂包结构整合
# 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 |
高频使用场景及代码示例
生成验证码
import random
def generate_code(length=6):
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
return ''.join(random.choice(chars) for _ in range(length))
print(generate_code()) # 输出如 '3X8T9Y'
随机打乱数据集
data = list(range(10))
random.shuffle(data) # 原地打乱
print(data) # 输出如 [7, 2, 5, 0, 9, 1, 3, 8, 4, 6]
加权随机选择(2025 年新特性)
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']
生成安全随机数
import secrets # Python 3.6+ 专用安全模块
secure_num = secrets.randbelow(100) # 生成 [0, 99] 的安全随机整数
print(secure_num) # 输出如 42
注意事项
- 种子设置:
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', ''] |
正则表达式核心语法
基础元字符
r'\d' # 匹配数字(等价于 [0-9])
r'\w' # 匹配字母/数字/下划线(等价于 [a-zA-Z0-9_])
r'\s' # 匹配空白符(空格、制表符等)
r'.' # 匹配除换行外的任意字符
r'^abc' # 匹配以 abc 开头
r'xyz$' # 匹配以 xyz 结尾
量词控制
r'a*' # 匹配 0 次或多次(贪婪)
r'a+?' # 匹配 1 次或多次(非贪婪)
r'a{2,5}' # 匹配 2-5 次
r'a|b' # 匹配 a 或 b
分组与引用
# 分组捕获
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'
高频应用场景与代码示例
邮箱验证
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
提取电话号码
text = "联系电话:010-12345678 或 0755-7654321"
phones = re.findall(r'\d{3,4}-\d{7,8}', text) # → ['010-12345678', '0755-7654321']
HTML标签内容提取
html = '<div class="title">Hello World</div>'
content = re.search(r'<div.*?>(.*?)</div>', html).group(1) # → 'Hello World'
敏感词替换
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)
常见错误
# 错误:未转义特殊字符
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库的使用
- Socket类型:
-
socket.SOCK_STREAM:TCP协议(可靠流式传输) -socket.SOCK_DGRAM:UDP协议(快速无连接传输) - 地址格式:
- IPv4使用元组
(host, port),如('127.0.0.1', 8888)- IPv6使用元组(host, port, flowinfo, scopeid)
TCP通信基础步骤
服务端代码示例
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()
客户端代码示例
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()
第三方库
graph LR A["Python第三方库分类"] --> B[Web开发] A --> C[游戏开发] A --> D[数据科学] A --> E[机器学习/深度学习] A --> F[GUI开发] A --> G[文件处理] A --> H[自然语言处理] A --> I[图像处理] A --> J[实用工具] %% Web开发(2025年主流框架) B --> B1("Django (全栈框架)") B --> B2("Flask (微框架)") B --> B3("Pyramid (可扩展框架)") %% 游戏开发(最新游戏引擎支持) C --> C1("Pygame (2D游戏开发)") C --> C2("Panda3D (3D游戏引擎)") C --> C3("cocos2d (移动端游戏)") %% 数据科学(2025年核心库) D --> D1("numpy (数值计算)") D --> D2("pandas (数据分析)") D --> D3("matplotlib (数据可视化)") D --> D4("scipy (科学计算)") D --> D5("mayavi (3D可视化)") %% 机器学习/深度学习(最新AI工具链) E --> E1("scikit-learn (传统机器学习)") E --> E2("Tensorflow (深度学习框架)") E --> E3("Theano (数值计算)") %% GUI开发(跨平台解决方案) F --> F1("PyQT5 (QT界面开发)") F --> F2("wxPython (跨平台GUI)") F --> F3("pyGTK (GNOME应用)") %% 文件处理(2025文档处理方案) G --> G1("pdfminer (PDF解析)") G --> G2("openpyxl (Excel操作)") G --> G3("python-docx (Word处理)") %% 自然语言处理(NLP工具) H --> H1("NLTK (自然语言工具包)") %% 图像处理(最新图形技术) I --> I1("PIL (图像处理库)") I --> I2("MyQR (二维码生成)") %% 实用工具(2025流行工具) J --> J1("Scrapy (爬虫框架)") J --> J2("WeRoBot (微信机器人)") J --> J3("beautifulsoup4 (HTML解析)") J --> J4("Sympy (符号数学)")
文件以及IO操作
graph LR A[Python文件操作] --> B[基础操作] A --> C[读写模式] A --> D[上下文管理] A --> E[异常处理] A --> F[高级功能]B --> B1["open()函数"]B --> B2[路径处理 os.path]B --> B3[文件元数据]C --> C1[文本模式 r/w/a]C --> C2[二进制模式 rb/wb/ab]C --> C3[读写组合 r+/w+/a+]D --> D1[with语句]D --> D2[自动关闭文件]E --> E1[try-except块]E --> E2[OSError处理]F --> F1[内存映射 mmap]F --> F2[临时文件 tempfile]F --> F3[目录操作 os]
open函数
open(
file,
mode='r',
buffering=-1,
encoding=None,
errors=None,
newline=None,
closefd=True,
opener=None
)
核心参数详解
file(必选):
- 接受路径对象或字符串路径
- 2025推荐写法
from pathlib import Path
file_path = Path("data/2025_log.txt")
mode(模式控制):
| 模式 | 描述 | 文件存在行为 | 读写权限 |
|---|---|---|---|
r |
只读 | 打开文件 | 读 |
w |
写入 | 清空内容 | 写 |
a |
追加 | 保留内容 | 写 |
r+ |
读写 | 打开文件 | 读写 |
w+ |
读写 | 清空内容 | 读写 |
a+ |
读写 | 保留内容 | 读写 |
二进制扩展模式(追加b):
# 处理图片/视频等二进制文件
with open("video.mp4", "rb") as f:
data = f.read()
encoding(编码规范):
- 必须显式声明(2025强制规范)
- 推荐值:
utf-8 - 错误示例:
# 不推荐(使用系统默认编码)
open("file.txt", "r")
# 正确写法
open("file.txt", "r", encoding="utf-8")
errors(编码错误处理):
| 策略 | 行为 |
|---|---|
strict |
遇到错误抛出异常(默认) |
ignore |
忽略错误字符 |
replace |
用?替代不可解码字符 |
# 处理老旧系统生成的GBK文件
with open("old_file.txt", "r", encoding="gbk", errors="replace") as f:
content = f.read()
with语句
with语句是用于资源自动管理的核心语法结构,其设计目标是通过上下文管理器协议确保资源的安全获取与释放
核心概念
替代传统的try/finally模式,实现资源自动释放(如文件句柄、数据库连接、线程锁等)
语法原型
with ContextManager() as resource:
# 在此使用资源
- 上下文管理器协议
-
__enter__():进入代码块时调用,返回资源对象 -
__exit__():退出代码块时调用,处理清理逻辑
典型应用场景
文件操作
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")
数据库连接池
# 新型异步数据库连接(2025新特性)
async with aio_db.connect() as conn:
await conn.execute("UPDATE data SET status=1")
线程锁管理
import threading
lock = threading.Lock()
with lock: # 自动获取和释放锁
shared_data.append(new_item)
进阶用法
自定义上下文管理器
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 (...)")
多资源并行管理
# 同时打开输入输出文件
with (open("source.csv", "r") as src,
open("processed.parquet", "wb") as dst):
process_data(src, dst) # 数据流式处理
文件
查(Read)操作
列出目录内容
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()]
获取文件信息
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)操作
创建文件
from pathlib import Path
new_file = Path('new_data.txt')
try:
new_file.touch(exist_ok=False) # 避免覆盖已有文件
except FileExistsError:
print("文件已存在!")
创建目录
from pathlib import Path
new_dir = Path('project/docs/2025')
new_dir.mkdir(parents=True, exist_ok=True) # 自动创建不存在的父目录
删(Delete)操作
安全删除文件
from pathlib import Path
target_file = Path('temp.txt')
if target_file.exists():
target_file.unlink() # 等价于 os.remove
else:
print("文件不存在")
删除目录
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)操作
重命名/移动文件
src = Path('old_name.txt')
dst = Path('new_name.txt')
try:
src.replace(dst) # 原子操作,跨文件系统自动复制+删除
except FileNotFoundError:
print("源文件不存在")
修改文件内容
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() # 截断多余内容
高级技巧
跨平台路径处理
config_path = Path('config') / 'app' / 'settings.yaml' # 自动适配不同系统路径分隔符
临时文件处理
from tempfile import NamedTemporaryFile
with NamedTemporaryFile(delete=False) as tmp:
tmp.write(b'临时数据')
tmp_path = tmp.name # 获取临时文件路径
# 结束后手动删除
Path(tmp_path).unlink()
文件监控
# 需安装:pip install watchfiles
from watchfiles import watch
for changes in watch('./data'):
print(f'检测到文件变化: {changes}')
IO操作
查(Read)操作
文本文件读取
# 使用pathlib自动管理资源
file_path = Path("data.txt")
try:
content = file_path.read_text(encoding="utf-8")
except FileNotFoundError:
print("文件不存在")
except UnicodeDecodeError:
print("编码错误")
二进制文件读取
with open("image.png", "rb") as f:
while chunk := f.read(4096): # 分块读取大文件
process(chunk)
增(Create/Write)操作
安全写入文本文件
output_path = Path("output.log")
try:
output_path.write_text("2025年最新数据\n", encoding="utf-8", errors="replace")
except PermissionError:
print("无写入权限")
追加写入文件
with open("app.log", "a", encoding="utf-8") as f:
f.write(f"[{datetime.now()}] 系统运行正常\n")
改(Update)操作
原地修改文件内容
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}")
安全替换文件
temp_path = Path("temp.txt")
with temp_path.open("w") as tmp:
tmp.write("新内容")
temp_path.replace("original.txt")
删(Delete)操作
清空文件内容
Path("clear.txt").write_text("") # 安全清空
删除文件
target = Path("obsolete.dat")
try:
target.unlink(missing_ok=True) # 等效于os.remove
except PermissionError:
print("删除权限不足")
高级IO技巧
内存流操作
with io.StringIO() as buffer:
buffer.write("内存临时数据")
buffer.seek(0)
print(buffer.read())
二进制流分块处理
with open("large.bin", "rb+") as f:
f.seek(1024)
f.write(b"NEW_BLOCK_DATA") # 直接修改指定位置数据
异步IO操作
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的基石
- 类(Class)
- 定义:类是对象的抽象模板,描述一类对象的共同属性和方法。
-
示例:
class Animal: def __init__(self, name): self.name = name # 属性 def speak(self): # 方法 pass2. 对象(Object) -
定义:对象是类的具体实例,拥有类定义的属性和方法。
-
示例:
dog = Animal("Buddy") # 创建Animal类的实例
OOP三大核心特性
封装(Encapsulation)
- 核心思想:隐藏对象的内部实现细节,仅通过公开的接口与外界交互。
-
作用:
-
提高安全性(如通过私有属性限制直接访问)
- 简化复杂度(用户无需关心内部逻辑)
- 示例:
```
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支持,需谨慎使用)
- 示例:
```
class Dog(Animal):
def speak(self):
return "Woof!"
dog = Dog("Buddy")
print(dog.speak()) # 输出: Woof!
```
多态(Polymorphism)
- 核心思想:同一接口在不同对象中表现出不同行为。
-
实现方式:
-
方法重写(子类覆盖父类方法)
- 接口抽象(不同类实现相同接口)
- 示例:
```
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__,负责创建并返回实例(用户通常无需重写)
代码示例:
class Robot:
def __init__(self, name):
self.name = name # 初始化实例属性
robot = Robot("Optimus") # 自动调用__init__
__slots__(属性白名单)
当不希望其他开发者对类动态添加额外属性时:
class Animal:
def __init__(self,name):
self.name = name
dog = Animal("小黄")
dog.age = 5# 添加了额外属性
可以使用__slots__方法:
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__方法类似,可以阻止动态添加属性:
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 ❌
solts与setattr的选择
| 场景 | 推荐方案 | 特点 |
|---|---|---|
| 高性能/内存敏感 | __slots__ |
内存节省20%~50%,属性严格限制 |
| 传统业务系统 | 动态拦截(__setattr__) |
灵活控制,可自定义错误处理逻辑 |
| 快速原型/脚本开发 | 原生动态属性 | 最大化开发效率 |
__dict__(对象属性字典)
__dict__是Python对象的特殊属性,存储实例级属性的键值对,键为属性名,值为属性数据
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'>, ...} |
核心应用场景
动态属性管理
# 动态添加属性
u.__dict__["age"] = 25 # 等价于 u.age = 25
# 动态删除属性
del u.__dict__["name"] # 等价于 del u.name
对象序列化
import json
# 对象转JSON(需先转为字典)
user_dict = u.__dict__.copy()
user_dict["timestamp"] = 20250421 # 扩展数据
json_data = json.dumps(user_dict)
元编程操作
# 批量修改属性
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实现实例间的数据隔离(每个实例维护独立属性)
实践场景
class BankAccount:
def __init__(self, balance=0):
self.balance = balance # 实例属性
def deposit(self, amount): # 必须包含self
self.balance += amount
静态属性
- 静态属性(类属性):直接定义在类命名空间中的变量,属于类本身而非实例。所有实例共享同一份类属性。
- 关键特征:
- 共享性:所有实例访问同一份类属性值。
- 独立性:修改类属性会全局影响所有实例(除非实例覆盖同名属性)。
- 直接访问:无需实例化即可通过类名访问。
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访问类属性、调用其他类方法,但无法直接访问实例属性(需实例化后操作)。 - 调用方式:支持通过类名或实例调用(本质仍由类处理)。
常见使用场景
替代构造函数
允许通过不同数据格式(如字符串、字典)创建实例,增强灵活性。
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")
工厂模式
根据输入参数返回不同子类实例,隐藏具体实现。
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")
类状态管理
操作类级别属性(如计数器、配置项)。
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
典型示例
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 的装饰器,用于定义 静态方法。其本质是将普通函数封装到类命名空间中,与类和实例无直接数据依赖。
| 特性 | 说明 |
|---|---|
| 参数要求 | 无强制参数(无需 self 或 cls) |
| 访问权限 | 无法直接访问类属性或实例属性 |
| 调用方式 | 通过类名或实例调用(推荐类名调用) |
| 继承行为 | 子类继承父类静态方法时,方法逻辑固定,无法动态绑定到子类 |
定义语法与示例
基础定义
class MathUtils:
@staticmethod
def add(a, b):
return a + b # 纯计算逻辑,无类/实例依赖
# 调用方式
print(MathUtils.add(3, 5)) # 输出: 8 (推荐类名调用)
obj = MathUtils()
print(obj.add(2, 3)) # 输出: 5 (通过实例调用,但不推荐)
动态添加
class Logger:
pass
def log_message(message):
print(f"[LOG] {message}")
Logger.log = staticmethod(log_message) # 动态添加静态方法
Logger.log("System started") # 输出: [LOG] System started
典型应用场景
场景1:工具函数封装
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:辅助计算
class Geometry:
@staticmethod
def circle_area(radius):
return 3.14159 * radius ** 2 # 无需类/实例数据
print(Geometry.circle_area(3)) # 输出: 28.27431
场景3:替代全局函数
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写法
class Dog(Animal): # 括号内指定父类
pass
Java等价写法
class Dog extends Animal { // 使用extends关键字
//...
}
核心差异点
| 特性 | Python | Java |
|---|---|---|
| 继承声明方式 | 类名后括号列父类 | extends关键字 |
| 多重继承支持 | 原生支持(逗号分隔多父类) | 仅单继承,需用接口实现多态 |
| 抽象类要求 | 无强制抽象关键字 | 需用abstract声明 |
| 构造器调用逻辑 | 显式调用父类__init__ |
自动调用super()构造函数 |
父类顺序
MRO
Python通过C3线性化算法确定多继承的初始化顺序,其核心规则:
- 子类优先:子类初始化方法优先于父类
- 从左到右:按继承列表顺序处理父类
- 唯一性:每个父类只初始化一次
执行逻辑
- 非直接调用父类:
super()并非直接调用父类,而是根据当前类的MRO列表决定下一个要调用的类 - 动态查找:在继承链中按MRO顺序依次触发初始化
执行流程示例
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()
输出结果:
C → A → B → object
MRO顺序:
C.mro() = [C, A, B, object]
查看MRO
print(ClassName.__mro__)
# 或
print(ClassName.mro())
初始化中断场景
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__()时,后续父类初始化将中断
强制调用指定父类
class D(Parent1, Parent2):
def __init__(self):
Parent2.__init__(self) # 绕过MRO直接调用
Parent1.__init__(self)
非推荐做法,会破坏MRO规则(可能导致重复初始化)
多态
多态(Polymorphism):同一操作作用于不同对象时,对象会表现出不同的具体行为。Python通过动态类型和鸭子类型实现多态,无需显式接口定义。
三大特性:
- 继承:子类继承父类方法
- 重写:子类修改父类方法实现
- 统一调用:以相同方式调用不同对象的方法
基础示例
# 基类定义
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()) # 输出:嘎嘎! (无需继承)
进阶场景
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种方式
命名约定(弱封装)
class Account:
def __init__(self, balance):
self._balance = balance # 单下划线约定为"受保护"属性
acc = Account(100)
print(acc._balance) # 仍可访问(非强制)
名称修饰(强封装)
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(了解机制但不要主动使用)
属性装饰器(推荐方案)
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" # ❌ 输出警告,拒绝修改
完整案例
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年最新实践,这些方法主要有两大作用:
- 运算符重载:让自定义对象支持
+/-等运算符 - 协议实现:响应
len()/with等内置函数的调用
高频方法
对象生命周期
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年的时光机已销毁
运算符重载
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)
容器协议
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__ |
使实例可像函数一样调用 |
上下文管理器示例
class DatabaseConnection:
def __enter__(self):
print("🔗 数据库连接已建立")
return self # 返回连接对象
def __exit__(self, exc_type, exc_val, exc_tb):
print("🚪 数据库连接已关闭")
with DatabaseConnection() as conn: # 自动管理资源
print("执行数据库操作...")