Python基础语法:数据类型、容器、分支与循环
完成 Hello World 与 I/O 入门之后,真正进入 Python 编程的世界,首先要掌握的是语言的"骨架":数据类型、变量、字符串与编码、容器类型(list / tuple / dict / set)、条件判断与循环 。这些内容是所有业务逻辑的基石,本文在系统梳理核心知识的同时,也补充了一些原文未展开的细节(如 bool 与 int 的关系、is 与 == 的区别、copy 浅深拷贝、walrus 海象运算符、dict 的有序性等),让你一次学透 Python 的底层规则。
一、数据类型与变量
1.1 内建基本数据类型
Python 原生支持以下几种"立即可用"的数据类型:
类型
示例
说明
整数 int
1, -8080, 0xff00, 10_000_000_000
无大小限制(受内存约束)
浮点数 float
1.23, -9.01, 1.23e9, 1.2e-5
运算可能有舍入误差
字符串 str
'abc', "xyz", '''多行'''
以 Unicode 存储
布尔值 bool
True, False
注意首字母大写
空值 NoneType
None
表示"无值",不是 0
补充说明 :
十六进制 / 二进制 / 八进制 :0xff、0b1010、0o17 分别对应十六、二、八进制字面量。
数字分隔符 :从 Python 3.6 起允许用 _ 分隔数字位,如 1_000_000,只是可读性技巧,对值无影响。
浮点精度陷阱 :0.1 + 0.2 == 0.3 返回 False,精确计算应使用 decimal.Decimal 或 fractions.Fraction。
bool 其实是 int 的子类 :True == 1、False == 0、True + 1 == 2 成立,isinstance(True, int) 返回 True。
1 2 3 4 5 6 7 8 9 10 11 big = 2 ** 1000 print (big) print (0.1 + 0.2 ) print (round (0.1 + 0.2 , 2 )) print (True + 1 ) print (sum ([True , True , False ]))
1.2 字符串与转义
单、双引号等价,'I\'m OK' 等价 "I'm OK";
常用转义:\n(换行)、\t(制表)、\\(反斜杠)、\'、\";
原始字符串 r'...':内部所有 \ 都被当成普通字符,常用于正则表达式和 Windows 路径;
多行字符串 '''...''' 或 """...""",可以包含换行;
二者可以叠加:r'''...''' 多行且不转义。
1 2 3 4 5 6 7 8 print ('I\'m learning\nPython.' ) print (r'C:\Users\Python' ) sql = """ SELECT id, name FROM user WHERE age > 18; """
1.3 布尔运算
三种运算符:and(与)、or(或)、not(非)。
1 2 3 5 > 3 and 3 > 1 5 > 3 or 1 > 3 not 1 > 2
**短路求值(Short-Circuit)**是 Python 的一个重要特性:
1 2 3 4 5 6 7 8 9 10 print (0 and 10 / 0 ) name = '' or '默认名' print (name) print (1 and 2 ) print (0 or 'x' )
Falsy 值(假值) :None、False、0、0.0、''、[]、()、{}、set()。其他都为真值。
1.4 变量:动态类型与"指向"模型
Python 是动态语言,变量本身不固定类型,变量名只是"贴在对象上的标签"。
1 2 3 4 a = 'ABC' b = a a = 'XYZ' print (b)
图示:
1 2 3 4 5 6 7 第 1 步:a = 'ABC' 第 2 步:b = a 第 3 步:a = 'XYZ' ┌───┐ ┌───────┐ ┌───┐ ┌───────┐ ┌───┐ ┌───────┐ │ a │──▶│ 'ABC' │ │ a │──▶│ 'ABC' │ │ a │──▶│ 'XYZ' │ └───┘ └───────┘ └───┘ └───────┘ └───┘ └───────┘ ┌───┐ ▲ ┌───┐ ┌───────┐ │ b │─────┘ │ b │────▶│ 'ABC' │ └───┘ └───┘ └───────┘
1.5 常量
Python 没有真正的常量机制,约定以全大写字母 命名:
1 2 PI = 3.14159265359 MAX_RETRY = 5
注:Python 3.8+ 可以用 typing.Final 做静态检查层面的"不可变约束",但运行期仍然允许改。
1.6 两种除法
1 2 3 4 5 6 10 / 3 9 / 3 10 // 3 10 % 3 -7 // 2 divmod (10 , 3 )
1.7 == 与 is 的区别(补充)
==:比较值是否相等(调用 __eq__);
is:比较是否是同一个对象(地址相同)。
1 2 3 4 5 6 7 a = [1 , 2 , 3 ] b = [1 , 2 , 3 ] print (a == b) print (a is b) c = None print (c is None )
二、字符串与编码
2.1 编码发展史
ASCII :1 字节,只覆盖 127 个英文字符;
GB2312 / Shift_JIS / Euc-kr :各国扩展,易冲突;
Unicode :收录全世界字符,常用 2 字节;
UTF-8 :Unicode 的可变长 编码(1~4 字节),英文 1 字节、中文 3 字节,与 ASCII 完全兼容。
字符
ASCII
Unicode
UTF-8
A
01000001
00000000 01000001
01000001
中
—
01001110 00101101
11100100 10111000 10101101
通用工作方式 :内存里用 Unicode;落盘 / 传输时用 UTF-8。
2.2 str 与 bytes
Python 3 的 str 默认是 Unicode。
1 2 3 4 5 6 ord ('A' ) ord ('中' ) chr (66 ) chr (25991 ) '\u4e2d\u6587'
str ↔ bytes 靠 encode() 与 decode() 互转:
1 2 3 4 5 6 7 'ABC' .encode('ascii' ) '中文' .encode('utf-8' ) b'\xe4\xb8\xad\xe6\x96\x87' .decode('utf-8' ) b'\xe4\xb8\xad\xff' .decode('utf-8' , errors='ignore' )
len() 的含义根据对象不同:
1 2 len ('中文' ) len ('中文' .encode('utf-8' ))
强烈建议 :统一使用 UTF-8 对 str / bytes 进行互转。
2.3 源码编码声明
当 .py 文件包含中文时,推荐在头部写:
第一行让 Unix/macOS 将此文件视为 Python 可执行脚本;第二行告诉解释器源码使用 UTF-8 编码(Python 3 默认即 UTF-8,可省略,但保留更稳妥)。
2.4 字符串格式化三种姿势
1)% 格式化(C 风格)
1 2 3 4 5 'Hello, %s' % 'world' 'Hi, %s, you have $%d.' % ('Michael' , 1000000 )'%2d-%02d' % (3 , 1 ) '%.2f' % 3.1415926 'growth rate: %d %%' % 7
常见占位符:
占位符
含义
%d
整数
%f
浮点数
%s
字符串(万能)
%x
十六进制
2)str.format()
1 'Hello, {0}, 成绩提升了 {1:.1f}%' .format ('小明' , 17.125 )
3)f-string(推荐,Python 3.6+)
1 2 3 4 5 6 7 r = 2.5 s = 3.14 * r ** 2 print (f'圆面积:{s:.2 f} ' ) x, y = 3 , 4 print (f'{x=} , {y=} ' )
个人推荐顺序 :f-string > format > %。f-string 速度最快、可读性最好。
三、list 与 tuple
3.1 list:可变有序序列
1 2 3 4 5 6 7 8 9 10 classmates = ['Michael' , 'Bob' , 'Tracy' ] len (classmates) classmates[0 ] classmates[-1 ] classmates.append('Adam' ) classmates.insert(1 , 'Jack' ) classmates.pop() classmates.pop(1 ) classmates[1 ] = 'Sarah'
list 元素类型可以混合,也可以嵌套:
1 2 3 L = ['Apple' , 123 , True ] s = ['python' , 'java' , ['asp' , 'php' ], 'scheme' ] s[2 ][1 ]
常用操作补充 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 L = [3 , 1 , 4 , 1 , 5 , 9 , 2 , 6 ] L.sort() sorted (L) L.reverse() L[::-1 ] L.count(1 ) L.index(5 ) L[2 :5 ] L[:3 ] L[-3 :] L[::2 ]
3.2 tuple:不可变有序序列
1 2 3 t = ('Michael' , 'Bob' , 'Tracy' ) t[0 ]
三个陷阱 :
1 2 3 t = () t = (1 ) t = (1 ,)
“不可变的 tuple” 里可以有可变元素 :
1 2 3 4 t = ('a' , 'b' , ['A' , 'B' ]) t[2 ][0 ] = 'X' t[2 ][1 ] = 'Y' print (t)
tuple 的"不变"指的是:每个位置的引用(指向)不变 ,但它指向的对象本身(比如 list)可以被修改。真正"内容也不变"的 tuple,要求内部每个元素都是不可变对象。
3.3 补充:浅拷贝 vs 深拷贝
由于 list / dict 等是可变对象,赋值只是复制引用:
1 2 3 4 5 6 7 8 a = [1 , 2 , [3 , 4 ]] b = a b[0 ] = 99 print (a) import copyb = copy.copy(a) b = copy.deepcopy(a)
四、条件判断:if / elif / else
1 2 3 4 5 6 7 age = 3 if age >= 18 : print ('adult' ) elif age >= 6 : print ('teenager' ) else : print ('kid' )
关键规则 :
缩进决定代码块(通常 4 个空格);
冒号 : 不能漏;
从上向下匹配,命中任一分支后跳出整个 if ;
if x: 等价于 if bool(x):,Falsy 值见前文。
1 2 3 4 5 6 7 birth = input ('birth: ' ) birth = int (birth) if birth < 2000 : print ('00前' ) else : print ('00后' )
当输入 'abc' 这类非法字符时 int() 会抛 ValueError,正式工程中需要 try-except 包裹(后续章节会讲)。
4.2 三目表达式与海象运算符(补充)
1 2 3 4 5 6 label = 'adult' if age >= 18 else 'teenager' while (line := input ('> ' )) != 'quit' : print (f'你输入了:{line} ' )
五、match 语句(Python 3.10+)
针对"单个变量匹配多种情况"的场景,match 比一长串 if-elif 更清晰。
5.1 基础用法
1 2 3 4 5 6 7 8 9 10 score = 'B' match score: case 'A' : print ('score is A.' ) case 'B' : print ('score is B.' ) case 'C' : print ('score is C.' ) case _: print ('invalid score.' )
5.2 复杂匹配:值范围 / 多值 / 绑定变量
1 2 3 4 5 6 7 8 9 10 11 12 age = 15 match age: case x if x < 10 : print (f'< 10 years old: {x} ' ) case 10 : print ('10 years old.' ) case 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 : print ('11~18 years old.' ) case 19 : print ('19 years old.' ) case _: print ('not sure.' )
5.3 列表 / 序列解构
1 2 3 4 5 6 7 8 9 10 args = ['gcc' , 'hello.c' , 'world.c' ] match args: case ['gcc' ]: print ('gcc: missing source file(s).' ) case ['gcc' , file1, *files]: print ('gcc compile: ' + file1 + ', ' + ', ' .join(files)) case ['clean' ]: print ('clean' ) case _: print ('invalid command.' )
5.4 补充:字典 / 类解构
match 的能力远不止匹配值,它是一种真正的结构化模式匹配 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 def handle (event ): match event: case {'type' : 'click' , 'x' : x, 'y' : y}: print (f'click at ({x} , {y} )' ) case {'type' : 'key' , 'key' : k}: print (f'press {k} ' ) case _: print ('unknown' ) from dataclasses import dataclass@dataclass class Point : x: int y: int def where (p ): match p: case Point(x=0 , y=0 ): return '原点' case Point(x=0 , y=_): return 'Y 轴' case Point(x=_, y=0 ): return 'X 轴' case Point(): return '平面其他位置'
六、循环:for 与 while
6.1 for 循环
1 2 3 names = ['Michael' , 'Bob' , 'Tracy' ] for name in names: print (name)
配合 range() 生成整数序列:
1 2 3 4 5 6 7 8 list (range (5 )) list (range (1 , 6 )) list (range (0 , 10 , 2 )) s = 0 for x in range (101 ): s += x print (s)
6.2 while 循环
1 2 3 4 5 s, n = 0 , 99 while n > 0 : s += n n -= 2 print (s)
6.3 break / continue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 n = 1 while n <= 100 : if n > 10 : break print (n) n += 1 n = 0 while n < 10 : n += 1 if n % 2 == 0 : continue print (n)
⚠️ 避免滥用 break / continue,它们会让逻辑分支变多,更易出 bug。多数场景可以用清晰的循环条件替代。
6.4 补充:for-else、enumerate、zip
Python 的循环有一个冷门但很好用的 else 分支 ——只有循环"正常跑完"(没被 break 打断)才会执行:
1 2 3 4 5 for x in range (10 ): if x == 100 : break else : print ('没 break,来 else 了' )
enumerate 同时拿下标和元素:
1 2 3 4 for i, name in enumerate (['Alice' , 'Bob' ], start=1 ): print (i, name)
zip 并行迭代多个序列:
1 2 3 4 names = ['Alice' , 'Bob' ] ages = [20 , 25 ] for n, a in zip (names, ages): print (n, a)
七、dict 与 set
7.1 dict:键值映射
1 2 3 4 5 6 7 8 9 d = {'Michael' : 95 , 'Bob' : 75 , 'Tracy' : 85 } d['Michael' ] d['Adam' ] = 67 'Thomas' in d d.get('Thomas' ) d.get('Thomas' , -1 ) d.pop('Bob' )
key 必须是不可变(可哈希)对象 :int、float、str、bool、tuple(且内部全为不可变)等都可以,list、dict、set 不行。
7.2 dict vs list 的权衡
维度
dict
list
查找 / 插入速度
O(1),非常快
O(n),随元素增加变慢
内存占用
大
小
有序性
Python 3.7+ 保留插入顺序 (语言规范保证)
有序
补充 :Python 3.6 CPython 实现已经让 dict 保留插入顺序,3.7 起成为语言规范。所以现在的 dict 既快又有序。
7.3 dict 常用操作补充
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 d = {'a' : 1 , 'b' : 2 , 'c' : 3 } list (d.keys()) list (d.values()) list (d.items()) for k, v in d.items(): print (k, v) d1 = {'a' : 1 } d2 = {'b' : 2 } merged = d1 | d2 d.setdefault('d' , 4 ) sq = {x: x*x for x in range (5 )}
7.4 set:无序不重集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 s = {1 , 2 , 3 } s = set ([1 , 2 , 3 ]) s = set () s.add(4 ) s.remove(4 ) s.discard(99 ) s1, s2 = {1 , 2 , 3 }, {2 , 3 , 4 } s1 & s2 s1 | s2 s1 - s2 s1 ^ s2
常见用途:去重 与成员检查 (同样是 O(1))。
1 unique = list (set ([1 , 1 , 2 , 2 , 3 , 3 ]))
7.5 可变对象与不可变对象
1 2 3 4 5 6 a = ['c' , 'b' , 'a' ] a.sort() s = 'abc' s.replace('a' , 'A' ) print (s)
对于不可变对象(str、int、tuple、frozenset),所有方法都"返回新对象",原对象永不改变——这正是它们可以作为 dict key / set 元素的原因。
八、综合示例:通讯录管理器
下面把本文所有知识点串起来,做一个小小的通讯录程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 contacts: dict [str , dict ] = {} def add (name, phone, age ): if name in contacts: print (f'⚠️ {name} 已存在,将被覆盖' ) contacts[name] = {'phone' : phone, 'age' : int (age)} def remove (name ): if contacts.pop(name, None ) is None : print (f'❌ 没有找到 {name} ' ) else : print (f'✅ 已删除 {name} ' ) def show_all (): if not contacts: print ('(通讯录为空)' ) return for i, (name, info) in enumerate (contacts.items(), start=1 ): print (f'{i} . {name} | {info["phone" ]} | {info["age" ]} 岁' ) def main (): add('Alice' , '13800000001' , 20 ) add('Bob' , '13800000002' , 25 ) add('Carol' , '13800000003' , 30 ) while True : cmd = input ('\n请输入命令 (add/del/list/quit): ' ).strip().split() if not cmd: continue match cmd: case ['quit' ]: print ('bye~' ) break case ['list' ]: show_all() case ['add' , name, phone, age]: add(name, phone, age) case ['del' , name]: remove(name) case _: print ('❓ 无效命令,用法:add <name> <phone> <age> | del <name> | list | quit' ) if __name__ == '__main__' : main()
这个例子涉及了:dict 嵌套、input + split、match 列表解构、for-enumerate、f-string、函数定义与默认返回值等多项内容,是一个很好的综合练习。
九、学习建议与下一步
先打好数据类型基础 :所有高级特性都建立在 int / float / str / list / tuple / dict / set / bool / None 之上。
理解"引用模型" :变量只是"贴在对象上的标签",这是理解赋值、函数参数传递、拷贝等行为的关键。
牢记可变 vs 不可变 :决定了能否做 dict key、默认参数陷阱、是否需要深浅拷贝。
熟练使用 f-string :现代 Python 的"首选"字符串格式化方式。
多写代码 :把通讯录、成绩录入、单词计数等小程序反复写几遍,比读十篇文章都管用。
掌握了本文内容,你已经可以用 Python 写出带基础逻辑的实用脚本了。下一步的重点将是函数、作用域与模块 ,让代码从"脚本"变成"可复用的结构"。
参考资料