3. Python基础回顾(上):数据类型与结构、函数与作用域、文件I/O操作
各位同学,欢迎来到第三章。我知道你们可能觉得Python基础没什么好讲的,但请相信我——在边缘AI这个领域,很多坑恰恰就埋在这些基础里。我见过太多人在模型部署时因为数据类型搞错,或者文件读取路径写错,白白浪费一整天。
今天咱们就快速过一遍,重点放在那些你真正会用到的部分。尤其是图片文件读取,这是咱们后续所有视觉模型的基础。
3.1 数据类型与结构:list、dict、set
Python的数据结构,说白了就是装数据的容器。在边缘AI开发中,最常用的就是list、dict和set。我个人的习惯是:能用dict就别用list,能用set就别用list——为什么?往下看。
3.1.1 list(列表)
list是最基础的数据结构。它有序、可重复、可修改。在模型推理时,我们经常用它来存储批量数据。
# 一个典型的list用法
image_paths = ['img_001.jpg', 'img_002.jpg', 'img_003.jpg']
# 添加元素
image_paths.append('img_004.jpg')
# 切片操作
first_three = image_paths[:3]
3.1.2 dict(字典)
dict是Python里最强大的数据结构,没有之一。它用键值对存储数据,查找速度极快。在模型配置、参数传递中,dict无处不在。
# 模型配置字典
model_config = {
'input_shape': (224, 224, 3),
'num_classes': 10,
'learning_rate': 0.001,
'batch_size': 32
}
# 访问配置
print(model_config['input_shape']) # 输出 (224, 224, 3)
3.1.3 set(集合)
set是一个无序、不重复的元素集合。它的最大用途是去重和集合运算。在数据预处理中,我经常用它来检查标签是否有重复。
# 检查标签是否唯一
labels = ['cat', 'dog', 'cat', 'bird', 'dog']
unique_labels = set(labels)
print(unique_labels) # 输出 {'cat', 'dog', 'bird'}
# 集合运算
train_labels = {'cat', 'dog', 'bird'}
test_labels = {'cat', 'fish'}
common = train_labels & test_labels # 交集
print(common) # 输出 {'cat'}
核心要点:
- list:有序、可重复、可修改,适合存储序列数据
- dict:键值对、查找快,适合配置和映射
- set:无序、不重复,适合去重和集合运算
3.2 函数与作用域
函数是代码复用的基本单元。在边缘AI开发中,我们经常把数据预处理、模型推理封装成函数。这里我重点讲两个容易出错的地方:作用域和默认参数。
3.2.1 函数定义与调用
def preprocess_image(image_path, target_size=(224, 224)):
"""图片预处理函数"""
# 读取图片
img = read_image(image_path)
# 调整大小
img = resize_image(img, target_size)
# 归一化
img = img / 255.0
return img
# 调用函数
processed_img = preprocess_image('test.jpg')
3.2.2 作用域:局部 vs 全局
Python的作用域规则其实很简单:函数内部定义的变量是局部变量,函数外部定义的是全局变量。但有一个坑——如果你在函数内部修改全局变量,必须用global关键字声明。
# 全局变量
model = None
def load_model():
global model # 声明要修改全局变量
model = load_weights('model.h5')
def predict(image):
# 这里只是读取全局变量,不需要global
result = model.predict(image)
return result
3.2.3 默认参数的陷阱
Python的默认参数只在函数定义时计算一次。如果默认参数是可变对象(如list、dict),就会出问题。
# 错误的写法
def add_item(item, items=[]):
items.append(item)
return items
print(add_item(1)) # 输出 [1]
print(add_item(2)) # 输出 [1, 2] —— 这里出问题了!
# 正确的写法
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
3.3 文件I/O操作(重点:图片文件读取)
文件读写是边缘AI开发的基础。你想想看,模型训练需要读数据,模型推理需要读图片,模型部署需要写日志——几乎每一步都离不开文件操作。
3.3.1 文本文件读写
# 写入文件
with open('labels.txt', 'w') as f:
f.write('cat\n')
f.write('dog\n')
# 读取文件
with open('labels.txt', 'r') as f:
lines = f.readlines()
print(lines) # 输出 ['cat\n', 'dog\n']
关键点:使用with语句可以自动关闭文件,避免资源泄漏。我见过太多人忘记f.close(),导致文件句柄耗尽——用with就永远不会出这个问题。
3.3.2 图片文件读取(重点)
图片读取是咱们课程的核心。在边缘AI中,常用的图片读取方式有三种:OpenCV、PIL、以及TensorFlow/PyTorch自带的读取方法。我个人的习惯是:开发调试用OpenCV,部署时用PIL(因为依赖更少)。
方法一:使用OpenCV
import cv2
# 读取图片
img = cv2.imread('image.jpg')
# OpenCV默认读取BGR格式,需要转成RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 获取图片信息
height, width, channels = img.shape
print(f'图片尺寸: {width}x{height}, 通道数: {channels}')
方法二:使用PIL(Pillow)
from PIL import Image
# 读取图片
img = Image.open('image.jpg')
# 转换为RGB(确保一致性)
img_rgb = img.convert('RGB')
# 调整大小
img_resized = img_rgb.resize((224, 224))
# 转换为numpy数组
import numpy as np
img_array = np.array(img_resized)
方法三:使用TensorFlow
import tensorflow as tf
# 读取并解码图片
img_raw = tf.io.read_file('image.jpg')
img = tf.image.decode_jpeg(img_raw, channels=3)
# 调整大小
img_resized = tf.image.resize(img, [224, 224])
# 归一化
img_normalized = img_resized / 255.0
- OpenCV读取的是BGR格式,PIL读取的是RGB格式——这个区别我至少踩过5次坑
- 图片路径不要用中文,不要有空格——在嵌入式设备上会出各种奇怪问题
- 批量读取时,注意内存占用。一张224x224的RGB图片约150KB,1000张就是150MB
3.3.3 二进制文件读写
模型权重文件通常是二进制格式。在边缘AI部署时,我们经常需要读取.bin或.h5文件。
# 读取二进制文件
with open('model_weights.bin', 'rb') as f:
data = f.read()
# 写入二进制文件
with open('output.bin', 'wb') as f:
f.write(data)
'rb'和'wb'模式。用文本模式读写二进制文件会导致数据损坏——我曾经因为这个原因,模型加载一直报错,查了整整一天才发现是模式写错了。
3.4 本章小结
好了,这一章的内容就到这里。咱们回顾一下重点:
- 数据结构:list、dict、set各有用途,选对数据结构能让代码效率翻倍
- 函数与作用域:注意全局变量和默认参数的陷阱,这些是新手最容易犯错的地方
- 文件I/O:图片读取是重点,记住OpenCV和PIL的区别,用
with语句管理文件
下一章我们会继续讲Python基础——面向对象编程和异常处理。这些在构建大型AI系统时非常重要。咱们下节课见。