Python 核心知识点全景学习博客(含详细代码注释 · AI应用强化版)

这篇博客专为初学者设计,每个知识点都从一个实际问题出发,通过生活化的例子帮你建立感性认识,再深入浅出地讲解核心原理,最后配合带详尽注释的演示用例和输出结果加深理解。
此外,每个知识点末尾都增加了 AI 应用场景提示,帮助你理解这些基础在 AI 开发中究竟用在哪里。


一、初级篇

1. 数据类型

问题
你有一堆信息要处理:年龄、姓名、购物清单、学生成绩表……如何让计算机正确区分并灵活操作它们?

生活化类比
想象你有一个分类储物箱:

  • 整数、浮点数像单个数字标签,写上去就不能擦掉重写,只能换新的标签。
  • 字符串像刻字的木牌,想改只能重新刻一块。
  • 列表像可随意增减物品的购物车,能随时添加、删除或更换商品。
  • 元组像已封箱的快递盒,装好就不能再变动。
  • 字典像根据姓名找人的通讯录,通过“键”快速定位到“值”。
  • 集合像去重后的兴趣标签,每个元素唯一且无序。

原理
Python 中一切数据都是“对象”,每个对象有固定的类型,决定它能做什么。

  • 不可变对象(int、float、str、tuple):一旦创建,内部值不能改变。修改操作其实会生成新对象,类似用新标签替换旧标签。
  • 可变对象(list、dict、set):允许原地增删改内容,就像在同一个购物车里增减物品。
    这种区分让 Python 在内存管理上更清晰,也影响函数传参是“传引用”还是“传值”。

演示用例(带注释)

# ---- 基本不可变类型 ----
age: int = 25                 # 整数:年龄
price: float = 19.99          # 浮点数:价格
name: str = "Alice"           # 字符串:名字
is_student: bool = True       # 布尔值:是否为学生

# 使用 type() 查看每个变量的实际类型
print(type(age), age)         # <class 'int'> 25
print(type(price), price)     # <class 'float'> 19.99
print(type(name), name)       # <class 'str'> Alice
print(type(is_student), is_student)  # <class 'bool'> True

# ---- 可变容器类型 ----
fruits: list = ["apple", "banana", "cherry"]   # 列表:可以修改的序列
point: tuple = (3, 4)                         # 元组:不可修改的序列
user: dict = {"name": "Bob", "age": 30}       # 字典:键值对集合
tags: set = {"python", "learning", "blog"}    # 集合:无序、不重复的元素

print(fruits[0])          # 列表按索引取值:第一个元素
print(point[1])           # 元组按索引取值:第二个元素
print(user["name"])       # 字典通过键取值
print("python" in tags)   # 集合成员检测:True 表示存在

# ---- 常用进阶操作(AI 开发必备) ----
# 字典的安全取值(避免 KeyError)
config = {"model": "gpt-4", "temperature": 0.7}
# 若字段不存在,使用默认值
top_p = config.get("top_p", 1.0)
print("top_p 取值:", top_p)

# 列表推导式(高效处理批量数据)
scores = [0.2, 0.8, 0.95, 0.4]
# 筛选出高于 0.5 的得分
high_scores = [s for s in scores if s > 0.5]
print("大于 0.5 的分数:", high_scores)

# 切片操作(取前 N 个元素)
top3 = scores[:3]    # 从索引 0 到 2
print("前三个分数:", top3)

输出结果

<class 'int'> 25
<class 'float'> 19.99
<class 'str'> Alice
<class 'bool'> True
apple
4
Bob
True
top_p 取值: 1.0
大于 0.5 的分数: [0.8, 0.95]
前三个分数: [0.2, 0.8, 0.95]

AI 应用场景:解析 API 返回的 JSON 数据时,经常需要从字典里安全地提取字段(例如提取模型的生成结果、置信度)。列表推导式和切片用于批量处理推理结果、选取 Top-K 预测。


2. 控制流

