第 2 章 Python 语言基础与数据结构¶
本章主要内容如下:
- 2.1 Python基本语法
- 2.2 变量与数据类型
- 2.3 数值型
- 2.4 字符串
- 2.5 列表(List)
- 2.6 元组(Tuple)
- 2.7 字典(Dictionary)
- 2.8 集合(Set)
- 2.9 类型转换
2.1 Python 基本语法¶
2.1.1 代码语句¶
- 大部分情况下,一行即为一句完整的代码语句,可以实现一定的功能。程序会依次从上到下执行每一句代码,直到单元格结束。
【小练习】分别在一行中键入 3 + 2,和分三行键入 3 + 2,看看结果有何不同?
- 要求不按照顺序执行代码时,可以使用复合语句来实现。具体方法,将在后续使用时介绍。
2.1.2 注释语句¶
- 注释语句是在单元格中的普通文字,不会被执行,仅提供解释说明的作用。
- 单行注释以
#开头。 - 多行注释以首尾各加上三引号
'''或"""来表示。 - Ctrl + / 可以快速注释/取消注释选中行。
📓 拓展知识
多行注释常常被用来写文档字符串(docstring)。 这主要用于大段代码的文字解释,常常放在需要解释的代码块的开头几行。
这是单行注释
x = 10 此表示期数(period)
这里演示多行注释的写法。
多行注释常用来作为代码的详细说明。
y = 20 此表示每期现金流(cash flow)
计算并输出(这里做一个最简单的“相加”示例)
print(x + y)
# Print函数演示
# 输出一个或多个值
print("Hello, Python!") # 输出字符串
print("The answer is", 42) # 输出多个值,默认以空格分隔
input()函数用于让用户自行输入信息。
input(prompt)可向用户显示提示信息,其中的prompt表示任意提示文本。- 用户输入完成后按回车,输入的内容会作为被存储为文本。
# input() 函数演示
# 请显示提示语:"请输入您的名字:"。
print("Hello,", input() ) # 输出问候语和用户输入的名字
2.2 变量与数据类型¶
2.2.1 变量的作用¶
Python中,变量(variable)可以理解为对数据的命名,这样我们就可以非常方便快速地使用某个数据。
类比:购物车中的物品可以看作变量,物品的种类(如苹果、香蕉)可以看作变量的类型,物品的数量可以看作变量的值。我们不需要提前告诉购物车里会放什么类型的物品,只要把物品放进去,购物车就会自动识别它们的类型和数量。
2.2.2 变量的赋值与调用¶
变量赋值时被自动创建,赋值表达式:变量名 = 值。
注意: = 用于赋值,而不是比较是否相等。
2.2.3 变量命名规范
- 以字母或下划线开头,不能以数字开头。
- 只能包含字母、数字、下划线。
- 大小写敏感。
- 避免与 Python 关键字重名(例如
for,if,class等)。 - 命名应体现含义,例如
invoice_id,gross_profit,customer_balance。 - Python3可以用中文变量名,但不推荐使用,因为可能会导致编码问题和可读性下降。
- (推荐)蛇形命名方法(snake_case):变量名由小写字母和下划线组成,单词之间用下划线分隔,例如
customer_balance、gross_profit。- 这种命名方式在 Python 社区中非常流行,符合 PEP 8 的命名规范,能够提高代码的可读性和一致性。
# 变量演示: 错误命名
# 1. 使用关键字作为变量名会导致语法错误
for = 10 # 这行代码会报错,因为 for 是 Python 的关键字,不能用作变量名
# 2. 变量名不能以数字开头
1st_value = 100 # 这行代码会报错,因为变量名不能以数字开头
# 3. 变量名不能包含空格或特殊字符
my variable = 5 # 这行代码会报错,因为变量名不能包含空格
# 4. 变量名只能包含字母、数字和下划线
my-variable = 10 # 这行代码会报错,因为变量名不能包含连字符
# 5. 变量名区分大小写
Value = 50
value = 100
print(Value) # 输出 50
print(value) # 输出 100
# 6. 变量名应具有描述性,避免使用单个字母或无意义的名称
x = 10 # 这行代码虽然合法,但变量名 x 没有描述性,不清楚它代表什么
customer_balance = 1000.00 # 这行代码更好,因为变量名 customer_balance 清晰地描述了它的含义
账户余额 = 1000.00 # 虽然合法,但不推荐使用中文变量名,因为可能会导致编码问题和可读性下降
zhanghuyue = 1000.00 # 虽然合法,但不推荐使用拼音变量名,因为可能会降低代码的可读性,尤其是对于非中文母语的开发者来说
ZHYE = 1000.00 # 使用拼音缩写的变量名会进一步减少可读性,不推荐使用
2.2.4 变量类型
变量类型用以确定该变量可以取哪些值,以及可以进行哪些运算操作。 Python 不需要提前声明变量类型,会根据赋值自动确定其类型。 可以使用 `type(变量名)` 查看变量类型。| 类别 | 数据类型 | type() | 特点 | 举例 |
|---|---|---|---|---|
| 基础 | 数字(number) | int / float / complex | 整数、浮点数、复数 | x = 8;y = 88.8;z = 8+8j |
| 基础 | 字符串(string) | str | 字符序列 | s = 'hello' |
| 基础 | 布尔(boolean) | bool | True / False | flag = True |
| 进阶 | 列表(list) | list | 有序,可修改 | a = [1,2,3] |
| 进阶 | 元组(tuple) | tuple | 有序,不可修改 | b = (1,2,3) |
| 进阶 | 集合(set) | set | 无序,不重复 | c = {1,2,3} |
| 进阶 | 字典(dictionary) | dict | 键值对,键唯一 | d = {'name':'Tom','age':18} |
| 进阶 | None 类型 | NoneType | 空值/缺失值 | x = None |
None类型:None 是一个特殊的类型,表示“没有值”或“缺失值”。它常用于函数没有返回值时的默认返回值,或者表示变量尚未赋值。在这节不会单独展开
# 赋值运算演示
a = 3 # 将整数 3 赋值给变量 a
b = a # 将变量 a 的值(3)赋值给变量 b,此时 a 和 b 都是 3
total = a + b
print(a)
print(total)
a = 6 # 将整数 6 赋值给变量 a,此时 a 的值变为 6,但 b 的值仍然是 3,因为它们是独立的变量
print(a)
print(total)
a = b # 将变量 b 的值(3)赋值给变量 a,此时 a 的值变回 3
print(a)
print(total)
a = a + 1 # 将 a 的值增加 1,相当于 a = a + 1 (这里可以看出 = 是一个赋值运算符,而 + 是一个加法运算符)
a += 1 # 这是 a = a + 1 的简写形式,效果相同
print(a)
a = a - 1 # 将 a 的值减少 1,相当于 a = a - 1
a -= 1 # 这是 a = a - 1 的简写形式,效果相同
print(a)
# 变量演示: 变量类型
x1 = 3 #x1是一个变量,值为3
x2 = 10 #x2是一个变量,值为10
total = x1 +x2 # total是一个变量,值为x1和x2的和,即13
X1 = "3" # X1是一个变量,值为字符串 "3"
X2 = "10" # X2是一个变量,值为字符串 "10"
TOTAL = X1 + X2 # TOTAL是一个变量,值为字符串 "3" 和 "10" 的连接,即 "310"
print(total)
print("total") # 输出字符串 "total",而不是变量 total 的值
print(TOTAL)
# 变量格式示例:不同类型的变量
x = 8 # int:整数(例如数量、期数)
y = 88.8 # float:小数(例如金额、利率)
s = "hello" # str:字符串(例如备注、ID)
a = [1, 2, 3] # list:列表(例如一组金额)
b = (1, 2, 3) # tuple:元组(例如一条固定结构记录)
c = {1, 2, 3} # set:集合(例如去重后的ID集合)
d = {"name": "Tom", "age": 18} # dict:字典(例如“字段名 → 字段值”映射)
flag = True # bool:布尔值(条件判断)
empty = None # None:空值/缺失值(还没填、暂时没有)
# type(...) 查看变量当前存储的数据类型
print(type(x), type(y), type(s))
print(type(a), type(b), type(c), type(d))
print(type(flag), type(empty))
2.3 数值型变量¶
2.3.1 数值型变量类型¶
数字类型用于表示数量与数值。常见数字类型:
int:整型 (整数)float:浮点型 (小数)bool:布尔型 (True/False)- 有固定写法: 一个为True, 一个为False,首字母大写,不能写成true或TRUE
- 布尔型可以当作整型对待,其中 True 的值为 1,False 的值为 0。
complex:复数,包含实部和虚部,例如3 + 4j(了解即可,本课程不涉及复数的运算)- z = a + bj,其中 a 是实部,b 是虚部,j 是虚数单位
- 数学课本上虚数单位用i表示,但python中用j表示,可能是因为i在数学中常用来表示索引或计数器,而j则不太常见,所以被选来表示虚数单位。
# 数字类型:int / float / bool
# bool 在 Python 中也属于一种数值类型:True 相当于 1,False 相当于 0(了解即可)
a = 3 # int:整数
b = -10 # int:负数也是 int
c = 3.14 # float:小数
flag1 = True # bool:真
flag2 = False # bool:假
print(type(a), a)
print(type(b), b)
print(type(c), c)
# int(flag) 会把 True/False 转成 1/0(在计数、条件累计时偶尔会用到)
print(type(flag1), flag1, int(flag1))
print(type(flag2), flag2, int(flag2))
2.3.2 常用算术运算符¶
| 运算符 | 含义 | 示例 |
|---|---|---|
+ |
加 | 3 + 2 |
- |
减 | 3 - 2 |
* |
乘 | 3 * 2 |
/ |
除 | 3 / 2 |
// |
整除 | 7 // 3 |
% |
取余 | 7 % 3 |
** |
幂 | 2 ** 3 |
Note
/的结果通常是float;//是整除(向下取整)。- 负数时的取整和取余:
-7 // 3结果为-3,-7 % 3结果为2。- 复杂表达式建议加括号,避免优先级带来的误读。
#算术运算符示例
print(3 + 2) # 加法
print(3 - 2) # 减法
print(3 * 2) # 乘法
print(3 / 2) # 除法(float)
print(3 / 3) # 除法(float) 使用算术运算符 /, 商一定是浮点数
print(3 // 3) # 整除(floor division) 使用算术运算符 //, 商向下取整
print(7 // 3) # 整除(floor division)
print(-7 // 3) # 负数的整除,结果是向下取整的整数部分
print(7.0 // 3) # 整除(floor division) 即使是浮点数,结果也是向下取整的整数部分,但结果是一个浮点数
print(7 % 3) # 取余(remainder)
print(-7 % 3) # 负数的取余,结果是一个非负数,满足 (a // b) * b + (a % b) == a 的关系
print(2 ** 3) # 幂(power)
# 运算符优先级演示
print(3**2+5/2) # 先计算幂,再计算除法,最后计算加法
print( (3**2+5)/2 ) # 先计算括号内的幂和加法,再计算除法
print(abs(-12.5)) # 绝对值
print(round(12.3456, 2)) # 四舍五入到 2 位小数(用于金额显示)
print(pow(2, 10), 2**10) # 幂运算,两种写法等价
print(divmod(17, 5)) # 返回 (17 // 5, 17 % 5)
练习¶
- 将月份映射为季度:
month = 1~12 → quarter = 1~4- 若输入
month = 1/2/3,输出quarter = 1;输入month = 4/5/6,输出quarter = 2;以此类推
- 若输入
- 计算复利终值:
FV = principal * (1 + r) ** t
双击阅读参考答案
2.4 字符串(String)¶
字符串(str)是字符序列,常用于表示文本、编码、标识符等。
字符串的常见定义方法:
- 单引号:
'hello' - 双引号:
"hello"(与单引号等价,常用于字符串里包含单引号) - 三引号:
'''...'''或"""..."""(多行字符串,或包含引号时更方便)- 多行注释和多行字符串如何区分?
- 多行注释通常不赋值给变量,直接写在代码中;多行字符串通常会赋值给变量,或者作为函数的 docstring。
- 多行注释和多行字符串如何区分?
# 字符串举例:
# 不能像列表那样直接修改某个位置的字符
# s = INV1001 # 这行代码会报错,因为 INV1001 没有定义为字符串,应该加上引号
s = 'INV1001'
s = "INV1001"
s = '''INV1001''' # 这也是一个字符串,包含了换行符
'''INV1001代表关于存货的一个记录ID,
通常用于标识某个特定的存货项目。''' # 这是一个多行注释,用来解释 INV1001 的含义
2.4.1 字符串的编码(移至第 5 章)¶
# --- 0:准备一个字符串 ---
s = "Life is short, you need Python."
print("original =", s)
# 1. 拼接 (+)
s1 = "Life is short"
s2 = "You need Python"
print(s1 + ", " + s2)
# 2. 重复 (*)
print("-" * 20)
print(s * 3)
print((s+'\n') * 3)
# 3. 成员运算 (in / not in)
print("Li" in s1)
print("Py" not in s1)
2.4.3 索引与切片¶
| 运算符 | 描述 | 实例 |
|---|---|---|
[] |
通过索引获取字符 | 'Hello'[0] -> 'H' |
[:] |
截取字符串中的一部分 (切片) | 'Hello'[1:4] -> 'ell' |
索引¶
字符串中的每个字符都有一个对应的索引(index),表示它在字符串中的位置。
- 索引从0开始
- 负数索引表示从末尾开始计数
切片¶
切片(slice)是指从字符串中提取出一个子字符串的操作。
切片基本形式:s[start:end:step]
start:起始位置(包含)end:结束位置(不包含)step:步长(可省略)- 左闭右开原则:切片结果包含
start索引对应的字符,但不包含end索引对应的字符。勘误:在之前的版本写作“左开右闭”,是不合适的。 但后面的表述“切片结果包含
start索引对应的字符,但不包含end索引对应的字符”是正确的。
字符串长度¶
可以使用 len() 函数获取字符串的长度(字符数)。
# --- 1:基本信息:长度 / 索引 / 切片 ---
print("len(s) =", len(s))
print("s[0] =", s[0]) # 第 1 个字符(可能是空格)
print("s[-1] =", s[-1]) # 最后 1 个字符
print("s[-5:] =", s[-5:]) # 最后 5 个字符
print("s[:10] =", s[:10]) # 前 10 个字符
print("s[2:12]=", s[2:12]) # 索引 2 到 11(左闭右开)
print("s[::-1] =", s[::-1]) # 反转字符串(step = -1)
2.4.5 其他常用字符串操作¶
| 类别 | 常用方法 | 说明 |
|---|---|---|
| 去空格 | strip, lstrip, rstrip |
删除首尾空白 |
| 大小写 | lower, upper, title |
统一文本格式 |
| 查找/计数 | find, count, in, not in |
查找位置 / 计数 |
| 判断 | startswith, endswith |
条件判断 |
| 替换 | replace |
替换子串 |
| 拆分与合并 | split,join |
拆分和合并字符串 |
# --- 2:清洗与大小写:strip / lower / upper / title ---
s_withblank = " Life is short, you need Python. "
print("raw string =", s_withblank)
t = s_withblank.strip() # 去掉首尾空白
print("strip() =", t)
print("lstrip() =", s_withblank.lstrip()) # 去掉左侧空白
print("rstrip() =", s_withblank.rstrip()) # 去掉右侧空白
print("lower() =", t.lower())
print("upper() =", t.upper())
print("title() =", t.title())
# --- 3:查找与判断:find / count / startswith / endswith / in ---
print("find('Python') =", t.find("Python")) # 找不到返回 -1
print("index('Python') =", t.index("Python")) # 找不到会抛出 ValueError 错误
print("count('o') =", t.count("o")) # 统计出现次数
print("startswith('Life') =", t.startswith("Life"))
print("endswith('.') =", t.endswith("."))
print("'need' in t ? =", "need" in t)
# 若find找不到时,会返回 -1
print("find('Python') =", t.find("Java"))
# 而index找不到时,会抛出 ValueError 错误
print("index('Python') =", t.index("Java"))
# 故而在实际使用中,如果不确定子串是否存在,建议使用 find() 方法来避免程序崩溃;
# 如果需要确保子串一定存在,可以使用 index() 方法,这样如果子串不存在时会立即抛出错误,方便调试和错误处理。
# --- 4:替换:replace ---
t2 = t.replace("Python", "SQL") # replace 会生成新字符串
print("t =", t)
print("t2 =", t2)
# --- 5:拆分与合并:split / join ---
words = t.split() # 按空白拆分(自动处理多个空格)
print("split() =", words)
joined = " | ".join(words) # 用分隔符把列表合成字符串
print("join(...) =", joined)
Note: 字符串是不可变对象(immutable),不能对单个字符进行原地修改。所谓“修改字符串”,本质上都是创建一个新字符串。
# 字符串(str)是不可变对象(immutable)
#t[0] = "X" # ❌ 会报错:TypeError,因为字符串不支持原地修改
new_t = "X" + t[1:] # ✅ 正确做法:用切片 + 拼接“生成新字符串”
print(new_t)
练习:字符串切片¶
将字符串"uforbgood"赋值到s1变量中
分别访问s1中的第0个、第3个、第5到8个元素,并将它们组合在一起,并且打印出来.(第0个元素和第3个元素之间要有空格相间,第3个元素和第5-8个元素要有空格相间)
双击阅读参考答案
双击阅读参考答案
2.4.6 字符串格式化输出(f-string)¶
f"{...}": 花括号 {} 里不仅可以引用变量,还可以直接写表达式(例如计算、拼接、函数调用等)。
- 引用变量:
f"{name}" - 使用表达式:
f"{a+b}"
# 例子 1:引用变量
name = "Jack"
course = "Python"
print(f"Hello, {name}! Welcome to {course}.")
# 例子 2:在 {} 里写表达式(expression),不仅限于变量名
a = 12
b = 5
# :.2f 表示“保留两位小数”
print(f"a+b = {a+b}, a*b = {a*b}, a/b = {a/b}")
a = int(input('Please enter your birth year (e.g., 2001):')) # int(...) 把输入的字符串转换成整数
b = 2026 - a
#print(...) #请在...中使用格式化输出使得屏幕上打印: Your age is XX. XX为年龄。
双击阅读参考答案
2.4.7 转义字符与原始字符串¶
在字符串字面量(string literal)里,反斜杠 \ 用来写“转义序列”(escape sequence):它不是普通字符,而是用来表示一些特殊字符。
\n:换行(newline)\t:制表符(tab)\\:一个反斜杠本身(因为单个\被用作转义开头)\"/\':在字符串里输出引号(当你需要把引号当作普通字符时)
原始字符串(raw string):r"..."
- 含义:把反斜杠
\当作普通字符保留,不再把它当作转义开头 - 典型用途:Windows 路径、正则表达式(regex)
Note
- 在代码里如果写
"C:\temp\new\2026.txt"这种“单反斜杠路径”,其中\t、\n可能会被当作转义序列(制表符/换行),打印出来就会“看起来乱码”。- 更稳妥的写法:
r"C:\temp\new\2026.txt"或"C:\\temp\\new\\2026.txt",也可以用正斜杠"C:/temp/new/2026.txt"。- raw string 不能以单个反斜杠结尾,例如
r"C:\temp\"会报错(最后的\会把引号“吃掉”)。
# 转义字符(escape sequence):\n 换行、\t 制表符
text = "Line1\nLine2"
print(text) # \n换行
tabbed = "col1\tcol2"
print(tabbed) # \t制表符
# 路径\t / \n 可能被当作转义,导致显示异常
bad_path = "C:\temp\new\2026.txt"
print("bad_path:", bad_path)
# 更稳妥的写法 1:raw string(原始字符串)—— 反斜杠按字面意思保留
good_path_raw = r"C:\temp\new\2026.txt"
# 更稳妥的写法 2:双反斜杠 —— 把每个 \ 写成 \\
good_path_escaped = "C:\\temp\\new\\2026.txt"
# 更稳妥的写法 3:正斜杠 —— 在很多场景也可以正常工作
good_path_slash = "C:/temp/new/2026.txt"
print("good_path_raw :", good_path_raw)
print("good_path_escaped:", good_path_escaped)
print("good_path_slash :", good_path_slash)
#1
#print('...') # 在...中尝试输出路径 C:\Users\Jack
#2
#print('...') # 在...中尝试输出如下内容 "\n" is a line break.
双击阅读参考答案
2.5 列表(List)¶
2.5.1 列表(List)的定义与性质¶
列表(List)是 Python 中最常用的有序容器。它通过方括号 [ ] 定义,并使用逗号分隔内部元素。
核心特性¶
- 有序(Ordered): 元素按照插入顺序排列,可以通过索引(Index)精确访问。
- 可变(Mutable): 支持在原地对元素进行修改、新增(插入/追加)或删除。
- 异构性(Heterogeneous): 列表可以同时包含不同数据类型的元素(如整数、字符串、布尔值等)。
- 可嵌套性(Nested): 列表的元素可以是另一个列表,从而构建多维数据结构。
Note
由于列表是可变对象(Mutable),它非常适合处理动态变化的数据流。例如:记录一组实时波动的金额、存储待处理的发票编号序列等。
# 列表举例
list1 = [1, 2, 3, 4, 5] # 包含整数的列表
list2 = ['a', 'b', 'c', 'd', 'e'] # 包含字符串的列表
list3 = [1, 'a', 2.5, True] # 包含不同类型元素的列表
x = x = ['abc', 1, 0.1, True, [1, 2, 3, 'a', 'b'], (1, 2, 3, 'a', 'b'), {'two':2, 'three':3}, {1, 2, 3}] # 包含各种类型元素的列表
print(list1)
print(list2)
print(list3)
2.5.2 索引与切片¶
- 类似字符串索引,我们可以用同样的方法索引列表中元素。
- 如果列表中的某个元素也是列表,我们可以通过二次索引来进一步索引、切片。比如,先从嵌套列表中提取索引为4的元素,这个元素还是一个列表。然后进一步再提取子列表中索引为1的元素。
x = ['abc', 1, 0.1, True, [1, 2, 3, 'a', 'b'], (1, 2, 3, 'a', 'b'), {'two':2, 'three':3}, {1, 2, 3}]
print(x)
print(x[0], x[-1]) # 第一个、最后一个
print(x[1:4]) # 切片:取第 2~4 个元素(不含右端)
print(x[::-1]) # 反转(step = -1)
print(x[4][1]) # 列表中的列表:取第 5 个元素(列表),再取其中的第 2 个元素(字符串 'b')
元素修改:索引赋值与切片赋值¶
列表是可修改对象(mutable),因此可以通过“索引/切片赋值”直接改动列表内容:
- 索引赋值:
lst[i] = x(修改某一个位置) - 切片赋值:
lst[a:b] = [...](一次修改一段;长度可能变化) - 删除指定位置:
del lst[i](按位置删,不返回被删元素) - 删除一段:
del lst[a:b]或lst[a:b] = []
Note
- 修改元素前,索引必须有效;常用
len(lst)或0 <= i < len(lst)先判断。- 与字符串不同:字符串是不可变对象(immutable),不能用
s[0] = "X"直接改字符。
# 元素修改演示:索引赋值 / 切片赋值 / del(每一步都 print)
items = ["INV1001", "INV1002", "INV1003", "INV1004"]
print("start:", items)
# 1) 索引赋值:修改某一个位置的元素
items[0] = "INV1001-UPDATED" # 修改第 1 个元素
print("after items[0] update:", items)
items[-1] = "INV1004-UPDATED" # 负索引:修改最后一个元素
print("after items[-1] update:", items)
# 2) 切片赋值:一次替换一段(长度可能变化)
items[1:3] = ["INV2001", "INV2002", "INV2003"]
print("after items[1:3] replace:", items)
# 3) del:按索引删除(不返回被删元素)
del items[0]
print("after del items[0]:", items)
2.5.3 常用列表操作¶
1. 增 (Adding)¶
| 操作 | 方法/写法 | 说明 |
|---|---|---|
| 追加 | append(x) |
在末尾追加一个元素 |
| 扩展 | extend(iter) |
追加多个元素(逐个加入) |
| 插入 | insert(i, x) |
在位置 i 插入元素(后面整体右移) |
2. 删 (Deleting)¶
| 操作 | 方法/写法 | 说明 |
|---|---|---|
| 删除末尾 | pop() |
删除并返回最后一个元素 |
| 删除指定位置 | pop(i) |
删除并返回索引 i 的元素 |
| 按值删除 | remove(x) |
删除第一个匹配元素(找不到会报错) |
| 清空 | clear() |
删除所有元素,列表变为空 |
3. 改 (Reordering / Sorting)¶
| 操作 | 方法/写法 | 说明 |
|---|---|---|
| 排序 | sort() / sorted(lst) |
原地排序 / 返回新列表(不改原列表) |
| 反转 | reverse() / reversed(lst) |
原地反转 / 返回迭代器(常配合 list(...)) |
4. 查 (Accessing / Searching)¶
| 操作 | 方法/写法 | 说明 |
|---|---|---|
| 查询位置 | index(x) |
返回 x 第一次出现的索引(找不到会报错) |
| 计数 | count(x) |
统计 x 出现次数 |
| 切片 | lst[a:b:step] |
取子列表(返回新列表),可用于“批量取/跳着取” |
5. 其他 (Others / Operations)¶
| 操作 | 方法/写法 | 说明 |
|---|---|---|
| 复制 | copy() |
浅拷贝(复制一层) |
| 拼接 | lst1 + lst2 |
生成新列表(不改原列表) |
| 重复 | lst * n |
列表内容重复 n 次(生成新列表) |
| 成员判断 | x in lst / x not in lst |
判断是否包含某元素 |
| 长度 | len(lst) |
列表元素个数 |
| 最值/求和 | min(lst) / max(lst) / sum(lst) |
常见汇总(列表里应是数字) |
# --- 0:准备数据 + 一个小工具函数(统一打印) ---
def show(tag, lst):
"""统一打印格式:tag + 当前列表 + 长度"""
print(f"{tag:<20} -> {lst} ") # {tag:<20} 表示 tag 左对齐,占 20 个字符宽度
# --- 1:添加类操作 append / extend / insert ---
items = ["INV1001", "INV1002"]
print("start items:", items)
show("before append", items)
items.append("INV1003") # 末尾追加 1 个元素
show("after append", items)
items.extend(["INV1004", "INV1005"]) # 末尾追加多个元素(逐个加入)
show("after extend", items)
items.extend("INV1006") # 尝试用extend追加一个元素,但是extend将字符串作为一个可迭代对象,逐个字符追加到列表中
show("after extend with a string", items)
items.insert(1, "INV9999") # 在索引 1 插入
show("after insert(1)", items)
# --- 2:删除类操作 pop / pop(i) / remove / clear / del ---
items = ["INV1001","INV9999", "INV1002", "INV1003", "INV1004","INV1005"]
show("start for delete", items)
# pop():删除末尾,并返回被删元素
last = items.pop()
show("after pop()", items)
print("popped last:", last)
# pop(i):删除索引 i,并返回被删元素
mid = items.pop(1)
show("after pop(1)", items)
print("popped index 1:", mid)
# remove(x):按值删除(删除第一个匹配项)
items.remove("INV1002")
show("after remove INV1002", items)
# del:按索引删除(不会返回被删元素)
# 注意:del 只能按位置删,不能像 remove 那样“按值删”
del items[0]
show("after del items[0]", items)
# 下面这行如果执行,会报错(因为列表里没有这个值)
# items.remove("INV_NOT_EXIST") # ValueError: list.remove(x): x not in list
# --- 3:查询类操作 len / in / index / count ---
items = ["INV1001", "INV1001", "INV1003", "INV1002"]
show("reset items", items)
print("len(items) =", len(items)) # 列表长度
print("'INV1003' in items ?", "INV1003" in items) # 判断某个元素是否在列表中,返回 True 或 False
print("'INV9999' in items ?", "INV9999" in items) # 判断某个元素是否在列表中,返回 True 或 False
print("items.count('INV1001') =", items.count("INV1001")) # 出现次数
print("items.index('INV1002') =", items.index("INV1002")) # 首次出现位置
#items.index("INV_NOT_EXIST") # index 找不到会报错
# --- 4:排序 sort / sorted(对比“是否修改原列表”) ---
items = ["INV1003", "INV1001", "INV1002"]
show("reset items", items)
# 1) 原地排序:sort() 会改变 items 本身,返回 None
ret = items.sort()
show("after items.sort()", items)
print("sort() return:", ret)
# 2) sorted(...) 返回新列表,不改变原列表
items = ["INV1003", "INV1001", "INV1002"]
show("reset items", items)
new_items = sorted(items)
show("original items", items)
show("sorted(items)", new_items)
# 3) 降序
desc_items = sorted(items, reverse=True)
show("sorted desc", desc_items)
# 4) reverse():原地反转(不排序)
items.reverse()
show("after items.reverse()", items)
# --- 小练习:现金账户流水分析 ---
# 场景:模拟“库存现金”账户的一组流水记录(单位:元)。
# 正数代表增加(收款),负数代表减少(支出/付款)。
cash_journal = [1000, -200, 500, -200, 3000, -150, 1000]
print("现金日记账流水:", cash_journal)
# -----------------------------------------------------------
# 任务 1:审计检查
# 请检查账目中是否包含一笔 -5000 的大额支出?(打印结果应该为 False)
# [在此处编写代码]
# -----------------------------------------------------------
# 任务 2:统计频次
# 统计金额为 1000 的收款在流水中出现了几次?
# [在此处编写代码]
# -----------------------------------------------------------
# 任务 3:整理账目
# 将所有流水按“从大到小”(金额高低)进行排序,可以快速看到最大的流入和流出。
# 请打印排序后的列表。
# [在此处编写代码]
请双击阅读参考答案
# --- 演示 1:原地修改 vs 返回新列表 ---
print("=== 1. 原地修改 append vs 返回新列表 sorted ===")
items = ["INV1002", "INV1001"]
print("Start:", items, "id =", id(items))
items.append("INV1003")
print("After append:", items, "id =", id(items), "(原列表被修改)")
sorted_items = sorted(items)
print("sorted_items:", sorted_items, "id =", id(sorted_items), "(新列表)")
print("items after sorted:", items, "id =", id(items), "(原列表保持 append 后的状态)")
2. 核心概念:可变 vs 不可变¶
在 Python 中,理解数据的“类型特性”是理解赋值与拷贝的基础。
- 不可变对象(Immutable): 内容一旦创建不可修改。
- 类型: 整数(
int)、浮点数(float)、字符串(str)、元组(tuple)。 - 行为: 对变量重新赋值时,会创建一个新对象,并将变量名指向新对象(内存地址改变)。
- 类型: 整数(
- 可变对象(Mutable): 内容可以在原地被修改。
- 类型: 列表(
list)、字典(dict)、集合(set)。 - 行为: 修改对象内部元素时,对象的内存地址不变。
- 类型: 列表(
3. 赋值(Assignment)的本质¶
Python 的赋值运算符 = 不是复制对象,而是建立引用(Binding)。
- 对于不可变对象: 赋值始终是引用;但由于不可变对象无法原地修改,对一个变量重新赋值会创建新对象并重新绑定变量名,因此看起来互不影响。
- 对于可变对象:
b = a只是给同一个对象起了个别名(Alias)。修改这个对象时,a和b都会看到变化。
# --- 演示 2:不可变类型 vs 可变类型的赋值差异 ---
print("\n=== 2. 不可变类型(如 int/str) ===")
a = 100
b = a # b 引用同一个整数对象
print(f"Start: a={a}, b={b}")
print(f"id(a)={id(a)}, id(b)={id(b)}") # 地址相同
# 重新赋值 a:整数不能原地改,a 会绑定到另一个整数对象
a = 200
print(f"After 'a=200': a={a}, b={b}") # b 不受影响,仍指向原来的 100
print(f"id(a)={id(a)}, id(b)={id(b)}") # a 绑定到新对象
print("\n=== 3. 可变类型(如 list) ===")
list_a = [1, 2, 3]
list_b = list_a # list_b 引用同一个列表对象(Alias)
print(f"Start: list_a={list_a}, list_b={list_b}")
print(f"id(list_a)={id(list_a)}, id(list_b)={id(list_b)}") # 地址相同
# 修改 list_a 指向的列表内容(原地修改):地址不变
list_a.append(4)
print(f"After append: list_a={list_a}, list_b={list_b}") # list_b 也会变
print(f"id(list_a)={id(list_a)}, id(list_b)={id(list_b)}") # 地址没变
4. 拷贝(Copy)¶
如果想让两个列表完全独立,需要进行拷贝。
Note
list_2 = list_1:引用同一个对象(Alias)。list_1.copy()或list[:]:浅拷贝(Shallow Copy),只复制第一层,也就是外层列表本身。copy.deepcopy(list_1):深拷贝(Deep Copy),递归复制所有层级(需要import copy)。浅拷贝里的“第一层 / 第二层”可以这样看:
a -> 外层列表 A -> [子列表 X, 子列表 Y] c -> 外层列表 C -> [子列表 X, 子列表 Y] ↑ ↑ 内层对象仍共享
a[0] = 123:替换的是a外层列表的第 0 格,浅拷贝c的外层列表不变,所以c[0]不受影响。a[1][1] = 888:修改的是共享的嵌套列表内部元素,所以a和浅拷贝c都会看到变化。
# --- 演示 3:浅拷贝的“第一层 / 第二层” ---
# 第一层:外层列表 a 的元素位置(a[0], a[1], ...)
# 第二层:嵌套列表内部的元素(a[1][1] 这种“第二个子列表里的第二个元素”)
import copy
a = [["INV1001", 100], ["INV1002", 200]] # 原始列表:元素是“嵌套列表”
b = a # alias:不是复制,只是同一个列表的另一个名字
c = a.copy() # 浅拷贝:只复制第一层(外层列表),第二层仍共享
d = copy.deepcopy(a) # 深拷贝:第一层和第二层都复制(了解)
print("图示:浅拷贝会新建外层列表,但内层列表仍共享")
print("a -> 外层列表 A -> [子列表 X, 子列表 Y]")
print("c -> 外层列表 C -> [子列表 X, 子列表 Y]")
print(" ↑ ↑ 内层对象共享")
print("\nstart(初始状态)")
print("a:", a)
print("b:", b)
print("c:", c)
print("d:", d)
print("\nPart A:替换外层元素 a[0] = 123")
a[0] = 123
print("a:", a)
print("b:", b) # b 是 alias,所以会跟着变
print("c:", c) # c 的外层列表独立,所以 c[0] 不变
print("d:", d) # d 完全独立,不变
print("\nPart B:修改嵌套元素 a[1][1] = 888")
a[1][1] = 888
print("a:", a)
print("b:", b) # alias:会变
print("c:", c) # 浅拷贝:第二层共享,所以也会变
print("d:", d) # 深拷贝:第二层独立,不变
2.5.6 列表推导式列表推导式用于“快速生成新列表”,语法是:¶
[表达式 for 变量 in 可迭代对象]
也可以加入条件过滤:
[表达式 for 变量 in 可迭代对象 if 条件]
Note
- 列表推导式会生成一个“新列表”,不修改原列表。
- 当逻辑很简单时,用列表推导式更清晰;逻辑复杂时,用普通
for循环更易读。
--->
练习:列表的特性及操作练习¶
- 建立一个列表命名为assets,存储如下字符串:Cash, Receivable, Inventory。
- 使用index()方法,将上述列表中的Receivable字符串改为Accounts receivable。
- 在Accounts receivable之后插入字符串Notes receivable。
双击阅读参考答案
2.6 元组(Tuple)¶
2.6.1 定义与性质¶
元组(tuple)是一组有序元素,但不可修改(immutable)。常用于表示结构固定的一条记录。
为什么有了列表,还要元组呢?
因为有些数据是结构固定的,比如:一条发票记录包含发票号码、金额、日期等字段,这些字段的含义和位置是固定的,不需要修改。使用元组可以更好地表达这种“结构固定”的数据概念,同时也能节省内存和提高性能。
- 函数的参数和返回值
元组只支持查询操作,不支持增删改操作
# 元组(tuple)常用于表示“结构固定的一条记录”
# 例如:一笔交易记录 (date, invoice_id, account, amount)
tx = ("2026-03-01", "INV1001", "Sales", 1200.50)
print(tx) # 整条记录
print(tx[1]) # 通过索引访问:发票号
# 解包(unpacking):把元组按位置拆成多个变量
date, inv, acct, amt = tx
print(date, inv, acct, amt)
# 查询类操作:len / in / index / count
print("len(tx) =", len(tx)) # 元组长度
print("tx[0:2] =", tx[0:2]) # 切片:取前两个元素
print("'INV1001' in tx ?", "INV1001" in tx) # 判断某个元素是否在元组中,返回 True 或 False
print("tx.index('Sales') =", tx.index("Sales")) # 首次出现位置
print("tx.count('2026-03-01') =", tx.count("2026-03-01")) # 出现次数
2.7 字典(Dictionary)¶
2.7.1 定义与性质¶
字典(dict)是一组键值对(key-value pairs),
基本格式: {key1: value1, key2: value2, ...}
具有以下特点:
- 键(key)必须唯一,值(value)可以重复
- 通过 key 快速访问 value
- 适合做“映射表”“分类汇总”“计数统计”
# 键必须唯一
dict1 = {"INV1001": 1200.50, "INV1002": 850.00}
print(dict1)
dict1 = {"INV1001": 1200.50, "INV1002": 850.00, "INV1001": 1300.00} # 键重复,后一个覆盖前一个
print(dict1)
2.7.2 常用字典方法¶
| 方法/写法 | 作用 | 备注 |
|---|---|---|
d[key] |
按键取值 | key 不存在会报错 |
d.get(key, default) |
安全取值 | key 不存在返回 default |
d.keys() |
所有键 | 可用于遍历键 |
d.values() |
所有值 | 可用于遍历值 |
d.items() |
(key, value) 对 | 最常用于遍历 |
d.update(other) |
批量更新/合并 | other 可以是 dict 或键值对序列 |
d.setdefault(key, default) |
若 key 不存在则插入 | 返回该 key 的值 |
d.pop(key[, default]) |
删除并返回值 | 可提供 default 避免报错 |
d.popitem() |
删除并返回一对键值 | Python 3.7+ 通常是“最后插入”的键值对 |
d.clear() |
清空字典 | 变为空字典 {} |
Note
d[key]在 key 不存在时会抛出KeyError;不确定 key 是否存在时优先用d.get(key, default)。
# --- 0:定义字典(key -> value) ---
accounts = {
"Sales": 1700.50,
"COGS": 630.20,
"Rent": 15000.00
}
print("Cell 0 | start accounts =", accounts)
# --- 1:增 (Add) ---
# 核心逻辑:直接赋值(key不存在时)或 update()
print("Initial accounts:", accounts)
# 方式 A:直接赋值(key 不存在 = 新增)
accounts["Utilities"] = 420.00
accounts["Tax"] = 0.00
print("After add Utilities & Tax:", accounts)
# 方式 B:update() 批量新增
accounts.update({"Interest": 55.50, "Other": 100.00})
print("After update/add:", accounts)
# --- 2:删 (Delete) ---
# 核心逻辑:del (语句) / pop (方法) / clear (清空)
print("Before delete:", accounts)
# 方式 A:del 语句(按键删除,不返回被删值)
if "Other" in accounts:
del accounts["Other"]
print("Deleted 'Other'")
# 方式 B:pop() 方法(删除并返回被删值,安全起见可给默认值或先判定)
if "Tax" in accounts:
removed_tax = accounts.pop("Tax")
print("Popped 'Tax':", removed_tax)
# 方式 C:clear() 清空(慎用,这里先不演示清空,以免后面没得玩)
# accounts.clear()
accounts1 = accounts.copy() # 先复制一份,演示清空
accounts1.clear() # 清空 accounts1,但不影响原来的 accounts
print("After clear accounts1:", accounts1)
print("After delete:", accounts)
# --- 3:改 (Modify) ---
# 核心逻辑:直接赋值(key已存在)或 update()
print("Before modify:", accounts)
# 方式 A:直接赋值(key 已存在 = 修改)
accounts["Sales"] = 2000.00 # 原来可能是 1700.50
print("After modify 'Sales':", accounts)
# 方式 B:update() 批量修改
accounts.update({"COGS": 800.00, "Rent": 16000.00})
print("After update/modify:", accounts)
# --- 4:查 (Query) ---
# 核心逻辑:[] / get() / in / keys() / values() / items()
# 1) 按键查询
print("Sales:", accounts["Sales"])
# print(accounts["Unknown"]) # 键不存在会报错 KeyError
# 2) get() 安全查询
print("Unknown (get):", accounts.get("Unknown", 0.0)) # 键不存在返回默认值
# 3) 成员判断 (in)
print("Is 'Rent' in accounts?", "Rent" in accounts)
# 4) 查看结构:keys(), values(), items()
print("All keys: ", list(accounts.keys()))
print("All values:", list(accounts.values()))
print("All items: ", list(accounts.items()))
练习:字典的特性及操作练习¶
建立一个字典,存储下列会计科目表的信息。注:标题行的信息无需存入该字典。
| 编号 | 科目名称 |
|---|---|
| 1001 | Cash |
| 1002 | Bank deposits |
| 1015 | Other cash |
| 6666 | Stock price |
| 1122 | Accounts Receivable |
- 添加一个元素,编号1241,科目名称为:Allowance for bad debts。
- 删除Stock price科目。
双击阅读参考答案
2.8 集合(Set)¶
2.8.1 定义与性质¶
集合(set)是一组无序且不重复的元素,常用于去重与集合运算。
- 无序(unordered)
- 元素唯一(unique)
Note
- 集合是无序的:打印/遍历的顺序不保证稳定。
- 如果你需要稳定顺序,可以用
sorted(s)得到一个“排好序的列表”。
2.8.2 常用集合操作¶
集合因为无序性,没有索引和切片操作,但支持丰富的集合运算:
| 操作 | 写法 | 说明 |
|---|---|---|
| 去重 | set(list_like) |
把列表/元组等转为集合,自动去重 |
| 成员判断 | x in s |
判断元素是否在集合中 |
| 交集 | A & B |
两个集合共同拥有的元素 |
| 并集 | A \| B |
两个集合所有元素(自动去重) |
| 差集 | A - B |
在 A 中但不在 B 中的元素 |
| 对称差 | A ^ B |
只在其中一个集合出现的元素 |
# 集合(set)常用于“去重”和“集合运算”
invoice_ids = ["INV1001", "INV1002", "INV1001", "INV1003"]
unique_ids = set(invoice_ids) # 去重
# 成员判断(in)
print("INV1002" in unique_ids)
# 集合运算:交集、并集等
# 集合和字典都使用花括号 {} 定义,但集合没有键值对,只有元素(无序且唯一)
A = {"INV1", "INV2", "INV3"}
B = {"INV2", "INV4"}
# 若要定义空集合,不能直接用 {},因为 {} 是空字典的语法
empty_set = set() # 定义一个空集合
print("Empty set:", empty_set)
print("A & B:", A & B) # 交集
print("A | B:", A | B) # 并集
print("A - B:", A - B) # 差集
2.9 类型转换(Type Conversion)¶
不同数据类型之间可以相互转换。常见的转换函数有:
- 基础类型:
int(),float(),str(),bool() - 容器类型:
list(),tuple(),set(),dict()
Note
类型转换常用于数据清洗。例如:将字符串数字转为整数计算,或利用集合去除列表中的重复项。
# --- 1:基础类型转换 (int / float / str) ---
# 场景:从文件读取的数据往往是字符串,需要转为数字进行计算
s_num = "100"
f_num = 3.14159
# 字符串 -> 整数
i_val = int(s_num)
print(f"str '{s_num}' -> int {i_val}, type: {type(i_val)}")
# 浮点数 -> 整数 (截断小数部分,不四舍五入)
i_from_float = int(f_num)
print(f"float {f_num} -> int {i_from_float} (truncated)")
# 数字 -> 字符串
s_val = str(f_num)
print(f"float {f_num} -> str '{s_val}', type: {type(s_val)}")
# 非法转换示例
# int("abc") # ValueError: invalid literal for int() with base 10: 'abc'
# --- 2:容器类型转换 (list / tuple / set) ---
# 场景:去重、转换为不可变对象作为字典键等
data = [1, 2, 2, 3, 3, 3]
# list -> set (去重)
unique_data = set(data)
print(f"list {data} -> set {unique_data}")
# set -> list (变回列表,方便索引访问)
clean_list = list(unique_data)
print(f"set -> list {clean_list}")
# list/tuple 互转
t_data = tuple(data)
print(f"list -> tuple {t_data} (immutable)")
l_from_t = list(t_data)
print(f"tuple -> list {l_from_t} (mutable)")
# zip -> dict (两个列表合并为字典)
keys = ["name", "age", "role"]
values = ["Alice", 30, "Dev"]
user_dict = dict(zip(keys, values))
print(f"lists -> dict {user_dict}")
【练习:年龄计算器】
请编写代码实现以下功能:
- 使用
input()函数提示用户输入出生年份。 - 将得到的输入(字符串类型)转换为整数类型。
- 计算并输出该用户当前的年龄(以 2026 年为准)。
双击阅读参考答案