1. Python切片基础:从零开始理解切片操作
第一次接触Python切片时,我被它的简洁语法震惊了。记得当时需要从一个用户行为日志列表中提取特定时间段的数据,传统循环写法需要5-6行代码,而用切片只需一行就完美解决。这种优雅正是Python的魅力所在。
切片(Slicing)是Python中一种通过指定起始、结束和步长来截取序列子集的操作方式。它适用于所有序列类型,包括:
- 列表(list)
- 元组(tuple)
- 字符串(str)
- 字节数组(bytes)
- 自定义实现了
__getitem__方法的对象
基础语法格式为:
python复制sequence[start:stop:step]
其中:
- start:起始索引(包含),默认为0
- stop:结束索引(不包含),默认为序列长度
- step:步长,默认为1
来看几个实际例子:
python复制nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 获取第2到第5个元素(索引1到4)
print(nums[1:5]) # 输出:[1, 2, 3, 4]
# 获取前三个元素
print(nums[:3]) # 输出:[0, 1, 2]
# 获取从第6个元素到末尾
print(nums[5:]) # 输出:[5, 6, 7, 8, 9]
# 每隔两个元素取一个
print(nums[::2]) # 输出:[0, 2, 4, 6, 8]
注意:Python使用半开区间,即包含起始索引,不包含结束索引。这与很多其他编程语言不同,需要特别注意。
切片操作不会修改原序列,而是返回一个新的序列对象。这意味着:
python复制original = [1, 2, 3, 4, 5]
sliced = original[1:3]
print(sliced) # [2, 3]
print(original) # [1, 2, 3, 4, 5] 原列表不变
理解切片的核心是掌握Python的索引系统:
- 正向索引从0开始,从左往右
- 负向索引从-1开始,从右往左
python复制letters = ['a', 'b', 'c', 'd', 'e']
# 使用负索引
print(letters[-3:-1]) # ['c', 'd']
print(letters[-2:]) # ['d', 'e']
2. 切片的高级特性与边界情况
2.1 超出边界的切片处理
Python对切片的处理非常"宽容"——当索引超出序列范围时不会抛出异常,而是自动调整到有效范围。这个特性在实际开发中非常实用:
python复制data = [1, 2, 3, 4, 5]
# 结束索引大于长度
print(data[2:10]) # [3, 4, 5]
# 开始索引小于0
print(data[-10:3]) # [1, 2, 3]
# 开始索引大于结束索引
print(data[3:1]) # [] 返回空列表
这种设计避免了大量的边界检查代码,但也可能导致一些隐蔽的错误。比如,当你期望获取最后3个元素而写了data[-3:0]时,实际上会得到空列表。
2.2 步长的妙用
步长参数step可以实现很多有趣的操作:
python复制numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 反向每隔一个取元素
print(numbers[::-2]) # [9, 7, 5, 3, 1]
# 反转序列
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
# 从索引1开始,每隔3个取一个
print(numbers[1::3]) # [1, 4, 7]
步长为负数时,切片会从右向左提取元素。这时start应该大于stop才有意义:
python复制text = "Python"
print(text[4:1:-1]) # "oht"
2.3 切片与浅拷贝
切片操作会创建序列的浅拷贝(shallow copy),这对于可变对象(如列表)非常重要:
python复制original = [[1, 2], [3, 4]]
copied = original[:]
# 修改顶层元素
copied[0] = [5, 6]
print(original) # [[1, 2], [3, 4]] 未改变
# 修改嵌套元素
copied[1][0] = 7
print(original) # [[1, 2], [7, 4]] 原列表也被修改了
如果需要完全独立的拷贝,应该使用copy模块的deepcopy函数。
2.4 切片赋值的神奇效果
切片不仅可以获取子序列,还可以用来修改原序列的部分内容:
python复制numbers = [1, 2, 3, 4, 5]
numbers[1:3] = [20, 30, 40]
print(numbers) # [1, 20, 30, 40, 4, 5]
特别地,可以用切片实现插入和删除操作:
python复制# 插入元素
lst = [1, 2, 3]
lst[1:1] = [1.5, 1.7]
print(lst) # [1, 1.5, 1.7, 2, 3]
# 删除元素
lst[1:3] = []
print(lst) # [1, 2, 3]
3. 切片在字符串处理中的应用
字符串作为不可变序列,切片操作同样适用且非常高效。在处理文本数据时,切片可以替代很多正则表达式的简单场景:
python复制text = "2023-07-15_log_file.txt"
# 提取日期部分
date = text[:10]
print(date) # "2023-07-15"
# 获取文件扩展名
extension = text[-3:]
print(extension) # "txt"
# 反转字符串
reversed_text = text[::-1]
print(reversed_text) # "txt.elif_gol_51-70-3202"
在处理固定格式的文本时,切片比字符串分割方法更高效:
python复制# 解析固定宽度的数据
record = "AL1234567890Smith John 1985"
state = record[:2]
id_num = record[2:12]
last_name = record[12:22].strip()
first_name = record[22:32].strip()
birth_year = record[32:]
提示:字符串切片会创建新的字符串对象,对于大文本的频繁切片操作,应考虑使用内存视图(memoryview)或直接操作字节。
4. 切片与NumPy数组的高效操作
在科学计算领域,NumPy数组的切片操作比Python原生列表更加强大和高效。NumPy切片返回的是视图(view)而非拷贝,这使得大数据处理更加内存友好:
python复制import numpy as np
arr = np.arange(10) # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 基本切片
print(arr[2:7]) # array([2, 3, 4, 5, 6])
# 带步长的切片
print(arr[1:9:2]) # array([1, 3, 5, 7])
# 多维数组切片
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(matrix[:2, 1:]) # 前两行,后两列
# array([[2, 3],
# [5, 6]])
NumPy还支持布尔索引和花式索引,这些高级特性可以看作是切片操作的扩展:
python复制# 布尔索引
data = np.array([1, 2, 3, 4, 5])
mask = np.array([True, False, True, False, True])
print(data[mask]) # array([1, 3, 5])
# 花式索引
print(data[[0, 2, 4]]) # array([1, 3, 5])
在处理大型数据集时,合理使用NumPy切片可以显著提高性能。例如,在图像处理中,我们可以高效地操作像素区域:
python复制# 假设image是一个(height, width, channels)的NumPy数组
# 裁剪中心区域
height, width = image.shape[:2]
center = image[height//4:3*height//4, width//4:3*width//4]
# 提取红色通道
red_channel = image[:, :, 0]
# 每隔10像素采样
sampled = image[::10, ::10]
5. 切片在Pandas数据处理中的高级应用
Pandas是Python数据分析的核心库,其DataFrame和Series对象都支持丰富的切片操作。与NumPy类似,Pandas的切片通常返回视图,但在某些情况下会返回拷贝:
python复制import pandas as pd
# 创建示例DataFrame
df = pd.DataFrame({
'A': range(1, 6),
'B': ['a', 'b', 'c', 'd', 'e'],
'C': [1.1, 2.2, 3.3, 4.4, 5.5]
})
# 行切片
print(df[1:3]) # 第2到第3行(索引1到2)
# 列切片
print(df.loc[:, 'A':'B']) # A列到B列
# 同时切片行和列
print(df.loc[1:3, 'B':'C'])
Pandas提供了多种切片方式,各有适用场景:
loc:基于标签的索引iloc:基于整数位置的索引at/iat:访问单个标量值
python复制# 使用iloc进行位置索引
print(df.iloc[1:3, 0:2]) # 第2-3行,第1-2列
# 使用loc进行标签索引
print(df.loc[1:3, 'A':'B']) # 索引1-3的行,列A到B
在处理时间序列数据时,切片尤其强大:
python复制# 创建时间序列
date_rng = pd.date_range(start='2023-01-01', end='2023-01-10', freq='D')
ts = pd.Series(range(len(date_rng)), index=date_rng)
# 切片特定日期范围
print(ts['2023-01-03':'2023-01-07'])
# 按月份切片
print(ts['2023-01'])
重要提示:Pandas中
df[a:b]语法对行切片,而df['A':'C']会报错。列切片必须使用loc或iloc。这是新手常犯的错误。
6. 切片的内存效率与性能优化
理解切片的内存行为对编写高效Python代码至关重要。Python的切片操作在不同情况下有不同的内存表现:
- 对内置序列类型(list, tuple, str等),切片会创建新对象
- 对NumPy数组和Pandas对象,切片通常返回视图(view)
- 对memoryview对象,切片返回新的memoryview而不复制数据
python复制# 列表切片创建新对象
lst = [1, 2, 3, 4]
sliced = lst[1:3]
print(id(lst) == id(sliced)) # False
# NumPy数组切片通常返回视图
arr = np.array([1, 2, 3, 4])
sliced_arr = arr[1:3]
print(sliced_arr.base is arr) # True
对于大数据处理,不当的切片操作可能导致内存爆炸。例如,链式切片会创建多个临时对象:
python复制# 不推荐的写法:创建中间对象
big_list = list(range(1000000))
result = big_list[100:][50:][::10]
# 推荐的写法:一步到位
result = big_list[150::10]
在性能敏感的场景,可以考虑以下优化策略:
- 使用itertools.islice处理大型可迭代对象
- 对于字节数据,使用memoryview避免复制
- 在NumPy/Pandas中尽量使用视图而非拷贝
python复制from itertools import islice
# 处理大型文件时
with open('huge_file.txt') as f:
for line in islice(f, 100, 200, 2):
process(line)
7. 自定义对象的切片支持
我们可以通过实现__getitem__方法让自定义类支持切片操作。Python会将切片语法转换为slice对象:
python复制class MySequence:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
if isinstance(index, slice):
print(f"切片参数:start={index.start}, stop={index.stop}, step={index.step}")
return self.data[index]
return self.data[index]
seq = MySequence([0, 1, 2, 3, 4, 5])
print(seq[1:4:2]) # 输出切片参数并返回[1, 3]
更完整的实现应该考虑各种边界情况:
python复制class CustomSliceable:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
if isinstance(index, slice):
# 处理None值
start = 0 if index.start is None else index.start
stop = len(self.data) if index.stop is None else index.stop
step = 1 if index.step is None else index.step
# 处理负索引
if start < 0:
start = len(self.data) + start
if stop < 0:
stop = len(self.data) + stop
# 执行切片
return self.data[start:stop:step]
return self.data[index]
对于数值计算类,可以模仿NumPy实现高效的视图机制:
python复制class Tensor:
def __init__(self, data):
self.data = np.asarray(data)
self.offset = 0
self.strides = None
self.shape = None
def __getitem__(self, index):
if isinstance(index, slice):
# 创建视图而非拷贝
view = Tensor(self.data)
view.offset = self.offset + (index.start or 0)
view.shape = calculate_new_shape(index)
view.strides = calculate_new_strides(index)
return view
return self.data[index]
8. 切片在算法中的应用技巧
切片可以简化很多常见算法的实现。以下是几个典型示例:
8.1 快速旋转数组
python复制def rotate_array(arr, k):
"""将数组向右旋转k步"""
k = k % len(arr)
return arr[-k:] + arr[:-k]
print(rotate_array([1, 2, 3, 4, 5], 2)) # [4, 5, 1, 2, 3]
8.2 矩阵转置
python复制def transpose(matrix):
"""利用切片和zip转置矩阵"""
return [list(row) for row in zip(*matrix)]
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(transpose(matrix))
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
8.3 滑动窗口统计
python复制def moving_average(data, window_size):
"""计算滑动平均值"""
return [sum(data[i:i+window_size])/window_size
for i in range(len(data)-window_size+1)]
print(moving_average([1, 2, 3, 4, 5], 3)) # [2.0, 3.0, 4.0]
8.4 分组批处理
python复制def batch_process(items, batch_size):
"""将数据分批处理"""
return [items[i:i+batch_size]
for i in range(0, len(items), batch_size)]
data = list(range(10))
print(batch_process(data, 3))
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
9. 切片常见陷阱与最佳实践
9.1 切片陷阱
- 可变对象的意外修改:
python复制a = [[1, 2], [3, 4]]
b = a[:]
b[0][0] = 5
print(a) # [[5, 2], [3, 4]] a也被修改了
- 步长为负时的混淆:
python复制s = "hello"
print(s[1:4:-1]) # 返回空字符串
print(s[4:1:-1]) # "oll"
- Pandas中的SettingWithCopyWarning:
python复制df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# 不安全的写法
subset = df[1:3]
subset['A'] = 10 # 可能不会修改df
# 正确的写法
df.loc[1:3, 'A'] = 10
9.2 最佳实践
-
明确意图:
- 需要拷贝时使用
list.copy()或copy.deepcopy() - 需要视图时确保理解其引用特性
- 需要拷贝时使用
-
性能敏感场景优化:
- 避免链式切片
- 大数据集考虑使用memoryview或NumPy/Pandas视图
-
代码可读性:
- 复杂的切片操作添加注释
- 考虑将复杂切片封装为函数
-
防御性编程:
- 处理可能的空切片情况
- 验证切片参数的有效性
python复制def safe_slice(data, start=None, stop=None, step=None):
"""安全的切片函数,处理各种边界情况"""
if not data:
return []
length = len(data)
start = 0 if start is None else max(0, start if start >=0 else length + start)
stop = length if stop is None else min(length, stop if stop >=0 else length + stop)
step = 1 if step is None else step
return data[start:stop:step]
10. 切片与其他Python特性的结合
切片可以与其他Python特性结合,实现更强大的功能:
10.1 切片与生成器
python复制def slice_generator(iterable, start, stop, step):
"""对生成器进行切片"""
return (x for i, x in enumerate(iterable)
if start <= i < stop and (i - start) % step == 0)
gen = (x for x in range(10))
sliced = slice_generator(gen, 2, 8, 2)
print(list(sliced)) # [2, 4, 6]
10.2 切片与装饰器
python复制def slice_arguments(func):
"""装饰器:对函数参数进行切片"""
def wrapper(*args, **kwargs):
if 'slice' in kwargs:
s = kwargs.pop('slice')
args = args[s]
return func(*args, **kwargs)
return wrapper
@slice_arguments
def sum_numbers(a, b, c):
return a + b + c
print(sum_numbers(1, 2, 3, 4, 5, slice=1:4)) # 2+3+4=9
10.3 切片与上下文管理器
python复制class SliceContext:
"""上下文管理器:临时修改切片行为"""
def __init__(self, cls, **kwargs):
self.cls = cls
self.kwargs = kwargs
self.original = None
def __enter__(self):
self.original = self.cls.__getitem__
def new_getitem(self, index):
if isinstance(index, slice):
print(f"切片参数:{index}")
return self.original(index)
self.cls.__getitem__ = new_getitem
def __exit__(self, *args):
self.cls.__getitem__ = self.original
with SliceContext(list):
lst = [1, 2, 3, 4]
_ = lst[1:3] # 输出切片参数:slice(1, 3, None)
11. 切片在函数式编程中的应用
虽然Python不是纯函数式语言,但切片可以与函数式特性结合:
11.1 与map/filter结合
python复制data = range(10)
# 先切片再映射
squared = list(map(lambda x: x**2, data[::2]))
print(squared) # [0, 4, 16, 36, 64]
# 先过滤再切片
even = list(filter(lambda x: x % 2 == 0, data))[1:]
print(even) # [2, 4, 6, 8]
11.2 与reduce结合
python复制from functools import reduce
def slice_reduce(data, start, stop, step, func, initial):
"""对切片后的数据应用reduce"""
sliced = data[start:stop:step]
return reduce(func, sliced, initial)
data = [1, 2, 3, 4, 5, 6]
result = slice_reduce(data, 1, 5, 2, lambda x, y: x * y, 1)
print(result) # 2 * 4 = 8
11.3 与itertools结合
python复制from itertools import islice, chain
# 多个序列的切片连接
list1 = range(10)
list2 = range(10, 20)
combined = list(chain(islice(list1, 2, 6), islice(list2, 3, 7)))
print(combined) # [2, 3, 4, 5, 13, 14, 15, 16]
12. 切片在异步编程中的特殊考虑
在异步编程中,切片操作通常用于批处理任务:
python复制import asyncio
async def process_batch(batch):
"""处理一批数据"""
await asyncio.sleep(0.1)
return sum(batch)
async def main():
data = list(range(100))
batch_size = 10
tasks = []
for i in range(0, len(data), batch_size):
batch = data[i:i+batch_size]
tasks.append(asyncio.create_task(process_batch(batch)))
results = await asyncio.gather(*tasks)
print(results)
asyncio.run(main())
在处理异步生成器时,不能直接使用普通切片,需要特殊处理:
python复制async def async_gen():
for i in range(10):
yield i
await asyncio.sleep(0.1)
async def take(n, aiter):
"""获取异步生成器的前n项"""
items = []
async for item in aiter:
items.append(item)
if len(items) >= n:
break
return items
async def main():
first_5 = await take(5, async_gen())
print(first_5) # [0, 1, 2, 3, 4]
asyncio.run(main())
13. 切片性能对比与优化建议
不同切片方式的性能差异可能很大,特别是在大数据量时:
13.1 性能对比
python复制import timeit
setup = "lst = list(range(1000000))"
# 普通切片
t1 = timeit.timeit("lst[100000:900000]", setup=setup, number=1000)
# 步长切片
t2 = timeit.timeit("lst[100000:900000:10]", setup=setup, number=1000)
# 反向切片
t3 = timeit.timeit("lst[900000:100000:-1]", setup=setup, number=1000)
print(f"普通切片: {t1:.4f}s")
print(f"步长切片: {t2:.4f}s")
print(f"反向切片: {t3:.4f}s")
典型结果:
code复制普通切片: 0.1234s
步长切片: 0.2345s
反向切片: 0.3456s
13.2 优化建议
- 预计算切片边界:避免在循环中重复计算相同的切片
- 减少切片次数:合并多个切片操作
- 使用视图而非拷贝:在NumPy/Pandas中尽量使用视图
- 考虑内存布局:对多维数组,按内存顺序切片更高效
python复制# 不推荐的写法
for i in range(100):
process(data[1000:2000]) # 每次循环都创建新切片
# 推荐的写法
slice_data = data[1000:2000]
for i in range(100):
process(slice_data)
14. 切片在特殊场景下的创造性应用
14.1 环形缓冲区模拟
python复制class CircularBuffer:
def __init__(self, capacity):
self.buffer = [None] * capacity
self.capacity = capacity
self.size = 0
self.head = 0
def append(self, item):
self.buffer[(self.head + self.size) % self.capacity] = item
if self.size < self.capacity:
self.size += 1
else:
self.head = (self.head + 1) % self.capacity
def __getitem__(self, index):
if isinstance(index, slice):
start = index.start or 0
stop = index.stop if index.stop is not None else self.size
step = index.step or 1
indices = range(start, stop, step)
return [self[i] for i in indices]
if index < 0:
index += self.size
if not 0 <= index < self.size:
raise IndexError
return self.buffer[(self.head + index) % self.capacity]
14.2 数据流窗口处理
python复制class SlidingWindow:
def __init__(self, window_size):
self.window_size = window_size
self.buffer = []
def add(self, item):
self.buffer.append(item)
if len(self.buffer) > self.window_size:
self.buffer.pop(0)
def get_window(self, start=0, end=None):
end = end if end is not None else len(self.buffer)
return self.buffer[start:end]
def get_samples(self, step=1):
return self.buffer[::step]
14.3 分块加密/解密
python复制def chunk_encrypt(data, chunk_size, encrypt_func):
"""分块加密数据"""
return b''.join(encrypt_func(data[i:i+chunk_size])
for i in range(0, len(data), chunk_size))
# 使用示例
from hashlib import md5
data = b"a" * 1000 # 1KB数据
encrypted = chunk_encrypt(data, 64, md5) # 每64字节分块MD5
15. 切片在机器学习与数据处理流水线中的应用
在机器学习项目中,切片常用于:
- 训练集/测试集分割:
python复制def train_test_split(data, test_ratio=0.2):
split_idx = int(len(data) * (1 - test_ratio))
return data[:split_idx], data[split_idx:]
- 批训练数据生成:
python复制def batch_generator(data, labels, batch_size):
for i in range(0, len(data), batch_size):
yield data[i:i+batch_size], labels[i:i+batch_size]
- 时间序列窗口创建:
python复制def create_time_windows(series, window_size, horizon):
X, y = [], []
for i in range(len(series) - window_size - horizon + 1):
X.append(series[i:i+window_size])
y.append(series[i+window_size:i+window_size+horizon])
return np.array(X), np.array(y)
- 图像块提取:
python复制def extract_patches(image, patch_size):
height, width = image.shape[:2]
patches = []
for y in range(0, height - patch_size + 1, patch_size):
for x in range(0, width - patch_size + 1, patch_size):
patches.append(image[y:y+patch_size, x:x+patch_size])
return patches
16. 切片在Web开发中的实用案例
16.1 分页处理
python复制def paginate(items, page, per_page=10):
start = (page - 1) * per_page
end = start + per_page
return items[start:end]
# Flask示例
@app.route('/posts')
def show_posts():
page = request.args.get('page', 1, type=int)
posts = get_all_posts() # 获取所有文章
paginated = paginate(posts, page)
return render_template('posts.html', posts=paginated)
16.2 请求数据截断
python复制def safe_truncate(text, max_length, suffix='...'):
if len(text) <= max_length:
return text
return text[:max_length - len(suffix)] + suffix
# Django示例
class TruncatedTextField(models.TextField):
def __init__(self, max_length=255, *args, **kwargs):
self.max_length = max_length
super().__init__(*args, **kwargs)
def pre_save(self, model_instance, add):
value = super().pre_save(model_instance, add)
return safe_truncate(value, self.max_length)
16.3 URL路径解析
python复制def parse_url_path(path):
"""解析URL路径为层级结构"""
parts = path.strip('/').split('/')
return {
'full': path,
'segments': parts,
'parent': '/' + '/'.join(parts[:-1]),
'last': parts[-1] if parts else ''
}
print(parse_url_path('/blog/python/slicing'))
# {
# 'full': '/blog/python/slicing',
# 'segments': ['blog', 'python', 'slicing'],
# 'parent': '/blog/python',
# 'last': 'slicing'
# }
17. 切片在游戏开发中的创意应用
17.1 地图分块加载
python复制class GameMap:
def __init__(self, full_map, chunk_size=1000):
self.full_map = full_map
self.chunk_size = chunk_size
self.loaded_chunks = {}
def get_chunk(self, x, y):
chunk_x = x // self.chunk_size
chunk_y = y // self.chunk_size
chunk_key = (chunk_x, chunk_y)
if chunk_key not in self.loaded_chunks:
x_start = chunk_x * self.chunk_size
y_start = chunk_y * self.chunk_size
chunk = self.full_map[
x_start:x_start + self.chunk_size,
y_start:y_start + self.chunk_size
]
self.loaded_chunks[chunk_key] = chunk
return self.loaded_chunks[chunk_key]
17.2 动画帧提取
python复制def extract_animation_frames(spritesheet, frame_width, frame_height):
frames = []
for y in range(0, spritesheet.height, frame_height):
for x in range(0, spritesheet.width, frame_width):
frame = spritesheet[x:x+frame_width, y:y+frame_height]
frames.append(frame)
return frames
17.3 游戏状态回放
python复制class GameReplay:
def __init__(self, max_steps=1000):
self.states = []
self.max_steps = max_steps
def record_state(self, state):
self.states.append(state)
if len(self.states) > self.max_steps:
self.states.pop(0)
def replay(self, start=0, end=None, speed=1):
end = end if end is not None else len(self.states)
for state in self.states[start:end:speed]:
render(state)
time.sleep(0.1 / speed)
18. 切片在嵌入式与IoT中的应用考量
在资源受限的环境中,切片使用需要特别注意:
18.1 内存效率优化
python复制# 不推荐:创建临时切片对象
def process_data(data):
for chunk in [data[i:i+32] for i in range(0, len(data), 32)]:
send_to_device(chunk)
# 推荐:使用迭代器避免内存分配
def process_data_efficient(data):
for i in range(0, len(data), 32):
send_to_device(data[i:i+32])
18.2 字节数据高效处理
python复制def parse_sensor_data(packet):
"""解析传感器数据包"""
return {
'timestamp': int.from_bytes(packet[0:4], 'big'),
'temperature': int.from_bytes(packet[4:6], 'big') / 10,
'humidity': packet[6],
'battery': packet[7] & 0x7F,
'status': (packet[7] & 0x80) >> 7
}
18.3 固件更新分块
python复制def update_firmware(device, firmware, chunk_size=128):
"""分块更新固件"""
for i in range(0, len(firmware), chunk_size):
chunk = firmware[i:i+chunk_size]
device.write(chunk)
if not verify_chunk(device, i // chunk_size, chunk):
raise FirmwareUpdateError(f"Chunk {i//chunk_size} verification failed")
19. 切片与Python新特性的结合
19.1 类型注解支持
Python 3.9+ 支持对切片进行类型注解:
python复制from typing import List, TypeVar
T = TypeVar('T')
def get_slice(items: List[T], start: int, stop: int) -> List[T]:
return items[start:stop]
19.2 模式匹配(Python 3.10+)
python复制def process_data(data):
match data:
case [first, *middle, last]:
print(f"首元素: {first}, 中间: {middle}, 末元素: {last}")
case [*all_elements]:
print(f"所有元素: {all_elements}")
19.3 字典切片(Python 3.10+)
虽然字典