问题
程序不能总是直线执行,有时需要“如果…就…否则…”,有时要重复做一件事直到条件改变。如何让代码学会“思考”?

生活化类比

  • 分支像是出门看天气:如果下雨,带伞;否则,戴帽子。
  • for 循环像按花名册依次点名,点完最后一个自动结束。
  • while 循环像在自动售货机前投币,只要余额不够就一直提醒你投钱,够了才出货。

原理

  • if-elif-else 根据条件表达式(结果为 True/False)选择执行哪段代码。
  • for 循环本质上是在遍历一个“可迭代对象”(如列表、字符串等),每一次取出下一个元素,直到取完。
  • while 循环则反复检查一个条件,只要条件成立就继续执行循环体。
  • break 能立即终止整个循环,continue 则跳过当前这一次迭代,直接进入下一次。

演示用例(带注释)

# ---- 条件分支 ----
score = 85
if score >= 90:
    grade = "A"
elif score >= 75:
    grade = "B"
else:
    grade = "C"
print(f"成绩等级:{grade}")

# ---- for 循环:遍历范围 ----
for i in range(1, 4):      # range(1,4) 产生 1,2,3
    print(f"循环第{i}次")

# ---- while 循环 + break/continue ----
count = 0
while True:                # 无限循环,必须靠 break 退出
    if count >= 3:
        break              # 彻底终止循环
    if count == 1:
        count += 1
        continue           # 跳过本次,不执行后面的打印
    print(f"计数:{count}")
    count += 1

输出结果

成绩等级:B
循环第1次
循环第2次
循环第3次
计数:0
计数:2

AI 应用场景:批量处理数据时,break 用于提前终止不满足条件的批次(如检测到异常样本);continue 用于跳过无效数据。循环结构是处理数据集、遍历模型输出列表的基础。


3. 函数

问题
你有一段经常要用的操作(比如计算运费、生成问候语),每次都重写一遍太麻烦,如何打包复用?

生活化类比
函数就像厨房里的搅拌机:你放进食材(参数),它按设定好的模式运行,最后倒出果汁(返回值)。不同的食材组合可以做出不同的饮品。

原理

  • def 定义一个函数,给它起个名字,指定参数和返回值。
  • 调用函数时,Python 会暂停当前工作,跳转到函数内部执行,完成后再跳回原处,并将 return 后的结果带回来。
  • 参数可以设定默认值,但默认值只在函数定义时求值一次,因此默认值不要用可变对象(如列表、字典),否则多次调用会共享同一个对象,导致难以发现的 bug。
  • 正确做法:将默认值设为 None,在函数体内再创建新的可变对象。

演示用例(带注释)

def greet(name: str, greeting: str = "Hello") -> str:
    """返回问候语,greeting 可自定义"""
    return f"{greeting}, {name}!"

print(greet("Alice"))
print(greet("Bob", greeting="Hi"))

# ---- 危险示例:可变对象作默认参数(绝对不要这样写!) ----
def add_to_list_bad(item, my_list=[]):
    my_list.append(item)
    return my_list

# 两次调用“看起来”应该是独立的,但实际上共享了同一个列表
print(add_to_list_bad(1))  # [1]
print(add_to_list_bad(2))  # [1, 2]   <- 可能不是你想要的结果!

# ---- 正确的写法:用 None 作为占位符 ----
def add_to_list_good(item, my_list=None):
    if my_list is None:
        my_list = []       # 每次调用都创建全新列表
    my_list.append(item)
    return my_list

print(add_to_list_good(1)) # [1]
print(add_to_list_good(2)) # [2]      <- 互不影响

输出结果

Hello, Alice!
Hi, Bob!
[1]
[1, 2]
[1]
[2]

AI 应用场景:调用大模型 API 时,几乎每个函数都包含大量可选参数(如 temperature、top_p、max_tokens),默认参数和关键字参数能让你的调用代码简洁且安全。避免可变默认参数可防止“缓存污染”这类隐蔽错误。


