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 文件,建议按这个顺序读:

  1. 看文件顶部注释或文档字符串,先知道这个脚本干什么
  2. import
  3. 看全局配置和路径变量
  4. 看函数定义 def ...
  5. 最后看 if __name__ == "__main__":

data_collection.py 里就是:

  • 上面是脚本说明
  • 中间是导包、配置、路径、缓冲区
  • 再下面是 video_callbacktrajectory_callbackwrite_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 是 pandas
  • deque() 是双端队列
  • 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++ 的区别:

  • 不写 intfloatstd::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)

一行里连着几步操作。
阅读时拆开看:

  1. timestamps
  2. .iloc[::3]
  3. .reset_index(drop=True)

24.4 withfinally 是资源管理重点

它们在 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-1
  • append:追加到列表
  • join:拼路径或等待线程,具体看对象是谁

26. 如果你的目标只是“快速看懂代码”

建议按这个顺序学,不要一开始就钻语法细节:

  1. 先只看控制流
    ifforwhiletry

  2. 再看数据流
    看变量从哪来,到哪去

  3. 再看库函数

  4. 最后再抠语法糖
    比如切片、列表推导式、f-string


27. 下一步怎么练最快

最推荐的方法不是刷语法题,而是拿 data_collection.py 直接练:

  1. 先只看主入口 if __name__ == "__main__":
  2. 再跳去看它调用的函数
  3. 每看到一条不熟的 Python 语法,就回到这份文档对照
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