第二章 Python 语言基础
第一章我们把环境搭起来了,写了个能跑的猜数字游戏。但有件事我没敢在那时候告诉你,第二章让我们来亲身感受下。
打开命令行试一下这行。
>>> 0.1 + 0.2 0.30000000000000004别急着怀疑电脑,也别怀疑 Python,这个结果有它自己的道理,本章会把它讲清楚。
上一章我们写的是"能跑就行"的代码,这一章要学怎么写"对的"代码。变量怎么存东西、数据分哪几类、运算符有哪些、输入输出怎么做得体面。学完你能写出带计算、带格式化输出、能跟人交互的小工具。
我会按照下面内容讲解。
第二章 Python 语言基础 │ ├── 1. 语法特点 → 缩进、换行、注释、大小写、动态类型 ├── 2. 保留字与标识符 → 35 个不能碰的词 + 命名规矩 ├── 3. 变量 → 它是标签不是盒子,以及三种赋值写法 ├── 4. 基本数据类型 → 数字 / 字符串 / 布尔 / None + 互相转换 ├── 5. 运算符 → 算术、比较、逻辑、优先级 ├── 6. 基本输入输出 → print 的隐藏参数、input 的返回类型 ├── 7. 实战 → 名片 / BMI / 小票 / 秒数换算 └── 8. 小结 → 一张表收口 + 5 道题 + 下一章预告老规矩,别只阅读。把代码敲进你的常用IDE,跑一遍,改点参数再跑一遍。
一、Python 语法特点
1.1 用缩进来分块,不用花括号
这是 Python 最显眼的特征。别的语言用{}包住代码块,Python 用缩进。
// C 语言,靠花括号 if (score >= 60) { printf("及格"); printf("可以回家了"); } printf("结束");# Python,靠缩进 if score >= 60: print("及格") print("可以回家了") print("结束")每条内容给你讲解下。
if score >= 60: ← 行尾的冒号,等于说"下面要开新块了" print("及格") ← 缩进 4 空格,属于 if 的地盘 print("可以回家了") ← 同样缩进,还是 if 的地盘 print("结束") ← 退回行首,已经出了 if,无论如何都会执行四条规矩记牢。
- 同一个代码块里,每一行的缩进量必须一模一样。
- 推荐 4 个空格,别用 Tab。混用会报
IndentationError(第一章 Q6 讲过怎么解决)。 - 冒号
:是"下面要开新块"的信号灯,看到if/for/def后面跟着冒号,下一行就得缩进。 - 缩进结束,代码块就结束。没有
end,也没有}。
我刚开始写 Python 的时候,最不习惯的就是这个。写了两周之后反倒回不去了,看别的语言那一堆花括号会觉得多余。
1.2 一行一句,分号可有可无
Python 里换行就代表这句话说完了,不用加分号。
a = 1 b = 2非要写在一行也行,用分号隔开。
a = 1; b = 2 # 语法没问题,但没人这么写一句话太长想换行,用反斜杠或者直接套括号。
total = 1 + 2 + 3 + \ 4 + 5 + 6 result = (1 + 2 + 3 + 4 + 5 + 6)我个人偏好括号那一种,反斜杠后面不小心多打个空格就报错,太脆了。
1.3 注释
单行注释用#。
# 这是单行注释 price = 19.9 # 行尾也可以写注释多行说明用三个引号包起来。严格说它是个字符串字面量,但放在文件开头或者函数下面,Python 会把它当成文档字符串(docstring)。
""" 价格计算模块 汇率按 7.2 算,用之前记得确认下最新汇率 """注释这事我只有一条建议,写为什么,别写做什么。
# ❌ 废话注释,代码本身已经说了在干嘛 price = price * 0.8 # 价格乘以 0.8 # ✅ 有价值,说清了 0.8 是怎么来的 price = price * 0.8 # 会员八折,运营给的口径1.4 大小写敏感
Name、name、NAME在 Python 眼里是三个完全不同的东西。写错大小写是最常见的低级错误之一,报错信息通常是NameError: name 'xxx' is not defined。
1.5 动态类型,万物皆对象
Python 的变量没有固定类型,同一个变量可以随时装不同的东西。
x = 10 # x 现在是整数 x = "hello" # 现在变成了字符串,完全合法 x = [1, 2, 3] # 又变成了列表想知道一个东西是什么类型,问type()。
>>> type(10) <class 'int'> >>> type(3.14) <class 'float'> >>> type("abc") <class 'str'>对比一下静态语言。Java 里写int x = 10;之后,x这辈子只能是整数,塞个字符串进去编译器直接报错。Python 没有这层约束,写起来快,代价是类型错误要等到运行时才暴露。
二、保留字与标识符
2.1 35 个不能碰的保留字
保留字(关键字)是 Python 自己留着用的词,你不能拿它们当变量名。想知道有哪些,直接问解释器。
import keyword print(keyword.kwlist) print(len(keyword.kwlist)) # 35按用途分个组,看着就不乱了。
| 分组 | 保留字 |
|---|---|
| 逻辑与空值 | TrueFalseNoneandornotisin |
| 控制流 | ifelifelseforwhilebreakcontinuepass |
| 定义与返回 | defclasslambdareturnyield |
| 异常处理 | tryexceptfinallyraiseassert |
| 作用域与删除 | globalnonlocaldel |
| 导入与上下文 | importfromaswith |
| 异步协程 | asyncawait |
几个容易踩的点。
TrueFalseNone首字母必须大写。写成true或none会报NameError,这是从其他语言转过来的人最常犯的错。matchcasetype_属于软关键字,Python 3.10 引入match语句时加的。它们只在特定位置有特殊含义,别的地方还能当变量名用,但我不建议这么干,容易把读代码的人绕晕。- 别拿内置函数名当变量。
liststrdictidtypesummax这些不是保留字,你确实能把它们覆盖掉,然后整段代码就开始莫名其妙地报错。
# 我年轻时候干过的蠢事 list = [1, 2, 3] print(list) # 还行,[1, 2, 3] x = list("abc") # TypeError,list 已经被你改成列表了,不再是那个函数2.2 标识符命名规则
标识符就是你给变量、函数、类起的名字。规则很简单。
| 名字 | 合法吗 | 原因 |
|---|---|---|
name | ✅ | 字母组成 |
user_name | ✅ | 字母加下划线 |
_count | ✅ | 下划线开头 |
age2 | ✅ | 数字不在开头就行 |
姓名 | ✅ | Python 3 支持 Unicode 标识符 |
2age | ❌ | 数字开头 |
user-name | ❌ | 中划线会被当成减号 |
user name | ❌ | 不能有空格 |
class | ❌ | 保留字 |
$price | ❌ | 特殊字符只允许下划线 |
中文变量名语法上合法,我见过有人这么用。两年之后他自己回来看代码也看不懂,别学。
2.3 命名约定
规则是强制的,约定是自发的。按 PEP 8(Python 官方代码风格指南)来就行。
| 场景 | 约定 | 例子 |
|---|---|---|
| 变量、函数 | 小写 + 下划线 | user_nameget_price() |
| 常量 | 全大写 + 下划线 | MAX_RETRYPI |
| 类名 | 大驼峰 | StudentInfo |
| 内部使用 | 单下划线开头 | _helper() |
| 魔术方法 | 双下划线包起来 | __init____str__ |
名字长短这事我有点体会,宁可长一点也别缩写到看不懂。usr_nm这种省三个字符的写法,半年后你得靠猜。
2.4 三个自检小技巧
import keyword keyword.iskeyword("class") # True,是保留字 keyword.iskeyword("name") # False,可以放心用 "user_name".isidentifier() # True,是合法标识符 "2age".isidentifier() # False起名字拿不准的时候,这两个函数比翻文档快。
三、变量
3.1 变量是标签,不是盒子
很多入门书把变量画成一个装东西的盒子,这个比喻在 Python 里会带你走偏。更准确的形容是这样。
a = 10 ┌────────┐ ┌───────────────┐ │ a │─────────▶│ 整数对象 10 │ └────────┘ └───────────────┘ 变量名 数据躺在内存里 b = a ┌────────┐ ┌───────────────┐ │ a │─────────▶│ 整数对象 10 │ ├────────┤ ▲ └───────────────┘ │ b │─────┘ └────────┘ 两个标签,贴的是同一个对象变量就是一张贴在对象上的标签。赋值这个动作,是把标签贴到某个对象上。
理解这一点,下面这段代码的结果你就能预测了。
a = 10 b = a a = 20 # a 撕下来贴到 20 上,b 还贴在 10 上 print(b) # 10,没跟着变换成列表就不一样了。
a = [1, 2, 3] b = a a.append(4) # 改的是对象本身,不是换标签 print(b) # [1, 2, 3, 4],b 也跟着变了区别在于整数是不可变对象,改不了只能换一个;列表是可变对象,能在原地改内容。这个话题第四章讲列表时还会展开。
3.2 三种赋值写法
# 1. 单个赋值 name = "张三" # 2. 多元赋值,一次给多个变量,等号两边数量必须一致 x, y, z = 1, 2.5, "abc" # 3. 交换两个变量,Python 里不用临时变量 a, b = 1, 2 a, b = b, a # 交换完成,a 是 2,b 是 1 # 4. 链式赋值 pi = rate = 0.0交换变量那一行我第一次见到的时候愣了一下,别的语言都得请出第三个变量当搬运工。多元赋值在后面拆包的时候还会用到,很好使。
3.3 id() 和 is
id()返回对象在内存里的身份证号,is比的就是这个号,而==比的是值。
x = [1, 2, 3] y = [1, 2, 3] print(x == y) # True,值一样 print(x is y) # False,两个各自独立的对象日常判断相等,用==就够了。只有一种情况必须用is,判断是不是None。
result = None if result is None: # ✅ 正确写法 print("还没算出来") if result == None: # ❌ 别这么写 print("还没算出来")顺带提一句,CPython 把 -5 到 256 之间的整数做了缓存复用,所以这个范围内用is比较会得到一些反直觉的结果。别去依赖它,那是实现细节,不是语言规则。
3.4 del 与常量
del删掉的是标签,不是对象。
a = 10 del a print(a) # NameError,标签没了Python 里没有真正的常量。PI = 3.14159只是大家约定全大写代表别改,你硬要改它也不拦着。靠自觉。
四、基本数据类型
4.1 类型家族树
Python 内置类型 │ ├── 数字 Number │ ├── int 整数,精度无限 │ ├── float 浮点,双精度 │ ├── bool 布尔,int 的子类 │ └── complex 复数,用得少 │ ├── 序列 Sequence │ ├── str 字符串(不可变) │ ├── list 列表(可变) ← 第四章细讲 │ └── tuple 元组(不可变) ← 第四章细讲 │ ├── 映射 dict 字典 ← 第四章细讲 ├── 集合 set 集合 ← 第四章细讲 │ └── NoneType 只有一个值 None本章只讲intfloatboolstrNone这五个,剩下的第四章之后逐个来。
4.2 数字
age = 18 # int price = 19.9 # float big = 2 ** 1000 # int,Python 的整数没有上限2 ** 1000这行在别的语言里会直接溢出,Python 算出来是一个 302 位的数,一点不慌。
>>> 2 ** 1000 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376浮点数是双精度,精度大约 15 到 16 位有效数字,末尾那点误差是二进制表示的锅。
布尔值在 Python 里是整数的子类,True就是 1,False就是 0。
>>> True + True 2 >>> isinstance(True, int) True它真正解释的是另一件事,为什么if 1和if True效果一样。
4.3 字符串
四种写法,各有各的用处。
s1 = '单引号' s2 = "双引号" s3 = """三引号, 可以跨行写""" s4 = r"C:\new\test" # 原始字符串,反斜杠不当转义符写 Windows 路径时r"..."能救命,不然\n会被当成换行。
转义字符就那么几个常用的。
| 转义 | 含义 |
|---|---|
\n | 换行 |
\t | 制表符 |
\\ | 一个反斜杠 |
\'\" | 引号本身 |
字符串可以按下标取字符,下标从 0 开始,负数表示从右往左数。
P y t h o n 0 1 2 3 4 5 -6 -5 -4 -3 -2 -1s = "Python" print(s[0]) # P print(s[-1]) # n print(s[1:4]) # yth,左闭右开,取到下标 4 之前 print(s[:3]) # Pyt print(s[3:]) # hon print(s[::-1]) # nohtyP,倒着来切片是s[起始:结束:步长],左闭右开。[::-1]反转字符串这个技巧值得背下来。
常用方法挑几个高频的。
| 方法 | 作用 | 例子 |
|---|---|---|
len(s) | 长度 | len("abc")→ 3 |
s.upper() | 转大写 | "abc".upper()→ ABC |
s.lower() | 转小写 | 反过来 |
s.strip() | 去掉首尾空白 | 处理用户输入必备 |
s.split(",") | 按分隔符切开 | "a,b".split(",")→['a', 'b'] |
"," .join(...) | 拼接 | 第五章用 |
s.replace(a, b) | 替换 | "a-b".replace("-", "") |
s.find("x") | 找位置,找不到返回 -1 | |
"x" in s | 判断子串,返回布尔 | "th" in "Python"→ True |
字符串是不可变的,改单个字符会报错。
s = "Python" s[0] = "p" # TypeError: 'str' object does not support item assignment想要新字符串就重新赋值,s = "python"。
4.4 类型转换
int("18") # 18,字符串转整数 int(3.99) # 3,直接截断,不是四舍五入 float("3.14") # 3.14 str(100) # "100" bool("") # False bool("0") # True,非空字符串一律为真几个坑。
| 表达式 | 结果 | 说明 |
|---|---|---|
int("3.14") | 报错 | 得先转 float 再转 int,int(float("3.14")) |
int("abc") | 报错 | 内容不是数字 |
int(3.99) | 3 | 向零截断,不是四舍五入 |
bool("0") | True | 字符串 "0" 不是假值 |
str(None) | "None" |
处理用户输入时int()最容易炸,因为用户什么都可能输。第一章那个温度转换器输入 abc 就崩,对吧。
4.5 格式化三种写法
第一种,%占位符,老派写法,现在新代码里基本不写了,但你读老代码会遇到。
print("姓名:%s,年龄:%d" % ("张三", 18))第二种,str.format(),Python 2.6 之后的主流。
print("姓名:{},年龄:{}".format("张三", 18))第三种,f-string,Python 3.6 之后的首选,我强烈推荐这个。
name = "张三" age = 18 print(f"姓名:{name},年龄:{age}")f-string 里能直接写表达式,还能带格式说明符。
price = 3.14159 print(f"{price:.2f}") # 3.14,保留两位小数 print(f"{price:>10.2f}") # 右对齐占 10 位 print(f"{42:03d}") # 042,不足补零 print(f"{1234567:,}") # 1,234,567,千分位 print(f"{0.256:.1%}") # 25.6%,百分比4.6 布尔与真值测试
下面这些东西在if里一律是假,其余都是真。
| 假值 | 说明 |
|---|---|
FalseNone | 布尔假与空值 |
00.00j | 各种零 |
"" | 空字符串 |
[](){}set() | 空容器 |
判断真假不用刻意转 bool,直接放进if就行。
name = input("请输入姓名:") if name: # 空字符串就是假,不用写 name != "" print(f"你好,{name}")五、运算符
5.1 算术运算符
| 运算符 | 含义 | 例子 | 结果 |
|---|---|---|---|
+ | 加 | 7 + 2 | 9 |
- | 减 | 7 - 2 | 5 |
* | 乘 | 7 * 2 | 14 |
/ | 除 | 7 / 2 | 3.5 |
// | 整除 | 7 // 2 | 3 |
% | 取余 | 7 % 2 | 1 |
** | 幂 | 2 ** 10 | 1024 |
三个暗坑,逐个说。
第一,/永远返回浮点数,哪怕能整除。
>>> 10 / 5 2.0 # 注意那个 .0,类型是 float >>> 10 / 3 3.3333333333333335第二,//是向下取整,不是四舍五入,负数方向要特别小心。
>>> 7 // 2 3 >>> -7 // 2 -4 # 不是 -3,它往更小的方向取整第三,%的结果符号跟着除数走,这一点跟 C、Java 不一样。
>>> 7 % 3 1 >>> -7 % 3 2 # 除数 3 是正数,结果就是正的 >>> 7 % -3 -2 # 除数是负数,结果跟着变负5.2 比较运算符
==!=><>=<=,结果是布尔值。Python 有个别语言没有的糖,链式比较。
age = 25 if 18 <= age < 60: # 等价于 18 <= age and age < 60 print("在职年龄段")5.3 逻辑运算符
andornot,三个都会短路求值,能省一步就省一步。
name = "" result = name or "匿名用户" # name 为空,取后者 print(result) # 匿名用户这里有个必须知道的细节,and和or返回的不是布尔值,是操作数本身。
>>> 3 or 5 3 # 3 是真的,直接返回它,不看后面 >>> 0 or 5 5 # 0 是假的,返回后面那个 >>> 3 and 5 5 # 前面为真,结果取决于后面,返回 5 >>> 0 and 5 0 # 前面为假,直接返回它记法是,or找第一个为真的,and找第一个为假的,都找不到就返回最后那个。
5.4 赋值运算符
count = 0 count += 1 # 等价于 count = count + 1 count *= 2 count -= 3+=-=*=/=//=%=**=全套都有。Python 里没有++和--,写i++不会报错(被当成两个正号),但也不会加一,这个坑我见过好几个人踩。
Python 3.8 加了个海象运算符:=,能在表达式里顺手赋值。
# 不用海象 n = input("输入点什么:") while n != "q": print(n) n = input("输入点什么:") # 用海象 while (n := input("输入点什么:")) != "q": print(n)5.5 身份与成员运算符
a is b # 比身份证号(同一个对象) a is not b "th" in "Python" # 成员判断,字符串里就是子串判断is和==的区别前面讲过了,再强调一次,比值用==,比 None 用is。
5.6 位运算符
了解即可。我写这么多年业务代码,用上位运算的场合一只手数得过来,基本就是权限位和状态标记这两类。
| 运算符 | 含义 |
|---|---|
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
~ | 按位取反 |
<<>> | 左移右移 |
>>> 6 & 3 # 110 & 011 = 010 2 >>> 1 << 3 # 左移三位,等于乘 8 85.7 优先级金字塔
** 最高 ~ +x -x (正负号) * / // % + - << >> & ^ | == != < > <= >= (比较) is is not in not in not and or = += -= *= ... 最低记不住就加括号。我本人就是这么干的,写了这么多年,遇到三四个运算符叠在一起的时候照样加括号,不丢人。括号还能让读代码的人一眼看懂你的意图。
5.8 浮点数精度问题
回到开头那个问题。
>>> 0.1 + 0.2 0.30000000000000004这是二进制浮点的通病,换 Java、C 也一样,跟 Python 没关系。0.1 在二进制里是个无限循环小数,就像十进制里的 1/3 一样,存的时候只能截断,误差就这么攒下来了。
两个应对办法。
# 1. 只要显示好看,用 round 或格式化 print(round(0.1 + 0.2, 2)) # 0.3 print(f"{0.1 + 0.2:.2f}") # 0.30 # 2. 算钱这种要精确的场合,用 decimal from decimal import Decimal print(Decimal("0.1") + Decimal("0.2")) # 0.3算钱一定用Decimal,别用 float,这是行业共识。
六、基本输入和输出
6.1 print 的三个隐藏参数
大部分人只用到了print()的第一个参数,其实它还有三个能玩的。
print("苹果", "香蕉", "橙子") # 默认空格分隔 print("苹果", "香蕉", "橙子", sep=" | ") # 换成竖线分隔 print("加载中", end="") # 结尾不换行 print("完成")第三个参数end默认是换行符\n,改成空字符串就不换行了。用它刷个进度条。
import time for i in range(101): print(f"\r当前进度 {i}%", end="") time.sleep(0.02) print("\n搞定")第四个参数file能把内容直接写进文件。
with open("log.txt", "w", encoding="utf-8") as f: print("程序启动", file=f)6.2 input 永远返回字符串
这一点第一章提过,这里再钉一次,因为它是新手 bug 的头号来源。
┌─── 终端 ────────────────────────────┐ │ 请输入年龄:18 │ │ │ │ 你拿到的是字符串 "18" │ │ int() 之后才是数字 18 │ │ "18" + "1" = "181" ← 拼接 │ │ int("18") + 1 = 19 ← 加法 │ └─────────────────────────────────────┘age = input("请输入年龄:") # 用户输入 18 print(age + 1) # TypeError,字符串不能跟整数相加 print(int(age) + 1) # 196.3 格式化输出实战
想要输出看起来像那么回事,掌握这四个就够用了。
| 写法 | 效果 | 输出 |
|---|---|---|
f"{3.14159:.2f}" | 保留两位小数 | 3.14 |
f"{42:03d}" | 补零到三位 | 042 |
f"{1234567:,}" | 千分位 | 1,234,567 |
f"{0.256:.1%}" | 百分比 | 25.6% |
f"{'abc':>10}" | 右对齐占 10 位 | 前面补 7 个空格 |
f"{'abc':^10}" | 居中 | 两边各补空格 |
对齐在做表格和小票的时候特别有用,下面的实战三会用到。
七、实战
建个D:\code\python-learn\chapter02\目录,本章代码都放这儿。
实战一|个人信息名片
练的是变量、多行字符串和 f-string。
# card.py name = "张三" job = "后端工程师" city = "杭州" years = 3 skills = "Python / MySQL / Docker" card = f""" ╔══════════════════════════════════╗ ║ 个人名片 ║ ╠══════════════════════════════════╣ ║ 姓名:{name} ║ ║ 职业:{job} ║ ║ 城市:{city} ║ ║ 年限:{years} 年 ║ ║ 技能:{skills} ║ ╚══════════════════════════════════╝ """ print(card) print(f"{name} 在 {city} 做了 {years} 年 {job}")运行结果。
╔══════════════════════════════════╗ ║ 个人名片 ║ ╠══════════════════════════════════╣ ║ 姓名:张三 ║ ║ 职业:后端工程师 ║ ║ 城市:杭州 ║ ║ 年限:3 年 ║ ║ 技能:Python / MySQL / Docker ║ ╚══════════════════════════════════╝ 张三 在 杭州 做了 3 年 后端工程师右边框对不齐,对吧。中文字符在终端里占两个英文字符的宽度,靠数空格对齐是治不好的,得按显示宽度算。这也是为什么做小票那种对齐输出时,我更愿意用下面的等宽思路。
实战二|BMI 计算器
练的是输入、类型转换、算术运算符和分支判断。
# bmi.py name = input("请输入姓名:") weight = float(input("请输入体重(kg):")) height = float(input("请输入身高(m):")) bmi = weight / (height ** 2) print(f"\n{name} 的 BMI 指数是 {bmi:.1f}") if bmi < 18.5: level = "偏瘦" elif bmi < 24: level = "正常" elif bmi < 28: level = "超重" else: level = "肥胖" print(f"身体状态:{level}")跑一遍。
请输入姓名:张三 请输入体重(kg):70 请输入身高(m):1.75 张三 的 BMI 指数是 22.9 身体状态:正常这里有两个细节。height ** 2比height * height更直观,指数运算就用**。输出用:.1f保留一位小数,不然 BMI 会甩出一长串小数。
实战三|购物小票
练的是运算符、f-string 对齐和格式化。这个例子我很喜欢,因为它输出的成果看着就像个正经东西。
# receipt.py shop_name = "街角便利店" item1, price1, count1 = "牛奶", 3.5, 2 item2, price2, count2 = "面包", 8.0, 1 item3, price3, count3 = "咖啡", 12.8, 3 amount = price1 * count1 + price2 * count2 + price3 * count3 discount = 0.9 # 会员九折 payable = amount * discount payable = round(payable, 2) # 算钱保留两位 line = "-" * 42 print(f" {shop_name}") print(line) print(f"{'商品':<8}{'单价':>8}{'数量':>8}{'小计':>12}") print(line) print(f"{item1:<8}{price1:>8.2f}{count1:>8}{price1 * count1:>12.2f}") print(f"{item2:<8}{price2:>8.2f}{count2:>8}{price2 * count2:>12.2f}") print(f"{item3:<8}{price3:>8.2f}{count3:>8}{price3 * count3:>12.2f}") print(line) print(f"{'合计':<8}{'':>8}{'':>8}{amount:>12.2f}") print(f"{'折扣':<8}{'':>8}{'':>8}{discount:>11.1%}") print(f"{'应付':<8}{'':>8}{'':>8}{payable:>12.2f}") print(line) print(" 谢谢惠顾,欢迎下次光临")输出长这样。
街角便利店 ------------------------------------------ 商品 单价 数量 小计 ------------------------------------------ 牛奶 3.50 2 7.00 面包 8.00 1 8.00 咖啡 12.80 3 38.40 ------------------------------------------ 合计 53.40 折扣 90.0% 应付 48.06 ------------------------------------------ 谢谢惠顾,欢迎下次光临几个值得学的点。
f"{'牛奶':<8}"里的<8是左对齐占 8 个字符宽,>8是右对齐。数字右对齐才符合看小票的习惯。price1, count1 = 3.5, 2这种多元赋值,把三个商品的参数一次性摆开,比一行行写清爽。- 算钱那一步
round(payable, 2)不能省,不然48.060000000000002这种结果会直接打印出来。 '折扣'那行用了:>11.1%,百分比格式自带一个%号,所以宽度比别的多留一位。
等等,{discount:>11.1%}里的 discount 是 0.9,输出是90.0%。如果你想要显示"打九折",写成f"{(1 - discount) * 100:.0f}% 优惠"更直白。
加练|秒数换算成时分秒
//和%的经典练习题,面试也爱考。
# seconds.py total = int(input("请输入总秒数:")) hours = total // 3600 minutes = total % 3600 // 60 seconds = total % 60 print(f"{total} 秒 = {hours} 小时 {minutes} 分 {seconds} 秒")跑一下。
请输入总秒数:3725 3725 秒 = 1 小时 2 分 5 秒拆解一下这三行。// 3600拿到能被整除的小时数,% 3600拿到扣掉小时后剩下的秒数再// 60就是分钟,最后% 60剩下的是秒。想让输出更好看点,可以补零,f"{hours:02d}:{minutes:02d}:{seconds:02d}"。
八、小结
8.1 本章知识小结
| 模块 | 你现在应该能做对的事 | 自测 |
|---|---|---|
| 语法特点 | 说清缩进规则和注释写法 | □ 能解释为什么 Python 不用花括号 |
| 保留字 | 知道 35 个保留字,会查 | □ 能用keyword.iskeyword()判断 |
| 标识符 | 起合规且规范的名字 | □ 能说出 snake_case 用在哪 |
| 变量 | 理解标签语义,会三种赋值 | □ 能解释a, b = b, a为什么能交换 |
| 数据类型 | 分得清 int / float / str / bool / None | □ 知道bool("0")是 True |
| 类型转换 | 会 int() float() str() 互转 | □ 知道int("3.14")会报错 |
| 运算符 | 会用算术比较逻辑,懂优先级 | □ 能说出-7 // 2等于几 |
| 输入输出 | 会用 print 参数和 f-string 格式化 | □ 能输出对齐的小票 |
8.2 五句话记住本章
- 缩进就是语法,冒号开块,4 空格,别混 Tab。
- 变量是标签,赋值是贴标签,
is比地址,==比值。 /永远得浮点,//向下取整,%符号跟除数。- input 拿到的一定是字符串,要计算就得转类型。
- 算钱用 Decimal,别用 float。
8.3 课后练习
- 温度转换器升级,输入摄氏度,同时输出华氏度和开尔文(K = ℃ + 273.15),都保留一位小数。
- 计算圆的周长和面积,输入半径
r,π 取 3.14159,两个结果都保留两位小数。 - 输入一个三位数,用
//和%把它拆成百位、十位、个位三个数字分别打印。 - 写个"个人信息录入",输入姓名、年龄、身高,用 f-string 拼成一句话输出,年龄那栏右对齐占 5 位。
- 挑战题,输入一个总天数,换算成「x 年 x 个月 x 天」(一年按 365 天算,一个月按 30 天算),想想余数的处理顺序。
8.4 下一章
第三章讲流程控制,if分支的各种写法、for和while循环、break和continue,还有range()这个循环好搭档。这一章写的 BMI 和小票,到时候都能用循环重写一遍,代码能短一半。
附录|运算符与内置函数速查卡
| 类别 | 运算符 / 函数 |
|---|---|
| 算术 | +-*///%** |
| 比较 | ==!=><>=<= |
| 逻辑 | andornot |
| 赋值 | =+=-=*=/=//=%=**=:= |
| 身份 | isis not |
| 成员 | innot in |
| 类型转换 | int()float()str()bool() |
| 常用内置 | type()id()len()print()input()round()abs()max()min() |
记不住就回来查,这张表我当年贴在显示器边上贴了半年。