主题
02 基础语法与数据类型
一句话:Python 的变量是贴在对象上的名字,不是装值的盒子;数字、字符串、布尔和控制流都围绕「对象 + 引用」工作,理解这一点能避开后面一半的坑。
适用:CPython 3.11+。match 需要 3.10+,| 类型联合需要 3.10+(类型注解见 09)。
为什么需要
其他语言里 x = 1 常被理解成「在变量盒子里放入 1」。Python 里 x 只是一个名字,1 是堆上的对象,赋值把名字绑定到对象。这个差异会直接影响:
- 两个名字可能指向同一个可变对象,改一个另一个也变(03 详述);
- 函数传参传的是对象引用,不是拷贝(04 详述);
None、0、""、[]都是假值,用or写默认值时会吞掉合法的0和空值。
如果不知道这些,代码能跑,但会在数据为空、计数为零、配置项显式设为 0 时出现难查的行为差异。
核心机制
名字指向对象
python
a = [1, 2]
b = a
b.append(3)
print(a) # [1, 2, 3]:a 和 b 是同一个列表
print(a is b) # True
x = 1
y = x
y = y + 1
print(x) # 1:整数不可变,y 重新绑定到新对象id(obj) 看对象标识,is 比较是否同一对象,== 比较值。判断 None 用 is None,不要用 == None。
数字:整除、浮点与类型转换
python
print(7 / 2) # 3.5,/ 永远返回 float
print(-7 // 2) # -4,向下取整,不是向零取整
print(-7 % 2) # 1,余数符号跟随除数
print(0.1 + 0.2) # 0.30000000000000004
print(int(3.99)) # 3,向零截断
print(int("101", 2)) # 5int 是任意精度;float 是 IEEE-754 双精度。金额和精确计数不要用 float,用 decimal.Decimal 或整数分。浮点比较用 math.isclose(a, b) 或 abs(a - b) < 1e-9。
字符串:不可变序列
python
s = "hello"
print(s[1:4]) # ell,左闭右开
print(s[::-1]) # olleh
# s[0] = "H" # TypeError:字符串不可变
s2 = s.upper() # 返回新字符串
print(s, s2) # hello HELLO
print("a,b".split(",")) # ['a', 'b']
print(",".join(["a", "b"])) # a,bf-string(3.6+)是拼接和格式化的首选:f"{value:.2f}"、f"{count:>8}"、f"{ratio:.1%}"。原始字符串 r"\n" 保留反斜杠;多行用三引号。
布尔与真值:or 写默认值会吞 0
python
print(bool(0), bool(""), bool([]), bool(None)) # False False False False
print(bool("0"), bool([0])) # True True
config = {"lr": 0.0}
wrong = config.get("lr") or 0.01 # 0.01:合法的 0.0 被当成缺失
right = config.get("lr", 0.01) # 0.0:只有键不存在才用默认值
print(wrong, right)规则:
- 只有「假值等价于缺失」时才用
x or default,例如空字符串表示未填写名字。 - 数值、计数、布尔配置用
d.get(key, default)或if key in d,不要用or。 - 函数参数默认值同理:
items or []会把调用方传入的空列表替换成新列表(04 详述)。
控制流:缩进即语法
python
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
else:
grade = "C"
print(grade) # B
for i in range(1, 6, 2):
print(i, end=" ") # 1 3 5
print()
for i, ch in enumerate("ab"):
print(i, ch) # 0 a / 1 b
for a, b in zip([1, 2], ["x", "y"]):
print(a, b)range(start, stop, step) 与切片一样左闭右开。for...else 的 else 只在循环未被 break 时执行。
最小上手
保存为 basics.py 后 python basics.py,预期输出见注释:
python
from decimal import Decimal
name, tokens = "demo", 12345
print(f"{name}: {tokens:,} tokens") # demo: 12,345 tokens
config = {"lr": 0.0, "batch": 32}
lr = config.get("lr", 0.01)
assert lr == 0.0, "0.0 是合法值,不能被 or 吞掉"
nums = [1, 2, 3, 4, 5, 6]
evens = [x for x in nums if x % 2 == 0]
print(evens) # [2, 4, 6]
total = sum(x * x for x in range(10))
print(total) # 285
price = Decimal("0.1") + Decimal("0.2")
print(price) # 0.3生产动作
- 编码规范:4 空格缩进,不混 Tab;变量/函数
snake_case,类CamelCase,常量UPPER_SNAKE;用ruff format和ruff check固化。 - 边界转换:外部输入先
int()/float()并捕获ValueError,不要假设格式;空值和0要分别判断。 - 浮点:比较用
math.isclose;金额用Decimal或整数分;不要把0.1 + 0.2 == 0.3写进测试。 - 排障三段:
- 现象:
IndentationError→ 命令:python -m tabnanny file.py、编辑器显示空白字符 → 判断:Tab/空格混用或缩进层级错。 - 现象:条件分支没按预期走 → 命令:
print(repr(value), bool(value))→ 判断:值是0、""、[]还是None。 - 现象:
ValueError: invalid literal for int()→ 命令:打印原始值与repr→ 判断:空串、带空格、千分位或非十进制输入。
- 现象:
边界
- 本文只讲语法与数据模型,容器与函数见 03/04;动态类型不阻止错误,注解只是静态检查器的元数据(见 09),运行时不会自动校验。
讲清楚
Python 的赋值是把名字绑定到对象,不是复制值;可变对象因此会被多个名字共享,不可变对象则表现为「换标签」。数字上要记住 / 返回浮点、// 向下取整、浮点不精确;字符串不可变,切片左闭右开,格式化优先 f-string。最常见的隐蔽错误是把 or 当默认值:0、""、[] 都是假值,会被替换掉,正确写法是 dict.get(key, default) 或显式判 None。控制流本身没有惊喜,缩进就是语法,for 走迭代器协议。
适用 CPython 3.11+ | 初稿 2026-08,2026-10 订正 falsy 默认值