4. 面向对象

问题
你需要用代码模拟现实世界的事物,比如不同种类的动物,它们有共性又各有特性,如何组织?

生活化类比

  • 就是模具,比如“手机模具”;对象就是用模具造出的一部部真实手机
  • 继承就像“智能手机”继承了“手机”的所有基础功能,还新增了触屏和上网。
  • 多态:同样一个“开机”按钮,不同品牌的手机开机画面不同,但操作方式一样。

原理

  • class 定义类,里面包含属性(数据)和方法(操作数据的行为)。
  • __init__ 是构造函数,创建对象时自动运行,用于初始化属性。
  • 子类继承父类后,可以用 super() 调用父类方法,在其基础上进行扩展。
  • 重写方法实现了多态。
  • 特殊方法(魔法方法)如 __str__ 可以定义对象被 print 时的输出,极大方便调试。

演示用例(带注释)

# 基类(父类):动物
class Animal:
    def __init__(self, name: str):
        self.name = name

    def speak(self) -> str:
        return "..."

    def __str__(self) -> str:       # 魔法方法:定义 print 时的显示
        return f"动物:{self.name}"

# 子类 Dog 继承 Animal,并重写 speak 方法
class Dog(Animal):
    def speak(self) -> str:
        return f"{self.name} says Woof!"

    def __str__(self) -> str:
        return f"狗:{self.name}"

# 子类 Cat 同样继承并重写 speak
class Cat(Animal):
    def speak(self) -> str:
        return f"{self.name} says Meow!"

# 子类扩展父类方法(使用 super)
class LoudDog(Dog):
    def speak(self) -> str:
        base_sound = super().speak()   # 先获得父类的叫声
        return base_sound.upper() + "!!!"

# 多态体现:不同对象调用同一个方法名,产生不同行为
animals = [Dog("Buddy"), Cat("Kitty"), LoudDog("Max")]
for a in animals:
    print(a.speak())
    print(a)   # 自动调用 __str__

输出结果

Buddy says Woof!
狗:Buddy
Kitty says Meow!
动物:Kitty
BUDDY SAYS WOOF!!!!
狗:Max

AI 应用场景:封装模型加载器、自定义数据集类、日志记录器等常使用继承 + super()__str__ 让你能直观地打印模型配置、数据样本信息。在复杂系统中,也可以将功能拆分成独立类再组合(例如一个 DataLoader 类包含一个 Tokenizer 对象),比多层继承更灵活。


5. 异常处理

问题
程序运行时可能遇到意外情况:除零、文件找不到、API 返回格式错误……不想让程序直接崩溃,怎么优雅地处理?

生活化类比
像在自动门前进出:

  • try 块是你尝试走进门。
  • 如果门失灵夹到你了(发生异常),except 就是一旁的急救员,立刻处理。
  • 如果顺利通过(无异常),else 会给你一个微笑。
  • 不管发生什么,finally 都会把门关上(清理资源)。

原理

  • 异常是错误信号,Python 遇到问题就会抛出(raise)一个异常对象。
  • 使用多个 except 分支可以分别处理不同类型的异常。
  • 使用 traceback 模块可以打印完整的错误堆栈,方便调试。
  • else 仅在没发生异常时运行;finally 总是运行,常用于释放资源。

演示用例(带注释)

import traceback

def divide(a: float, b: float) -> float | None:
    try:
        result = a / b
    except ZeroDivisionError:
        print("错误:除数不能为零!")
        return None
    except TypeError as e:                 # 捕获类型错误
        print(f"类型错误:{e}")
        traceback.print_exc()              # 打印完整堆栈,方便定位
        return None
    else:
        print("计算成功")
        return result
    finally:
        print("执行完毕")

print(divide(10, 2))
print("---")
print(divide(10, 0))
print("---")
print(divide("10", 2))   # 触发 TypeError

输出结果

