这一节把后面要用的语法一次过完:五种基本类型、四种容器、字符串与切片、函数、if、for、 模块导入。 不需要背,需要的是看到一段深度学习代码时,认得出每一行在干什么。 Demo 把这些写法一次跑完: list 追加后长度 6、set 去重剩 3 个、切片 [1:4:2] 取出 13、函数一次返回三个值。
这是第 2 章的最后一节,也是全书唯一一节讲语法的地方。 后面所有 Demo 都只用到这里出现过的写法——没有装饰器、没有类、 没有生成器表达式(除了列表推导那一种)。 如果已经会 Python,这一节可以只扫一眼代码块里的注释。
一、变量与基本类型
Python 的变量不用声明类型,赋什么就是什么。五种最常用:int、float、str、bool、None。
三种除法要分清:i // 2 是整除(得 3),i % 2 是取余(得 1),i / 2 是真除(得 3.5,
结果永远是 float)。
做索引、切片、循环次数时用整除;算比例、算损失、算准确率时用真除。
写错了不会报错,只会悄悄把 0.5 变成 0——这种 bug 最难找。
二、四种容器
| 容器 | 写法 | 能不能改 | 什么时候用 |
|---|---|---|---|
| list | [3, 1, 4] | 能 | 有序、会变长,最常用 |
| tuple | (3, 1, 4) | 不能 | 固定的几个值一起返回 |
| set | {3, 1, 4} | 能,但无序 | 去重、判断在不在 |
| dict | {"学习率": 0.1} | 能 | 按键取值,存参数 |
list 和 tuple 的差别只有一个:能不能改。 函数返回多个值时 Python 用的是 tuple;
你给它赋值给三个变量,就自动拆开了,这就是 lo, hi, av = stat(xs) 那一行。
set 最实用的是去重:{3, 1, 4, 1} 直接变成三个元素。
dict 最实用的是存超参数:{"学习率": 0.1, "轮数": 3000},后面所有训练脚本的配置都长这样。
三、字符串与切片
字符串可以用 + 连接、用 * 重复。
split 切开,join 合起来——注意 join 是用分隔符去 join 列表,不是列表自己 join。
格式化有三代写法:% 老式、.format() 中间代、f"..." 现在最常用。
本书的 Demo 用 %,因为要控制小数位数时它最直接:"%.4f" % x。
切片是 [start:stop:step],含头不含尾。 "0123456"[1:4:2] 从下标 1 开始、到 4 之前、
每 2 个取一个,得 "13"。[::-1] 是反转,这是处理序列时最常用的两个技巧。
四、函数与流程控制
def 定义函数,return 返回。没有 return 就返回 None。
返回多个值其实是返回一个 tuple,接收时拆开即可。
if / elif / else 按顺序判断,命中一个就跳出。
for ... in ... 遍历,enumerate 同时拿下标和值,range(start, stop, step) 生成等差数列。
注意 range(0, 10, 3) 是 [0, 3, 6, 9]——同样含头不含尾,和切片一个规矩。
写循环时数不对,多半是把尾算进去了。
五、模块导入
import math 之后用 math.sqrt;from math import sqrt 之后直接 sqrt。
两种都行,项目里统一一种,别混着写。
import numpy as np 这种起别名是惯例,全书都这么写。
别名不是语法要求,是为了少打字、也让别人一眼看出这是 numpy。
导入发生在文件被加载的时候。
如果某个包没装,import 那一行就会抛错,整个脚本一行都跑不了——
这也是为什么环境问题总在第一个 import 处爆出来。
六、动手 Demo:一次跑完这一节要用的全部写法
七小段,一段一件事:类型、三种除法、四种容器、字符串与切片、函数返回多值、if 判断、 for 加 enumerate、模块导入。每段的输出都打在下面,对照着看就知道每个写法到底产出什么。
i, f, s, ok, nothing = 7, 3.5, "深度", True, None
print(type(i).__name__, type(f).__name__, type(s).__name__)
print(i // 2, i % 2, i / 2) # 整除、取余、真除
L = [3, 1, 4, 1, 5]; L.append(9) # 可变
T = (3, 1, 4) # 不可变
S = {3, 1, 4, 1} # 自动去重
D = {"学习率": 0.1, "轮数": 3000} # 键值
print("深" + "度", "ab" * 3)
print("a,b,c".split(","), "-".join(["a", "b"]))
print("0123456"[1:4:2], "abcdef"[::-1])
def stat(xs):
return min(xs), max(xs), sum(xs) / len(xs)
lo, hi, av = stat([3, 1, 4, 1, 5])
for k, v in enumerate([3, 1, 4]):
pass
实跑输出:
--------------------------------------------------------------------
Python 的基本语法:一次跑完这一节要用的全部写法
--------------------------------------------------------------------
1) 五种基本类型:int / float / str / bool / NoneType
7 // 2 = 3,7 % 2 = 1,7 / 2 = 3.50
2) list [3, 1, 4, 1, 5, 9],长度 6;tuple (3, 1, 4);set 去重后 [1, 3, 4];dict 取轮数 3000
tuple 改不动:'tuple' object does not support item assignment
3) 字符串:连接 深度,重复 ababab
format:1 与 2,f-string:1 与 2
split:['a', 'b', 'c'],join:a-b
切片 [1:4:2] = 13,反向 [::-1] = fedcba
4) 函数返回三个值:min=1 max=5 mean=2.80
5) if 判断:学习率 0.100 属于「常见范围」
6) for 加 enumerate 累加:3×1 + 1×2 + 4×3 = 17
range(0, 10, 3) 生成 [0, 3, 6, 9]
7) 导入模块:math.sqrt(2) = 1.414214,math.log(math.e) = 1.000000
这一节的语法就这些,**够写完本书所有 Demo 了。**
真正需要多练的只有两件:切片和字典——后面处理数据和超参数天天用。
五种类型打出来是 int/float/str/bool/NoneType。注意 None 的类型叫 NoneType,
不是 None——报错信息里见到它是另一回事。
7 // 2 = 3、7 % 2 = 1、7 / 2 = 3.50。
三个数一起看最清楚:整除丢掉小数,取余留下余数,真除给你小数。
list 追加 9 之后长度 6;
tuple 一改就抛 TypeError,报错原文是 'tuple' object does not support item assignment;
set 里塞了 4 和 1 两次,去重后只剩三个元素。
切片那两个结果值得记:"0123456"[1:4:2] 得 13(取了下标 1 和 3),
"abcdef"[::-1] 得 fedcba(整个反转)。这两个写法在处理序列时天天用。
函数那一段:stat 返回三个值,一行拆给三个变量。
最后一次跑下来 min=1、max=5、mean=2.80——注意 2.80 是浮点,%.2f 把它截到两位。
语法就这些。
后面第 4 章手推反向传播、第 5 章滑窗做卷积,用的全是这里出现过的写法,没有更复杂的东西。
30 秒实验
- 把
L.append(9)改成L + [9],看 L 变了没有——这能说明可变与不可变的区别。 - 用 dict 存三个超参数,再写一个 for 循环把它们的名字和值打印出来。
- 把
"0123456"[1:4:2]改成[::2]和[-3:],分别猜一下结果再跑。
常见误区
- 用
=复制 list。B = A只是起了个别名,改 B 会连着 A 一起变。 真要复制得写B = A[:]或list(A)。 - 把整除和真除混用。
accuracy = correct / total是对的,写成//就永远是 0 或 1。 这种错不报异常,只是数不对。 - 以为 range 含尾。
range(1, 5)是 1、2、3、4,不含 5。 循环少跑一轮、多跑一轮,基本都是这里。
自测三问(点开对答案)
1. list、tuple、set、dict 最本质的区别是什么? —— 能不能改、有没有序、怎么取值。list 有序可改,tuple 有序不可改,set 无序去重,dict 按键取值。 2. `"0123456"[1:4:2]` 为什么得 "13"? —— 从下标 1 开始(字符 1),到下标 4 之前(不含 4),步长 2,所以取了下标 1 和 3 两个字符, 拼起来是 13。 3. 函数返回多个值时,实际返回的是什么? —— 一个 tuple。 写成 `a, b, c = f()` 时 Python 自动把它拆开,这叫序列解包, 和 `x, y = y, x` 交换变量是同一个机制。第 2 章到此结束:解释器装好、包装好、语法认全。 下一章开始真正接触深度学习——书里用 TensorFlow 和 Keras 跑第一个图像辨识,而这台机器上没有它们, 所以那一章会一边讲书上的代码,一边用 numpy 把同样的事做一遍。
- ☐ (本章完,下一节 3.1 TensorFlow 与 Keras 的安装)