← 返回模块
3.1.1.1beta 可读 · 未来免费校验通过内容版本 2026-05-26

语法、数据类型与控制流

3.1.1 · Python 语言基础 · 编程

早上 7:42,做市台。研究员在群里丢了一句:「把跳空分类脚本重跑一下,阈值改成 5%。」打开她的笔记本,屏幕上是十几行 Python——没有 import、没有类,只有一段 if/elif/else 在判断 stdin 读进来的收益率。新人立刻问了一句:「Python 凭什么知道 if 到哪一行结束?」这门课就从这里讲起。学完之后你能默写出同样的脚本:stdin 到 float 的转换、链式比较(chained comparison)、以及 is== 的差异——这条差异上季度还咬过组里某位交易员一次。

空白即语法

Python 没有大括号、也没有语句结尾分号。代码块就是连续若干行使用相同缩进;带冒号的头行(iffordefwhile)打开块,缩进退回外层时块结束。每级缩进用 4 个空格——不要 tab、不要 2 空格、不要混用。# 起一行注释,直到行末;Python 没有多行注释语法。

跑代码有两种姿势。REPL(python 命令进入)一次评估一个表达式,最适合用来确认「7 // 2 到底等于几」。脚本模式(python run.py)从头到尾跑完整个文件,只打印你显式 print 的内容。养成不确定时立刻打开 REPL 的肌肉记忆——比凭直觉猜要快。

标量类型

五个内置标量类型够你写一个单文件脚本。int 是任意精度(arbitrary precision),2 ** 1000 也是合法 int,不会溢出。float 是 IEEE-754 双精度;0.1 + 0.2 实际等于 0.30000000000000004,结算金额比较别用 ==boolint 的子类型,只有 True/FalseTrue + True 等于 2——偶尔有用,偶尔是 bug。str 是不可变(immutable)的 Unicode 字符串,字面量 '510300'"510300"、或三引号跨行。None 是单例哨兵。

四个算术运算符的区分值得背下来,以行内代码示例呈现:7 / 2 evaluates to 3.5(真除法,恒返回 float),7 // 2 evaluates to 3(地板除,两侧都是 int 时返回 int),7 % 2 evaluates to 1(取模,余数),2 ** 10 evaluates to 1024(乘方)。

/// 的拆分是从 C/Java 过来的人最容易踩坑的点。布尔运算符拼写成 andornot,不是 &&||。它们具有短路特性(short-circuit):a and ba 为假时不会再求值 b。Python 视为「假」的值有 FalseNone00.0"",以及空容器(下一课覆盖);其余都为真。

比较运算符可以链式书写。0 < x < 10 等价于 (0 < x) and (x < 10),但 x 只求值一次。本课课后练习用得上这个写法。

名称指向对象

赋值在 Python 里不是「把值塞进盒子」。x = 450 创建一个值为 450int 对象,并把名字 x 绑定到它。y = xy 也指向同一个对象。id(x) 返回对象的唯一编号;x is y 判断两个名字是否指向同一对象,而 x == y 判断两个对象的值是否相等。小整数和短字符串在 CPython 里会被缓存(intern),因此 a = 5; b = 5; a is b 通常返回 True——别依赖这一点。日常代码里值得写 is 的几乎只有 x is None,其它一律用 ==

增强赋值(augmented assignment)x += 1s += "!" 多数时候只是写法上的便利:对于不可变类型,它会把 x 重新绑定到一个新对象。对于可变类型则可能原地修改。这里先把 x += 1 读作「给 x 加一」就够了。

控制流

条件分支是 if / elif / elseelif 等价于其它语言的 else iffor 循环遍历任意可迭代对象,现在先理解为「能逐项取出的序列」;用 range(n)0 数到 n-1range(a, b)ab-1while 在条件为真时持续循环。break 跳出最内层循环,continue 跳到下一轮。Python 还支持循环上的 else: 子句——只在循环未被 break 中断时执行;老代码里偶尔出现,自己写时不必使用。

下面是一段完整脚本,把上面的要点串起来:从 stdin 读一批 300ETF 日收益率,用 for 循环依次判断每一个是否跨过涨跌停 ±10% 附近的关注阈值(涨跌停精确规则在 Track 1,这里用 5% 作为一个偏弱的关注线):

# classify a batch of 300ETF daily returns
returns = [float(s) for s in input("returns, comma-separated: ").split(",")]

for r in returns:
    if r < -0.05:
        label = "down-shock"
    elif r < -0.01:
        label = "down"
    elif r <= 0.01:
        label = "flat"
    elif r <= 0.05:
        label = "up"
    else:
        label = "up-shock"
    print(f"300ETF return {r:.4f} -> {label}")

列表推导式把每个 stdin token 转成 float(不转就会在和 -0.05 比较时直接抛 TypeError);for 循环按顺序走过整批;if/elif 链按阈值由小到大排列,后一支条件天然假设前面的判断已经失败;f-string f"{r:.4f}" 把浮点格式化成四位小数。喂它 0.005,0.06,第二个值会落到 up-shock 分支——这是上线前你愿意做的一次手工验证。

练习

Exercise

写一段脚本,从 input() 读入一个数 x,若 x < 0 打印 "negative",若 x == 0 打印 "zero",若 0 < x < 10 打印 "small",否则打印 "large"。整段用一条 if/elif/else 链,且只调用一次 input()。

提示
先把 stdin 的字符串转成数字:x = float(input(...))。然后写四条按顺序排布的分支——「small」那一支可以直接依赖「前面没命中意味着 x > 0」这件事。
提示
链式比较 0 < x < 10x > 0 and x < 10 更短、也更接近数学写法。四个输出字符串要严格匹配:"negative""zero""small""large",包括引号和小写。

衔接下一课

到此你已经能读输入、做分支、跑循环、打印结果——足够写一个有用的单文件脚本。但你还没法把这段逻辑封装起来供别处复用。下一课介绍 def:把一段代码命名、在多处调用,并理清楚作用域规则(同名 r 在函数体内会指向哪一个绑定)。深一层的延伸阅读可看廖雪峰 Python 教程的函数节,以及《流畅的 Python》第 2 版第 1 章。