3. Python基础知识:注释、变量以及数据类型、标识符和关键字、输入函数、输出函数、运算符、程序类型转换
好,咱们正式开始Python基础部分。说实话,很多搞CUDA的同学一开始觉得Python太“软”,不如C++硬核。但我在做GPU加速项目时,Python往往是那个“粘合剂”——数据预处理、模型搭建、结果可视化,全得靠它。所以,别小看这些基础,它们是后续并行计算的基石。
3.1 注释:给未来的自己留个便签
注释这东西,说白了就是代码里的“人话”。机器不看,但人要看。我见过最惨的案例是,自己写的代码三个月后看不懂了……嗯,从那以后我养成了写注释的习惯。
Python里注释有两种:
- 单行注释:用
#开头,整行都失效 - 多行注释:用三个单引号
'''或三个双引号"""包裹
# 这是单行注释,我习惯在关键逻辑前加一行
print("Hello, CUDA!") # 行尾也可以加注释
'''
这是多行注释
可以写好几行说明
比如解释这个函数为什么这么写
"""
当然双引号也行
'''
3.2 变量与数据类型:Python的“盒子”哲学
Python的变量,你可以想象成一个贴了标签的盒子。你不需要提前告诉盒子能装什么——它很智能,你放进去什么,它就是什么类型。
我刚开始从C++转Python时特别不习惯,总觉得变量得先声明类型才安心。后来发现,动态类型在快速原型开发时太爽了。
# 变量赋值,不需要声明类型
a = 10 # 整数
b = 3.14 # 浮点数
c = "CUDA" # 字符串
d = True # 布尔值
e = [1, 2, 3] # 列表
Python常见的数据类型:
| 类型 | 名称 | 示例 | 说明 |
|---|---|---|---|
int |
整数 | 42 |
任意大小,没有溢出问题 |
float |
浮点数 | 3.14159 |
双精度,GPU里常用float32 |
str |
字符串 | "Hello" |
不可变,支持索引和切片 |
bool |
布尔值 | True / False |
注意首字母大写 |
list |
列表 | [1, 2, 3] |
可变,可嵌套,类似数组 |
tuple |
元组 | (1, 2, 3) |
不可变,常用于函数返回多个值 |
dict |
字典 | {"key": "value"} |
键值对,查找极快 |
numpy.float32 显式指定。
3.3 标识符和关键字:起名字的艺术
标识符就是你给变量、函数、类起的名字。规则很简单:
- 只能包含字母、数字、下划线
- 不能以数字开头
- 不能是Python关键字
- 区分大小写(
myVar和myvar是两个东西)
Python的关键字大概有30多个,比如 if、for、while、def、class 等等。你想想看,如果你给变量起名叫 class,Python就懵了——你到底是想定义类还是引用变量?
# 合法的标识符
my_variable = 10
var2 = 20
_longName = 30
# 不合法的标识符
# 2var = 10 # 数字开头,报错
# my-var = 10 # 有连字符,报错
# if = 10 # 关键字,报错
gpu_memory;类用驼峰命名法(CamelCase),比如 GpuKernel。团队协作时,统一风格比风格本身更重要。
3.4 输入函数:让程序学会“听”
input() 函数是Python从控制台获取用户输入的方式。注意,它返回的永远是字符串!
name = input("请输入你的名字:")
print("你好," + name)
# 如果需要数字,必须手动转换
age = input("请输入年龄:")
age = int(age) # 字符串转整数
print("明年你", age + 1, "岁")
input() 接收了文件路径,结果用户输入了带空格的路径,程序直接崩溃。后来我加了 strip() 去空格,再用 os.path.exists() 检查。永远不要相信用户的输入!
3.5 输出函数:让程序学会“说”
print() 是Python最常用的输出函数。它有很多小技巧,我挑几个常用的:
# 基本用法
print("Hello, World!")
# 多个参数,自动用空格分隔
print("GPU", "CUDA", "Python") # 输出:GPU CUDA Python
# 指定分隔符
print("GPU", "CUDA", "Python", sep=" -> ") # 输出:GPU -> CUDA -> Python
# 指定结束符(默认是换行)
print("加载中", end="...")
print("完成") # 输出:加载中...完成
# 格式化输出(f-string,Python 3.6+)
name = "CUDA"
version = 12.0
print(f"当前版本:{name} {version}") # 输出:当前版本:CUDA 12.0
我个人最常用f-string,简洁又直观。在调试GPU程序时,我经常用 print(f"blockIdx: {blockIdx.x}, threadIdx: {threadIdx.x}") 来定位问题。
3.6 运算符:计算的“工具包”
运算符就是用来做各种操作的符号。Python的运算符很丰富,咱们挑重点说:
| 类别 | 运算符 | 示例 | 说明 |
|---|---|---|---|
| 算术 | + - * / // % ** |
10 // 3 = 3 |
// 是整除,** 是幂运算 |
| 比较 | == != < > <= >= |
5 == 5 为 True |
返回布尔值 |
| 赋值 | = += -= *= /= |
x += 1 等价于 x = x + 1 |
简化代码 |
| 逻辑 | and or not |
True and False 为 False |
注意不是 && 或 || |
| 成员 | in not in |
"CUDA" in ["CUDA", "OpenCL"] |
检查是否在序列中 |
| 身份 | is is not |
a is None |
检查是否是同一个对象 |
# 算术运算符
a = 10
b = 3
print(a + b) # 13
print(a / b) # 3.333...
print(a // b) # 3(整除)
print(a ** b) # 1000(10的3次方)
# 逻辑运算符
x = True
y = False
print(x and y) # False
print(x or y) # True
print(not x) # False
// 整除和 % 取余非常常用。比如计算线程索引时,threadIdx.x // blockDim.x 可以算出当前线程在网格中的位置。这个技巧我几乎每个项目都用。
3.7 程序类型转换:让数据“变形”
类型转换就是把一种数据类型变成另一种。Python提供了内置函数来做这件事:
# 常见类型转换
a = "123"
b = int(a) # 字符串 -> 整数,b = 123
c = float(a) # 字符串 -> 浮点数,c = 123.0
d = str(456) # 整数 -> 字符串,d = "456"
e = bool(1) # 整数 -> 布尔值,e = True
f = list("abc") # 字符串 -> 列表,f = ['a', 'b', 'c']
类型转换有两种:
- 隐式转换:Python自动帮你转。比如
3 + 0.5,整数3自动变成浮点数3.0 - 显式转换:你手动调用函数转。比如
int("42")
float() 转一下。还有一次,我把 None 转成了布尔值,结果 bool(None) 是 False,导致一个条件判断出了bug。记住:0、None、空字符串、空列表都会转成 False。
好了,Python基础部分就到这里。这些内容看起来简单,但它们是后续所有并行计算代码的“砖瓦”。下一章咱们会深入控制流——if判断和循环,这些在GPU线程调度中会频繁用到。到时候见!