Python 快速看代码入门(面向有 C/C++ 基础)
Python 快速看代码入门(面向有 C/C++ 基础)
这份文档不是系统讲 Python 语法,而是为了让你能 快速看懂项目里的 Python 脚本,尤其像 “导包 + 配置 + 回调 + 线程 + 文件 IO + 数据处理”的工程代码。
默认你已经有 C / C++ 基础,所以本文重点讲:
- Python 代码长什么样
- 常见语法块怎么读
- 和 C / C++ 最容易混淆的地方
- 结合 真实项目
data_collection.py的真实用法来理解
https://github.com/zxzm-zak/FastUMI_Data#
1. 先建立整体感觉
Python 和 C / C++ 最大的阅读差异不是“能力不同”,而是“表达方式不同”:
- Python 靠缩进表示代码块
- Python 变量不用先写类型
- Python 容器和字符串操作很重
- Python 大量使用库函数和对象方法
- Python 常把文件、异常、遍历写得很紧凑
比如你在 C++ 里可能会写:
if (ok) {
do_work();
}
Python 对应就是:
if ok:
do_work()
核心区别:
- 没有花括号
- 没有分号
- 冒号
:后面接一个缩进块
2. 读 Python 代码的推荐顺序
看到一个 Python 文件,建议按这个顺序读:
- 看文件顶部注释或文档字符串,先知道这个脚本干什么
- 看
import - 看全局配置和路径变量
- 看函数定义
def ... - 最后看
if __name__ == "__main__":
在 data_collection.py 里就是:
- 上面是脚本说明
- 中间是导包、配置、路径、缓冲区
- 再下面是
video_callback、trajectory_callback、write_video这些函数 - 最后
if __name__ == "__main__":才是真正执行入口
3. import 怎么看
Python 常见导入写法:
import os
import json
import pandas as pd
from time import sleep
from collections import deque
可以这样理解:
import os
类似 C++ 里引入一个命名空间,后面用os.path.join(...)import pandas as pd
给库起别名,后面写pd.read_csv(...)from time import sleep
直接把sleep这个名字拿进当前作用域,后面可以直接写sleep(0.001)
对应到当前项目:
import pandas as pd
from collections import deque
from cv_bridge import CvBridge
读的时候你只需要知道:
pd.xxx是 pandasdeque()是双端队列CvBridge()是 ROS 图像消息和 OpenCV 图像之间的转换器
4. 变量不写类型,怎么看
Python 变量通常直接赋值:
task = args.task
num_episodes = args.num_episodes
video_buffer = deque()
frame_width, frame_height = cfg['cam_width'], cfg['cam_height']
和 C / C++ 的区别:
- 不写
int、float、std::string - 变量类型在运行时由值决定
- 可以一行给多个变量赋值
比如:
frame_width, frame_height = cfg['cam_width'], cfg['cam_height']
等价于概念上的:
auto frame_width = cfg["cam_width"];
auto frame_height = cfg["cam_height"];
但 Python 更常见、更自然。
5. 字典、列表、元组,先会认
Python 里最常见的 3 种容器:
5.1 列表 list
names = ["front", "left", "right"]
类似动态数组 / std::vector。
常见操作:
names.append("top")
len(names)
names[0]
5.2 字典 dict
config = {
"robot_type": "XARM6",
"data_dir": "./dataset"
}
类似 std::unordered_map<string, ...>。
取值方式:
config["robot_type"]
config["data_dir"]
项目里大量是这种写法:
cfg['camera_names']
config['task_config']['ros']['video_topic']
就是多层字典嵌套取值。
5.3 元组 tuple
item = (frame, timestamp)
可以把它理解成“轻量、不准备改的固定组合”。
项目里缓冲区常塞这种东西:
video_buffer.append((frame, timestamp))
6. if / elif / else
这是最基本的条件分支:
if torch.cuda.is_available():
device = 'cuda'
else:
device = 'cpu'
和 C / C++ 一样,只是写法变成:
- 条件后面没有括号也可以
- 冒号
: - 用缩进表示代码块
elif 就是 C / C++ 的 else if:
if x > 0:
print("positive")
elif x == 0:
print("zero")
else:
print("negative")
7. for ... in ... 是最常见遍历
这是 Python 阅读里最重要的一个。
7.1 遍历列表
for cam_name in cfg['camera_names']:
data_dict[f'/observations/images/{cam_name}'] = []
意思是:
- 从
cfg['camera_names']里一个个取元素 - 每次取到的元素叫
cam_name
近似 C++:
for (const auto& cam_name : camera_names) {
...
}
7.2 遍历范围
for episode in range(num_episodes):
...
相当于:
for (int episode = 0; episode < num_episodes; ++episode) {
...
}
7.3 同时取索引和值
for idx, row in downsampled_timestamps.iterrows():
...
你可以先理解成:
idx是编号row是当前这一行数据
8. while 循环
项目里线程函数常见:
while not rospy.is_shutdown():
...
意思是:
- 只要 ROS 系统还没关闭,就一直循环
和 C / C++ 对应大概是:
while (!ros::isShutDown()) {
...
}
9. def 就是定义函数
Python 用 def 定义函数:
def write_video():
...
带参数时:
def video_callback(msg):
...
和 C / C++ 的差别:
- 不写返回类型
- 不写参数类型
- 通过缩进表示函数体
如果函数有返回值,通常会写:
def add(a, b):
return a + b
10. with 是必须会的
这是 Python 文件操作里最常见的写法。
with open('config/config.json', 'r') as f:
config = json.load(f)
你可以把它理解成:
- 打开文件
- 在这个代码块里使用它
- 代码块结束后自动关闭文件
近似于 C++ 里的“RAII 自动释放资源”,只是 Python 用 with 显式写出来。
10.1 为什么比手动 open / close 更推荐
如果写成:
f = open('a.txt', 'r')
data = f.read()
f.close()
中间一旦异常,就可能没执行到 close()。
而 with 会更安全:
with open('a.txt', 'r') as f:
data = f.read()
10.2 你这个项目里的真实用法
with open(TRAJECTORY_PATH_TEMP, 'w', newline='') as trajectory_file, \
open(TIMESTAMP_PATH_TEMP, 'w', newline='') as timestamp_file:
...
这表示:
- 同时打开两个文件
- 一个代码块里一起使用
- 离开块后自动关闭
11. open 常见模式
11.1 读文件
with open('a.json', 'r') as f:
text = f.read()
11.2 写文件
with open('a.txt', 'w') as f:
f.write("hello")
11.3 追加写
with open('log.txt', 'a') as f:
f.write("one more line\n")
模式含义:
'r'读取'w'写入,若文件已存在通常会覆盖'a'追加
你项目里就有:
with open(STATE_PATH, 'a', newline='') as csv_file2:
csv_writer2 = csv.writer(csv_file2)
意思是往已有 states.csv 后面继续追加。
12. try / except / finally 很重要
这相当于 C++ 的异常处理思路。
try:
start_recording()
except Exception as e:
print(f"An error occurred: {e}")
raise
finally:
frame_timestamp_writer.writerow([episode, first_frame_timestamp])
video_writer.release()
可以这样理解:
try:先尝试执行except:如果报错,就进入异常处理finally:不管报不报错,最后都执行
12.1 这段在项目里是什么意思
在 data_collection.py 里:
- 正常情况:录制完成
- 出错情况:打印错误并继续抛出
- 但无论如何,都要:
- 写首帧时间戳
- 释放视频对象
- 继续做清理和收尾
12.2 和 C++ 对比
大致类似:
try {
start_recording();
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
throw;
}
// finally 在 C++ 里没有原生关键字,通常靠析构或手工收尾实现
Python 的 finally 就是把“收尾一定要执行”这件事直接写出来。
13. as 的常见含义
Python 里 as 很常见,通常有两种意思。
13.1 在 with 里起别名
with open('a.txt', 'r') as f:
...
意思是把打开的文件对象命名为 f。
13.2 在异常处理中起别名
except Exception as e:
print(e)
意思是把捕获到的异常对象命名为 e。
14. 字符串格式化:f"..." 很常用
这是 Python 非常高频的写法:
filename = f"{int(frame_idx / 3)}.jpg"
print(f"Episode {episode + 1}/{num_episodes} started!")
意思是把变量直接嵌进字符串。
相当于 C++ 里用格式化库,比如:
std::format("Episode {}/{} started!", episode + 1, num_episodes);
看到 {...} 时,一般就是把表达式的值放进去。
15. 对象方法怎么读
Python 代码里很多是:
video_buffer.append((frame, timestamp))
video_thread.start()
video_thread.join()
trajectory['Timestamp'].astype(float)
形式是:
对象.方法(...)
和 C++ 很像,只是通常用 .,不是 ->。
例如:
append:往容器后面追加start:启动线程join:等待线程结束astype(float):转换数据类型
16. 类似“引用传递”的感觉从哪来
Python 没有 C++ 那种裸指针 / 引用语法,但对象经常表现出“共享同一个对象”的效果。
例如:
data_dict = {'/action': []}
lst = data_dict['/action']
lst.append(1)
这时 data_dict['/action'] 里面也会变,因为它们指向的是同一个列表对象。
所以读 Python 时,不要死盯“值拷贝还是引用拷贝”的语法形式,而要记住:
- 不可变对象:如整数、字符串、元组
- 可变对象:如列表、字典
列表、字典改内容时,经常会影响共享它们的其他变量。
17. global 是什么意思
项目里有:
def video_callback(msg):
global first_frame_timestamp, first_time_judger
意思是:
- 这个函数里要修改外部的全局变量
- 如果不写
global,Python 会把它当成本地变量处理
简单理解:
- 读全局变量通常不用写
global - 改全局变量时经常需要写
global
18. None 类似“空”
Python 里的空值通常是 None:
video_subscriber = None
trajectory_subscriber = None
可以把它理解成:
- “还没有对象”
- 类似空指针 / null 的概念,但不是 C++ 那种裸地址
判断时常见:
if x is None:
...
19. 布尔表达式常见写法
19.1 not
while not rospy.is_shutdown():
...
就是逻辑非。
19.2 链式比较
Python 可以写:
if 0 < x < 10:
...
相当于:
if (0 < x && x < 10) {
...
}
20. 下标访问和切片
20.1 普通下标
names[0]
trajectory['Timestamp']
20.2 切片
项目里很关键的一句:
downsampled_timestamps = timestamps.iloc[::3].reset_index(drop=True)
重点看 ::3,它表示:
- 从头到尾
- 每隔 3 个取一个
类似概念上:
for (int i = 0; i < n; i += 3) {
...
}
所以这句的含义就是“每 3 帧保留 1 帧”。
21. 列表推导式:先会认,不一定马上自己写
项目里有一句:
idx = len([name for name in os.listdir(data_path) if os.path.isfile(os.path.join(data_path, name))])
这叫列表推导式。
可以拆成普通写法理解:
tmp = []
for name in os.listdir(data_path):
if os.path.isfile(os.path.join(data_path, name)):
tmp.append(name)
idx = len(tmp)
阅读建议:
- 先别怕
- 从后往前看
- 把它 mentally 展开成普通
for + if + append
22. 常见工程库调用,先知道“在干嘛”即可
看工程 Python,不需要每个库都学透,只要知道职责。
在这个脚本里常见的是:
os.path.join(...)
拼路径os.makedirs(..., exist_ok=True)
创建目录;已存在也不报错json.load(f)
从 JSON 文件读配置argparse.ArgumentParser()
解析命令行参数threading.Thread(...)
启动线程deque()
双端队列pd.read_csv(...)
读 CSV 为表格np.abs(...)
数组绝对值cv2.VideoWriter(...)
写视频h5py.File(...)
写 HDF5 文件
阅读时先问自己:
- 这是在“读文件 / 写文件 / 处理数组 / 操作线程 / 操作路径”中的哪一类?
通常就够了。
23. 看 data_collection.py 时最值得先懂的几句
23.1 读配置
with open('config/config.json', 'r') as f:
config = json.load(f)
意思:打开配置文件,读成 Python 字典。
23.2 创建目录
os.makedirs(data_path, exist_ok=True)
意思:如果目录不存在就创建,已存在也没关系。
23.3 建立 ROS 订阅
video_subscriber = rospy.Subscriber(..., Image, video_callback, ...)
意思:收到图像消息时,调用 video_callback。
23.4 往缓冲区塞数据
video_buffer.append((frame, timestamp))
意思:把一帧图像和它的时间戳存起来,等后台线程处理。
23.5 录制主循环
for episode in range(num_episodes):
...
意思:录多段 episode。
23.6 异常收尾
try:
start_recording()
except Exception as e:
...
finally:
...
意思:无论成功失败,都要执行收尾。
24. C / C++ 读者最容易踩的坑
24.1 缩进就是语法
在 C++ 里缩进乱一点通常还能编译;在 Python 里不行。
缩进层级本身就是代码块边界。
24.2 变量类型不是写出来的
你要根据上下文判断:
[]多半是列表{}多半是字典()有时是元组,有时是函数调用参数
24.3 很多“短代码”其实信息量很大
比如:
timestamps.iloc[::3].reset_index(drop=True)
一行里连着几步操作。
阅读时拆开看:
timestamps.iloc[::3].reset_index(drop=True)
24.4 with 和 finally 是资源管理重点
它们在 Python 里承担了很多 C++ 中“析构自动清理”的角色。
24.5 Python 常把数据结构和逻辑写在一起
比如一边遍历,一边构造字典,一边写文件,这在工程脚本里很常见。
不要试图像读模板元编程那样逐 token 分析,先抓住“这段在干什么”。
25. 一份最小阅读词典
你先记住这些,读大多数工程 Python 就够用了:
def:定义函数if / elif / else:条件分支for ... in ...:遍历while:循环with:进入一个资源管理上下文,常用于文件open:打开文件try / except / finally:异常处理和收尾return:返回值import:导入模块as:起别名None:空值True / False:布尔值len(x):长度range(n):0..n-1append:追加到列表join:拼路径或等待线程,具体看对象是谁
26. 如果你的目标只是“快速看懂代码”
建议按这个顺序学,不要一开始就钻语法细节:
-
先只看控制流
看if、for、while、try -
再看数据流
看变量从哪来,到哪去 -
再看库函数
-
最后再抠语法糖
比如切片、列表推导式、f-string
27. 下一步怎么练最快
最推荐的方法不是刷语法题,而是拿 data_collection.py 直接练:
- 先只看主入口
if __name__ == "__main__": - 再跳去看它调用的函数
- 每看到一条不熟的 Python 语法,就回到这份文档对照
更多推荐


所有评论(0)