计算成功
执行完毕
5.0
---
错误:除数不能为零!
执行完毕
None
---
类型错误:unsupported operand type(s) for /: 'str' and 'int'
Traceback (most recent call last):
  File "demo.py", line 4, in divide
    result = a / b
TypeError: unsupported operand type(s) for /: 'str' and 'int'
执行完毕
None

AI 应用场景:调用外部 API 时可能遇到网络超时、返回格式错误、模型推理失败等异常,需要分别捕获并记录。多分支异常处理和完整的堆栈信息是 7x24 小时服务的调试基础。


6. 文件 I/O

问题
你想让程序保存数据到硬盘,下次还能读出来。如何安全地读写文件,避免忘记关闭?

生活化类比
with open 就像用银行保险柜

  • 你申请打开保险柜(打开文件),在里面存取物品(读写)。
  • 操作完成后,无论你是否弄乱东西(发生异常),银行都会自动关好柜门(关闭文件)。

原理

  • open() 函数返回一个文件对象,相当于获取了操作文件的“手柄”。
  • 使用 with 语句,进入时自动打开文件,离开时自动关闭,即使内部代码出错也会关闭,因为它利用了上下文管理器协议。
  • 文本模式(r/w)会自动处理编码(如 UTF-8),二进制模式(rb/wb)处理原始字节(如图片、模型文件)。
  • jsoncsv 模块提供了更高级的结构化数据读写方式。

演示用例(带注释)

import json
import csv

# ---- 文本文件写入与读取 ----
with open("demo.txt", "w", encoding="utf-8") as f:
    f.write("第一行内容\n")

