跳到正文

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))  # 5

int 是任意精度;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,b

f-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 默认值

把一门技术讲透到既懂也会用