书架 · Python 学习系列 · 01 · Python 基础下一章:02 Python 进阶 →
01 · Python 基础
本章目标:装好环境,掌握变量、流程控制、四大核心数据结构、函数、模块、异常处理。学完你能独立写出几百行的脚本。
前置知识:会任何一门编程语言(你写过 Java,这章会非常快)。
目录
- Python 是什么,为什么 AI 圈都用它
- 环境搭建(Windows 11)
- 第一个程序:REPL 与脚本
- 变量与基本数据类型
- 字符串
- 运算符
- 流程控制
- 四大核心数据结构:list / tuple / dict / set
- 函数
- 模块与包
- 文件读写初步
- 异常处理
- 自测清单
- 小练习
1. Python 是什么,为什么 AI 圈都用它
Python 是一门动态类型、解释执行的语言。它成为 AI 第一语言不是偶然:
- 所有主流大模型 SDK(OpenAI、Anthropic、智谱、DeepSeek、通义)Python 版都是一等公民,新特性最先发布
- 数据科学生态(numpy / pandas / pytorch)只有 Python 版可用
- Web 侧 FastAPI 天然契合 AI 服务:异步、类型提示、流式输出
☕ Java vs Python 一句话:Java 是"编译成字节码跑在 JVM 上的静态类型语言",Python 是"解释器直接执行的动态类型语言"。Java 重工程规整,Python 重开发速度。两者不是替代关系——你以后大概率是 Java 写业务 + Python 写 AI 的双枪将。
| 维度 | Java | Python |
|---|---|---|
| 类型 | 静态,编译期检查 | 动态,运行时才知道 |
| 语句结尾 | ; |
换行即结尾 |
| 代码块 | { } |
缩进(4 个空格) |
| 注释 | // 和 /* */ |
# 和 """文档字符串""" |
| 主流场景 | 企业后端、大数据 | AI、数据科学、脚本、Web |
| 运行方式 | 先 javac 编译再运行 |
python xxx.py 直接跑 |
最重要的一条:Python 用缩进表示代码块,缩进错了程序就错了(甚至逻辑变了但没报错)。请从今天起统一用 4 个空格,不要混用 Tab。
2. 环境搭建(Windows 11)
2.1 安装 Python
- 去 python.org/downloads 下载 Python 3.12+ 的 Windows installer(64-bit)
- 安装第一屏务必勾选 "Add python.exe to PATH"(这是新手第一大坑)
- 验证:打开 PowerShell(或 Git Bash),执行:
python --version # 输出 Python 3.12.x 即成功
pip --version # pip 是 Python 的包管理器,类似 maven
⚠️ 本机如果装了多个 Python,
python命令可能指向老版本。用where python(PowerShell 用Get-Command python)排查。
2.2 安装 uv(现代工具链,强烈推荐)
uv 是 Astral 公司用 Rust 写的 Python 工具链,一个命令搞定 Python 版本管理、虚拟环境、依赖安装,速度比 pip 快 10 倍以上,2024 年后已是事实标准:
# PowerShell 安装
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# 验证
uv --version
安装后你可以完全不用系统 Python,uv 能自己管理:
uv python install 3.12 # 安装某个版本的 Python
uv python list # 查看可用版本
📌 本章你只需要记住 3 条 uv 命令(第 03 章系统讲): -
uv init demo—— 新建项目 -uv add requests—— 加依赖(自动创建虚拟环境) -uv run main.py—— 在项目环境中运行
2.3 编辑器:VSCode
- 安装 VSCode
- 扩展市场搜 Python(Microsoft 官方)安装
- 装 Pylance(语法提示,随 Python 扩展自带)
写大项目也可以用 PyCharm(社区版免费),但 VSCode + Pylance 对新手完全够用且更轻。
3. 第一个程序:REPL 与脚本
3.1 REPL(交互式环境)
终端输入 python 回车,进入交互模式(>>> 提示符),适合做"草稿纸":
>>> 1 + 1
2
>>> "hello" * 3
'hellohellohello'
>>> exit() # 退出
新手建议:学本章时把所有示例都在 REPL 里敲一遍,肌肉记忆比看书强十倍。
3.2 脚本文件
新建 hello.py:
# hello.py
print("Hello, Python!")
name = "macao"
age = 18
print(f"{name} 今年 {age} 岁") # f-string,第 5 节细讲
运行:
python hello.py
# 或者用 uv(自动使用项目环境)
uv run hello.py
☕ 对照 Java:不需要
public class Hello { public static void main(String[] args) }这套样板,顶层直接写语句。print()就是System.out.println()。
4. 变量与基本数据类型
4.1 变量:没有类型声明
age = 18 # int
price = 9.99 # float
is_vip = True # bool(注意大写开头:True / False)
name = "macao" # str
nothing = None # None 类似 Java 的 null
# 变量只是"名字标签",可以随时贴到别的类型上
x = 100
x = "换个类型也行" # 合法!但工程里别这么干(有类型检查工具,见第 02 章)
查看类型:
age = 18
is_vip = True
type(age) # <class 'int'>
type(is_vip) # <class 'bool'>
☕ Java vs Python: - Java:
int age = 18;—— 类型属于变量 - Python:age = 18—— 类型属于值,变量只是名字。等价于所有变量都是Object age,但用起来有各自类型的方法 - Python 的None≈ Java 的null,判断写if x is None:(不是==,见第 02 章的坑)
4.2 数字
# int 无限精度,不会像 long 一样溢出
2 ** 100 # 直接算,2 的 100 次方
# 除法有三种
7 / 2 # 3.5 —— 真除法,结果永远是 float
7 // 2 # 3 —— 地板除,扔掉小数
7 % 2 # 1 —— 取模
round(3.14159, 2) # 3.14 —— 四舍五入到 2 位
abs(-5) # 5
int("42") # 42 —— 字符串转 int
float("3.14") # 3.14
str(42) # "42" —— 转字符串
☕ Java 里
7 / 2是 3(整数除法),Python 里/永远给 float,//才是整数除法。这跟 Java 正好相反,注意。
4.3 bool 与真值
True and False # False
True or False # True
not True # False
# Python 独有:任何值都有"真值性"
# 以下都算 False:0、0.0、""、空 list/dict/set、None
# 其余全是 True
items = []
if not items: # 不用写 len(items) == 0
print("空的")
5. 字符串
5.1 三种引号与 f-string
s1 = '单引号'
s2 = "双引号" # 两者完全等价,习惯上外双内单
s3 = """三引号可以
跨越多行,
类似 Java 的文本块""" # Java 15+ 的 """
# f-string:格式化字符串(必学,相当于 String.format 的语法糖)
name, score, age = "macao", 92.5, 18
print(f"{name} 的分数是 {score}")
print(f"明年 {age + 1} 岁") # {} 里可以放表达式
print(f"{score:.1f}") # 92.5,保留 1 位小数
print(f"{1234567:,}") # 1,234,567 千分位
print(f"{'居中':^10}") # 填充对齐
5.2 常用方法
s = " Hello, Python "
s.strip() # "Hello, Python" 去两端空白
s.strip().lower() # "hello, python"
s.replace("Python", "Java")
s.split(",") # 按分隔符切 → list
"a,b,c".split(",") # ['a', 'b', 'c']
"-".join(["2026", "09", "05"]) # "2026-09-05" ← 注意 join 写在分隔符上
"abc123".startswith("abc")
"abc123".endswith("123")
"py" in "python" # True —— 成员判断直接用 in
len("python") # 6
"hello"[0] # 'h' —— 索引取字符
☕ Java vs Python:Java 字符串是不可变的,Python 同样不可变——所有方法都返回新串。但 Python 用
in代替contains(),用len()代替.length(),切片代替substring()。
5.3 切片(slicing)—— 高频技巧
s = "python"
s[0] # 'p' 正索引从 0 开始
s[-1] # 'n' 负索引从末尾数,-1 是最后一个
s[0:3] # 'pyt' 第 0~2 个(左闭右开,同 Java substring)
s[2:] # 'thon' 省略结尾 = 到最后
s[:2] # 'py' 省略开头 = 从头开始
s[::2] # 'pto' 步长 2,隔一个取一个
s[::-1] # 'nohtyp' 反转字符串的惯用写法
切片同样适用于 list/tuple,是 Python 的核心操作,务必练熟。
6. 运算符
# 算术:+ - * / // % **
2 ** 10 # 1024
# 比较:== != > < >= <=,产出 bool
# ⭐ Python 支持链式比较(Java 不支持)
age = 30
18 < age < 60 # 等价于 18 < age and age < 60
# 逻辑:and / or / not(不是 && || !)
a, b = True, False
a and b # False
# 身份判断:is / is not(比较"是不是同一个对象")
x = None
x is None # True —— 判断 None 的标准写法
# 成员判断:in / not in
3 in [1, 2, 3] # True
"k" not in "abc" # True
☕ 对照:
&&→and,||→or,!→not。Python 没有++/--,自增写i += 1。没有三元? :,写x = a if cond else b。
7. 流程控制
7.1 if / elif / else
score = 85
if score >= 90:
grade = "A"
elif score >= 80: # elif = else if
grade = "B"
elif score >= 60:
grade = "C"
else:
grade = "D"
☕ 没有
switch(3.10+ 有match-case,语法见下,但底层是模式匹配,比 switch 强大):
command = "start"
match command:
case "start":
print("启动")
case "stop" | "exit": # 或模式
print("停止")
case _: # default
print("未知命令")
7.2 for 循环 —— 是"foreach",不是计数器
# Python 的 for 只有一种形态:遍历可迭代对象
for fruit in ["苹果", "香蕉", "橘子"]:
print(fruit)
for ch in "abc":
print(ch) # 字符串也能遍历
# 要计数器时用 range
for i in range(5): # 0 1 2 3 4(左闭右开)
print(i)
for i in range(2, 10, 2): # 2 4 6 8(起、止、步长)
print(i)
# 同时要下标和值:enumerate(Java 里 for-i 循环的替身)
for i, fruit in enumerate(["苹果", "香蕉"]):
print(i, fruit) # 0 苹果 / 1 香蕉
# 并行遍历多个序列:zip
names = ["Tom", "Jerry"]
ages = [3, 4]
for name, age in zip(names, ages):
print(name, age)
☕ Java vs Python:
for (int i = 0; i < n; i++)在 Python 里几乎不存在,等价物是for i in range(n);遍历集合用for x in list(= Java 的for (var x : list))。需要下标时永远优先 enumerate,不要range(len(list))再下标访问(暴露你是 Java 转来的 :))。
7.3 while、break、continue、循环 else
count = 0
while count < 3:
print(count)
count += 1
# break / continue 与 Java 一致
# Python 特色:循环可以带 else(循环没被 break 才执行)
for n in [2, 4, 6, 7]:
if n % 2 == 1:
print("发现奇数", n)
break
else:
print("全是偶数") # 没有 break 时走这里
循环 else 在"查找类"逻辑里很好用:找到就 break,走完没找到进 else。
8. 四大核心数据结构:list / tuple / dict / set
☕ 总对照表(先记这个):
Python 近似 Java 可变 有序 典型用途 listArrayList<Object>✅ ✅ 通用有序集合 tupleList.of(...)不可变 List❌ ✅ 固定结构、函数多返回值 dictHashMap<K,V>✅ ✅(3.7+) 键值映射,到处都是 setHashSet<Object>✅ ❌ 去重、成员判断
8.1 list
# 创建
nums = [1, 2, 3]
mixed = [1, "two", 3.0, [4, 5]] # 可混合类型(但工程里别混)
empty = []
# 增
nums.append(4) # 尾部追加 → [1,2,3,4]
nums.insert(0, 0) # 指定位置插入
nums.extend([5, 6]) # 拼接另一个 list
# 删
nums.remove(3) # 按值删(第一个匹配)
last = nums.pop() # 弹出尾部并返回
first = nums.pop(0) # 弹出指定下标
del nums[0] # 按下标删
# 改 / 查
nums[0] = 100
nums[1] # 读
nums[-1] # 最后一个
nums[1:3] # 切片,返回新 list
len(nums) # 长度
# 判断
3 in nums # True
# 排序
sorted([3, 1, 2]) # [1,2,3] 返回新列表
sorted([3, 1, 2], reverse=True) # [3,2,1]
nums.sort() # 原地排序,返回 None ⚠️
words = ["banana", "apple", "fig"]
sorted(words, key=len) # ['fig', 'apple', 'banana'] 按长度排
# 常用聚合
sum([1, 2, 3]) # 6
max([1, 5, 3]) # 5
min([1, 5, 3]) # 1
⚠️
list.sort()是原地排序返回None,sorted()返回新列表。新手常写nums = nums.sort(),结果 nums 变成 None。
8.2 list 推导式(comprehension)—— Python 灵魂语法
# 传统写法
squares = []
for x in range(10):
squares.append(x ** 2)
# 推导式一行搞定
squares = [x ** 2 for x in range(10)]
# 带条件过滤
evens = [x for x in range(20) if x % 2 == 0]
# 带 if-else 转换
labels = ["偶" if x % 2 == 0 else "奇" for x in range(5)]
# 嵌套(少用,可读性差)
pairs = [(x, y) for x in range(3) for y in range(3)]
☕ 等价于 Java Stream 的
map/filter/collect:[x**2 for x in xs if x>0]≈xs.stream().filter(x->x>0).map(x->x*x).toList()。Python 里能用推导式就不用 for 循环 append,这是地道写法。
8.3 tuple
point = (3, 5) # 圆括号(可省略,但别省)
single = (42,) # ⚠️ 单元素必须带逗号
x, y = point # 解包(unpacking)——超常用
x, y = y, x # 交换变量不需要中间变量!
# 函数返回多个值其实就是返回 tuple
def min_max(nums):
return min(nums), max(nums)
lo, hi = min_max([3, 1, 4]) # 解包接收
tuple 不可变:point[0] = 9 会抛 TypeError。它的意义:表达"固定结构的数据"(坐标、配置项),以及作为 dict 的 key。
8.4 dict
# 创建
user = {"name": "macao", "age": 18}
empty = {}
# 增改
user["city"] = "成都" # 有则改,无则增
# 查
user["name"] # key 不存在 → KeyError ⚠️
user.get("name") # 不存在 → None
user.get("phone", "未填写") # 不存在 → 给默认值
# 删
del user["city"]
age = user.pop("age") # 删除并返回值
# 判断 key
"name" in user # True(判断的是 key,不是 value!)
# 遍历
for key in user: # 默认遍历 key
print(key, user[key])
for key, value in user.items(): # 同时要 key value(最常用)
print(key, value)
for v in user.values():
print(v)
# 常用
len(user)
user.update({"age": 20, "vip": True}) # 批量合并
new_user = {**user, "extra": 1} # 合并出新 dict(不改动原 dict)
# 字典推导式
lengths = {name: len(name) for name in ["ab", "cde"]}
☕
dict.get(k, default)≈map.getOrDefault(k, d)。JSON 与 dict 结构同构,AI 开发里 API 报文、模型消息全是 dict/list 嵌套,dict 是 Python 里最重要的结构,没有之一。
8.5 set
s = {1, 2, 3}
empty_set = set() # ⚠️ {} 是空 dict,不是空 set!
s.add(4)
s.remove(1) # 元素不存在会抛 KeyError
s.discard(99) # 不存在也不报错
# 核心价值 1:去重
nums = [1, 2, 2, 3, 3, 3]
unique = list(set(nums)) # [1, 2, 3](顺序不保证)
# 核心价值 2:集合运算
a = {1, 2, 3}
b = {3, 4, 5}
a & b # {3} 交集
a | b # {1,2,3,4,5} 并集
a - b # {1,2} 差集
a ^ b # {1,2,4,5} 对称差
# 核心价值 3:O(1) 成员判断(大 list 判断存在性前先转 set)
big_list = list(range(1_000_000))
big_set = set(big_list)
10000 in big_list # O(n) 慢
10000 in big_set # O(1) 快
8.6 解包进阶(很常用)
first, *rest = [1, 2, 3, 4] # first=1, rest=[2,3,4]
*init, last = [1, 2, 3, 4] # init=[1,2,3], last=4
def f(*args, **kwargs): # 见函数一节
pass
f(*[1, 2], **{"k": 3}) # 调用时解包展开
9. 函数
9.1 定义与调用
def add(a, b):
"""两数相加。这行叫 docstring,是 Python 的文档注释。"""
return a + b
# 无返回值函数默认返回 None
def greet(name):
print(f"hello {name}")
result = greet("macao") # result 是 None
☕
def≈ 方法定义;docstring ≈ Javadoc;没有可见性关键字(没有 public/private,惯例用_name表示私有);没有方法重载(后定义覆盖先定义,同名不同参靠默认参数解决)。
9.2 参数的四种形态(重点)
# 1. 位置参数(最普通)
def power(x, n):
return x ** n
# 2. 关键字参数:调用时指名道姓,可读性神器
power(n=2, x=3) # 不用管顺序
# 3. 默认参数
def greet(name, greeting="你好"):
return f"{greeting}, {name}"
greet("Tom") # 你好, Tom
greet("Tom", greeting="Hello") # Hello, Tom
# ⚠️ 头号新手坑:默认值绝不能是 list/dict 等可变对象!
def bad(items=[]): # ❌ 默认值在函数定义时只创建一次,多次调用共享
items.append(1)
return items
bad() # [1]
bad() # [1, 1] ← 惊不惊喜
def good(items=None): # ✅ 标准写法
items = items if items is not None else []
items.append(1)
return items
# 4. 可变参数:*args 收集多余位置参数为 tuple,**kwargs 收集多余关键字参数为 dict
def summary(*args, **kwargs):
print(args, kwargs)
summary(1, 2, 3, mode="fast", debug=True)
# (1, 2, 3) {'mode': 'fast', 'debug': True}
9.3 lambda
# lambda 只能写一个表达式
square = lambda x: x ** 2
# 主要用途:作为 key 函数传给 sorted / max / min
users = [{"name": "a", "age": 30}, {"name": "b", "age": 25}]
by_age = sorted(users, key=lambda u: u["age"])
oldest = max(users, key=lambda u: u["age"])
☕ ≈ Java 的
(x) -> x * x。Python 的 lambda 故意做得弱(只能一个表达式),复杂逻辑就老老实实def。
9.4 作用域
x = 10 # 全局
def outer():
y = 20 # 局部
def inner():
nonlocal y # 引用外层函数变量(少用)
y += 1
inner()
def read_global():
print(x) # 读全局 OK
def write_global():
global x # 想改全局要声明(工程里避免这种写法)
x = 99
10. 模块与包
10.1 import
import math # 导入整个模块
math.sqrt(16) # 4.0
from math import sqrt, pi # 导入具体名字(常用)
sqrt(16) # 直接用
import numpy as np # 起别名(社区惯例,如 np / pd)
from datetime import datetime # 标准库常用模块
# ⚠️ 不推荐 from math import *(污染命名空间)
☕
import≈import,一个.py文件就是一个模块(≈ Java 一个类文件),一个带__init__.py的目录就是一个包(≈ package)。区别:Python 导入的是整个模块对象,from x import y是把模块里的名字 y 拿到当前命名空间。
10.2 if __name__ == "__main__":
# utils.py
def add(a, b):
return a + b
def main():
print("自测:", add(1, 2))
# __name__ 是模块的内置名字:
# 直接运行本文件时它是 "__main__",被别人 import 时它是模块名 "utils"
if __name__ == "__main__":
main()
这是 Python 版的"入口函数":让文件既能当库被导入、又能当脚本直接跑。每个可执行脚本都应带上它。
10.3 用第三方库
# 传统方式(pip)
pip install requests
# uv 项目方式(推荐,见第 03 章)
uv add requests
import requests
resp = requests.get("https://api.github.com")
print(resp.status_code)
11. 文件读写初步
# with 语句自动关文件(≈ try-with-resources,第 02 章细讲原理)
with open("data.txt", "w", encoding="utf-8") as f: # ⚠️ Windows 下必带 encoding
f.write("第一行\n")
f.write("第二行\n")
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read() # 一次读全
with open("data.txt", encoding="utf-8") as f:
for line in f: # 逐行读(大文件友好)
print(line.strip()) # strip 去掉行尾换行符
# 追加模式 "a",二进制 "rb"/"wb"
模式:r 读(默认)/ w 清空写 / a 追加写 / x 新建写(存在则报错)。
JSON 读写(AI 开发天天用):
import json
user = {"name": "macao", "tags": ["py", "ai"], "vip": True}
with open("user.json", "w", encoding="utf-8") as f:
json.dump(user, f, ensure_ascii=False, indent=2) # ensure_ascii=False 才能存中文
with open("user.json", encoding="utf-8") as f:
loaded = json.load(f)
# 串 ↔ 对象(更常用)
s = json.dumps(user, ensure_ascii=False) # dict → str
d = json.loads(s) # str → dict
☕
json.dumps≈objectMapper.writeValueAsString,json.loads≈readValue。Python 的 dict/list 天生就是 JSON 结构,没有"实体类"这一层。
12. 异常处理
12.1 基本结构
try:
num = int("abc") # ValueError
except ValueError as e:
print(f"转换失败: {e}")
except (KeyError, IndexError): # 一个 except 接多种异常
print("键或下标错了")
except Exception as e: # 兜底(≈ catch (Exception e))
print(f"未知错误: {e}")
else:
print("没出异常才执行") # Java 没有这个块
finally:
print("无论如何都执行")
常见异常类型速查:
| 异常 | 场景 |
|---|---|
ValueError |
值不对:int("abc") |
TypeError |
类型不对:"a" + 1 |
KeyError |
dict key 不存在 |
IndexError |
下标越界 |
FileNotFoundError |
文件不存在 |
ZeroDivisionError |
除零 |
AttributeError |
属性/方法不存在:None.xxx 高频! |
12.2 抛出与自定义
def set_age(age):
if age < 0:
raise ValueError(f"年龄不能为负: {age}") # raise ≈ throw
return age
# 自定义异常:继承 Exception 即可
class BusinessError(Exception):
def __init__(self, code: str, message: str):
super().__init__(message)
self.code = code
raise BusinessError("A0001", "余额不足")
☕ 对照 Java: - Python 没有 checked 异常——所有异常都相当于
RuntimeException,函数签名不声明也不强制捕获 -raise=throw,except=catch,finally同义 - Python 文化是 EAFP(It's Easier to Ask Forgiveness than Permission):先直接干,错了再 catch。Java 的 LBYL(先 if 判断再执行)风格在 Python 里常被认为不地道:
d = {"name": "macao"} # 示例数据
default = "未填写"
# LBYL(Java 风)
if "key" in d:
v = d["key"]
# EAFP(Python 风)
try:
v = d["key"]
except KeyError:
v = default
print(v) # 未填写(两条路都没进 if,最终由 except 兜住)
13. 自测清单
能不查资料回答以下问题,本章就算过关:
- [ ] Python 用什么表示代码块?推荐几个空格?
- [ ]
7 / 2和7 // 2分别输出什么? - [ ] list、tuple、dict、set 分别对应 Java 的什么?哪些可变?
- [ ]
[x*2 for x in range(10) if x > 5]输出什么? - [ ]
d.get("k", 0)和d["k"]的区别? - [ ] 函数默认参数为什么不能写
def f(items=[])? - [ ]
if __name__ == "__main__":的作用? - [ ] 怎么判断一个变量是 None?用
==还是is? - [ ]
nums.sort()和sorted(nums)的区别? - [ ] Windows 下 open 文件必须带什么参数?
14. 小练习
练习 1(基础):写函数 fizzbuzz(n),打印 1~n:3 的倍数输出 "Fizz",5 的倍数输出 "Buzz",两者都是输出 "FizzBuzz",否则输出数字。
练习 2(数据结构):给定 words = ["apple", "banana", "avocado", "cherry", "blueberry"],用一行推导式筛出 a 开头且长度 > 5 的单词,再按长度倒序排序。
练习 3(dict 应用):统计一段英文里每个单词出现的次数(忽略大小写),输出出现最多的前 3 个单词。提示:str.split()、dict 计数、sorted(d.items(), key=lambda kv: kv[1], reverse=True)。
练习 4(综合):读取一个 JSON 文件(自己造一个用户列表),找出 age > 18 的用户,把他们的 name 写入新的 JSON 文件。
⬅️ 返回目录 | ➡️ 下一章:02-Python进阶