with open("demo.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line.strip())

# ---- 二进制文件读写(例如保存/加载图像或模型权重) ----
data = bytes([0, 128, 255])   # 模拟一些二进制数据
with open("data.bin", "wb") as f:
    f.write(data)

with open("data.bin", "rb") as f:
    content = f.read()
    print("二进制内容:", list(content))

# ---- JSON 文件:解析大模型 API 响应常用 ----
response_json = '{"model": "gpt-4", "choices": [{"text": "你好"}]}'
parsed = json.loads(response_json)
print("解析 JSON:", parsed["model"])
with open("response.json", "w", encoding="utf-8") as f:
    json.dump(parsed, f, ensure_ascii=False, indent=2)

# ---- CSV 文件:批量处理数据集的常用格式 ----
with open("scores.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "score"])
    writer.writeheader()
    writer.writerow({"name": "model_a", "score": 0.89})
    writer.writerow({"name": "model_b", "score": 0.93})

with open("scores.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(f"{row['name']}: {row['score']}")

输出结果

第一行内容
二进制内容: [0, 128, 255]
解析 JSON: gpt-4
model_a: 0.89
model_b: 0.93

AI 应用场景:模型权重、图片数据用二进制模式读写;API 返回结果用 JSON 解析;训练数据、评测结果常用 CSV 存储。这些是 AI 开发中读写数据的必备技能。


二、中级篇

1. 迭代器与生成器

问题
处理海量数据时,一次性把所有数据加载到内存太浪费,有没有一种“按需生产”的方式?

生活化类比

  • 迭代器像是餐厅服务员,一次只给你上一道菜,吃完才能要下一道,而不是把整桌菜堆满。
  • 生成器智能厨师,只有你喊“上菜”(调用 next)时,他才会现做一道,并记住上次做到哪一步了。

原理

  • 迭代器实现了两个关键动作:__iter__(返回自己)和 __next__(返回下一个元素)。
  • for 循环背后就是反复调用 next() 直到 StopIteration 被抛出。
  • 生成器是用 yield 代替 return 的函数。调用生成器函数不会立即运行代码,而是返回一个生成器对象。每次用 next() 请求时,代码执行到 yield 处暂停并吐出值,状态保留,下次从暂停点继续。
  • 生成器表达式 (x for x in ...) 是生成器的简写形式,比列表推导式更节省内存。

演示用例(带注释)

# ---- 生成器函数:斐波那契数列 ----
def fibonacci(n: int):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

for num in fibonacci(5):
    print(num, end=" ")
print()

# ---- 生成器表达式(懒加载,不立即分配内存) ----
gen_exp = (x * 2 for x in range(1000000))   # 不会立刻产生 100 万个元素
# 只取出前 3 个
for i, val in enumerate(gen_exp):
    if i >= 3:
        break
    print(val, end=" ")
print()

# ---- 自定义迭代器类:倒计时 ----
class CountDown:
    def __init__(self, start: int):
        self.current = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < 0:
            raise StopIteration
        value = self.current
        self.current -= 1
        return value

for n in CountDown(2):
    print(n, end=" ")

输出结果

0 1 1 2 3 
0 2 4 
2 1 0 

AI 应用场景:大语言模型的流式输出(SSE)就是生成器的典型应用,模型一边生成 token 一边把内容“推”给客户端。生成器表达式常用于逐条读取大型数据集而不撑爆内存。


2. 装饰器

问题
你想给某个函数增加计时、日志等功能,但又不想修改函数本身的代码,怎么办?

生活化类比
装饰器就像给礼物包上包装纸:礼物本身(原函数)不变,外面多了一层漂亮的包装(额外功能)。你可以随时包上或拆掉,而不影响礼物。

原理

  • 装饰器本质上是一个接收函数、返回新函数的“函数工厂”。
  • @decorator 相当于执行 原函数 = decorator(原函数)
  • 内部通常定义 wrapper 函数,在原函数调用前后添加操作(如计时),并利用闭包记住原函数。
  • 使用 functools.wraps 可保留原函数的名称等元信息,防止被覆盖。
    装饰器让代码复用更优雅,遵循“开放扩展,封闭修改”原则。

演示用例(带注释)

import time
from functools import wraps

# 装饰器函数,接收被装饰的函数 func
def timer(func):
    @wraps(func)                # 保留 func 的元数据(如函数名)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()     # 开始计时
        result = func(*args, **kwargs)  # 执行原函数
        end = time.perf_counter()       # 结束计时
        print(f"{func.__name__} 耗时:{end - start:.6f} 秒")
        return result
    return wrapper               # 返回包装后的函数

# 使用 @timer 装饰器,相当于 slow_sum = timer(slow_sum)
@timer
def slow_sum(n: int) -> int:
    total = 0
    for i in range(n):
        total += i
    return total

print(slow_sum(100000))          # 调用时自动打印耗时

输出结果(耗时因机器而异)

slow_sum 耗时:0.004512 秒
4999950000

AI 应用场景:装饰器常用于 API 调用计时、自动重试(网络请求失败时)、缓存推理结果(避免重复调用模型)以及权限校验。


3. 上下文管理器

问题
有些资源(文件、数据库连接、锁)用完后必须释放,手动释放容易遗漏,如何自动管理?

生活化类比
上下文管理器就像自动感应水龙头:手伸过去(进入 with)自动出水,手离开(退出 with)自动关水,无需记得关,也不会浪费水。

原理

  • 实现 __enter__(获取资源)和 __exit__(释放资源)的对象称为上下文管理器。
  • with 语句调用 __enter__ 获取资源并赋值给 as 后的变量;即使在 with 块内发生异常,也会调用 __exit__ 进行清理。
  • 也可用 @contextmanager 装饰一个单次 yield 的生成器,yield 前为进入操作,yield 后为退出操作。
    这种方式确保了资源安全性,代码也简洁明了。

演示用例(带注释)

from contextlib import contextmanager

# ---- 基于类的上下文管理器 ----
class ManagedFile:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):
        self.file = open(self.filename, self.mode, encoding="utf-8")
        print("文件已打开")
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()
        print("文件已关闭")

with ManagedFile("test.txt", "w") as f:
    f.write("Hello Context Manager!")

# ---- 基于生成器的上下文管理器 ----
@contextmanager
def managed_list(lst: list):
    print("进入上下文,备份列表")
    backup = lst.copy()
    try:
        yield lst                 # 将列表交给 with 块内的变量
    finally:
        lst.clear()
        lst.extend(backup)
        print("退出上下文,恢复列表")

data = [1, 2, 3]
with managed_list(data) as working:
    working.append(4)
    print("内部修改:", working)
print("外部查看:", data)

输出结果

文件已打开
文件已关闭
进入上下文,备份列表
内部修改: [1, 2, 3, 4]
退出上下文,恢复列表
外部查看: [1, 2, 3]

AI 应用场景:在进行模型推理时临时切换到评估模式(model.eval()),推理完成后恢复到训练模式;数据库事务的自动提交/回滚;分布式训练中获取和释放锁,都是上下文管理器的经典应用。


4. 异步编程(asyncio)

问题
程序要并发处理多个网络请求,但不想使用复杂的多线程,怎样高效地“同时”进行多件事?

生活化类比
你在家煮饭:把米下锅后,不用一直盯着,可以同时切菜;饭好了,回来盛饭,这期间没有雇佣多个厨师,只是利用等待时间做别的事。
异步编程就是一位大厨,利用空闲时间穿插做多道菜。

原理

  • asyncio 基于事件循环,单线程轮询各个任务。
  • async def 定义协程,内部使用 await 挂起(让出控制权),当等待的操作(如网络 I/O、睡眠)完成时,事件循环会恢复执行。
  • 多个协程通过 asyncio.gather 并发调度,看起来是同时进行的,实际上是在等待间隙切换任务。
  • 如果需要在协程中调用同步阻塞代码(例如本地的同步模型推理),可以使用 loop.run_in_executor 将阻塞操作放到线程池中执行,避免卡死事件循环。

演示用例(带注释)

import asyncio
import time

# 定义一个异步协程函数(模拟网络请求)
async def fetch_data(task_id: int, delay: float) -> str:
    print(f"任务 {task_id} 开始,等待 {delay} 秒...")
    await asyncio.sleep(delay)     # 模拟 I/O 等待,释放控制权
    print(f"任务 {task_id} 完成")
    return f"数据来自任务{task_id}"

# 模拟一个同步的阻塞函数(例如本地模型推理)
def sync_inference(model_name: str) -> str:
    time.sleep(1)   # 模拟耗时计算
    return f"{model_name} 推理结果"

async def main():
    # 并发执行异步任务
    tasks = [
        fetch_data(1, 2.0),
        fetch_data(2, 1.0),
        fetch_data(3, 1.5),
    ]
    results = await asyncio.gather(*tasks)
    print("异步任务全部完成,结果:", results)

    # 在协程中安全地调用同步阻塞代码
    loop = asyncio.get_running_loop()
    infer_result = await loop.run_in_executor(None, sync_inference, "resnet")
    print("同步推理结果:", infer_result)

# 启动事件循环
asyncio.run(main())

输出结果

任务 1 开始,等待 2.0 秒...
任务 2 开始,等待 1.0 秒...
任务 3 开始,等待 1.5 秒...
任务 2 完成
任务 3 完成
任务 1 完成
异步任务全部完成,结果: ['数据来自任务1', '数据来自任务2', '数据来自任务3']
同步推理结果: resnet 推理结果

原因解释:任务 2 只等了 1 秒,所以最先完成;任务 3 等了 1.5 秒,第二个完成;任务 1 等了 2 秒,最后完成。并发执行的总耗时约等于最慢任务的时间(2 秒),而不是三个任务时间的总和。

AI 应用场景:同时调用多个模型 API、流式聊天、异步读取批量数据。当调用 scikit-learn 等同步库进行推理时,必须用 run_in_executor 将阻塞操作扔进线程池,否则整个异步服务会卡死。另外,async withasync for 可用于异步数据库客户端和流式 HTTP 响应,在实际工程中也很常见。


5. 类型注解

问题
代码多了以后,常常忘记某个函数参数该传什么类型,返回值又是什么类型,怎么办?

生活化类比
就像给药品包装写明成分和用法用量,虽然你不一定照着做,但看一眼就知道该吃什么、怎么吃。类型注解就是代码的“成分说明”。

原理

  • Python 是动态语言,变量类型在运行时确定。类型注解(如 name: str)只是提示,不会在运行时强制检查
  • 注解信息保存在函数的 __annotations__ 属性里,可以被第三方工具(如 mypy)读取,在运行前进行静态分析,提前发现类型错误。
  • 运行 mypy your_file.py 即可扫描整个文件,提示类型不匹配的地方。
  • typing 模块提供 ListDictOptional 等高级类型,能表达更复杂的结构。对于更精确的 API 响应结构,可以使用 TypedDict 来定义字典的“形状”。

演示用例(带注释)

from typing import List, Dict, Union, Optional

# ---- 基本注解 ----
def add(a: int, b: int) -> int:
    """参数和返回值都标注为 int 类型"""
    return a + b

# ---- 复合类型定义 ----
UserDict = Dict[str, Union[str, int]]   # 自定义类型别名

def get_user(id: int) -> Optional[UserDict]:
    """根据 id 返回用户信息,可能返回 None"""
    if id == 1:
        return {"name": "Alice", "age": 30}
    return None

user = get_user(1)
if user:
    print(user["name"], user["age"])

# ---- 泛型列表 ----
def average(numbers: List[float]) -> float:
    """计算浮点数列表的平均值"""
    return sum(numbers) / len(numbers)

scores: List[float] = [85.5, 90.0, 76.5]
print(f"平均分:{average(scores):.1f}")

输出结果

Alice 30
平均分:84.0

AI 应用场景:类型注解配合 mypy 可以在代码上线前就发现类型不匹配的 bug。对于复杂的 API 返回数据(如 OpenAI 的响应 JSON),使用 TypedDict 可以精确描述每个字段的类型和是否可选,让 IDE 自动补全和检查。


面试模拟题

1. 场景型:你在调用一个模型 API 时,发现返回的 JSON 中 choices[0].message.content 字段有时不存在。如何安全地提取这个字段而不让程序崩溃?

答案要点:使用 dict.get("choices", [{}])[0].get("message", {}).get("content", "") 链式安全取值,配合 try/except 捕获 KeyErrorIndexError,并打印完整 traceback 方便定位是 API 返回异常还是网络问题。


2. 原理型:为什么在函数中写 def load_model(cache={}) 是有风险的?正确的写法是什么?

答案要点:Python 的默认参数只在函数定义时求值一次,可变对象 {} 会被多次调用共享,导致缓存互相污染。正确写法是 def load_model(cache=None): if cache is None: cache = {}


3. 场景型:你有一个 10GB 的日志文件,每行是一个 JSON,需要提取特定字段做分析。如何在不撑爆内存的情况下处理?

答案要点:使用生成器逐行读取,for line in file 每次只读一行到内存,yield json.loads(line) 逐条产出记录。结合 chunksize 分块读取如果是 CSV 格式。


4. 对比型asyncio.gatherloop.run_in_executor 分别在什么 AI 应用场景下使用?

答案要点gather 用于并发调用多个异步 API(如同时请求三个模型),利用等待 I/O 的间隙切换。run_in_executor 用于在协程中调用同步阻塞代码(如 scikit-learn 的 model.predict()),将其放入线程池避免阻塞事件循环。


总结

这篇博客用“问题-类比-原理-演示”的四步法,并针对 AI 应用开发补充了进阶操作和实战提示。从基本的 getbreaksuper()、多重异常,到文件 I/O 的二进制与结构化读写,再到生成器表达式、run_in_executor、mypy 静态检查——你现在不仅掌握了 Python 核心语法,还理解了它们在真实 AI 开发中的位置。亲手运行每一段代码,把这些基础刻进肌肉记忆里,它们会成为你构建更复杂系统的坚实基石。

更多推荐