AI 学院 · Python 入门线 · 节点 ③ / ⑨

函数与模块

手把手教程:把代码封装成可复用的积木,学会 import 站在巨人肩上。约 5-7 个番茄,学完把前两节点的程序重构为函数版才算过。

状态 进行中 前置 ② 数据结构与字符串 下一步 ④ 文件与异常

第 0 步 · 为什么需要函数

你已经在用函数了——print()input()len()sorted()。函数 = 起名的代码块,三个好处:

第 1 步 · 定义与调用(def)

def greet(name):          # def 函数名(参数):
    """打招呼"""           # 文档字符串:说明这个函数干嘛
    return f"你好,{name}!"   # return 把结果交出去

msg = greet("丢丢")      # 调用:传参 → 拿返回值
print(msg)                 # 你好,丢丢!
return vs print 的千古之惑print 是"显示给你看";return 是"把值交给调用方继续用"。函数里 return 之后的行不执行。没有 return 的函数返回 None
心智模型:函数像一台机器——参数进、结果出。机器内部(缩进块)外面看不见。这层"封装"是后面面向对象、写大型程序的第一块砖。

第 2 步 · 参数的花样

2.1 默认参数(不传就用默认值)

def greet(name, greeting="你好"):
    return f"{greeting},{name}!"

greet("丢丢")             # 你好,丢丢!
greet("丢丢", "早上好")  # 早上好,丢丢!

2.2 关键字参数(按名字传,顺序无所谓)

def make_profile(name, age, city="南京"):
    return f"{name}, {age}岁, 来自{city}"

make_profile(age=6, name="丢丢")   # 关键字参数,顺序可乱

2.3 *args 与 **kwargs(可变数量参数,先混个脸熟)

def total(*nums):          # * 收集所有位置参数为元组
    return sum(nums)

total(1, 2, 3, 4)     # 10
看到 print("a", "b", "c", sep="-") 里能传任意多个参数吗?print 内部就是 *args + 关键字参数。现在不用深挖,认识即可。

第 3 步 · 作用域(谁看得见谁)

name = "全局"              # 全局变量:所有函数都能读

def change():
    name = "局部"          # 函数内赋值 → 创建了一个新的局部变量
    print(name)           # 局部(函数内)

change()
print(name)                 # 全局(外面还是"全局"!函数里的 name 是另一个)
新手第一大坑:函数内赋值不改变全局变量。想让函数改全局要用 global——但最好别用。正确做法:函数用参数进、return 出,数据靠传递不靠共享。

第 4 步 · lambda(一行小函数)

square = lambda x: x * x        # 等价于 def square(x): return x*x
square(5)                        # 25

pairs = [("数学", 92), ("英语", 88)]
sorted(pairs, key=lambda p: p[1])  # 按分数排序(②的词频统计用过)
lambda 最常见的舞台就是 sorted()key=:告诉排序器"按什么排"。一行逻辑用 lambda,逻辑复杂就写 def。

第 5 步 · 模块(import 站在巨人肩上)

5.1 三种导入方式

import math              # 方式 1:import 模块,用 math.sqrt()
from math import sqrt      # 方式 2:只导入 sqrt,直接用 sqrt()
import random as rnd      # 方式 3:起别名,用 rnd.randint()

5.2 必会的标准库(Python 自带,无需安装)

import random
random.randint(1, 100)   # 随机整数(①的猜数字用过)
random.choice(["数学", "英语"])  # 随机选一个

import math
math.sqrt(16)          # 4.0 平方根
math.floor(3.7)       # 3 向下取整

from datetime import datetime
now = datetime.now()      # 当前时间
now.strftime("%Y-%m-%d")  # '2026-08-12' 格式化
后面节点会逐个学:json(④)、os/pathlib(⑥)、csv(⑦)、requests(⑧)。标准库 = 你的军火库,import 就是上膛。

第 6 步 · 实战项目:把前两节点重构为函数库

需求:把②的词频统计器改造成一个可复用的函数库 text_tools.py,并加一个"用时记录"函数。

Step 1:写函数库(每个功能一个函数)

# text_tools.py
import time

def clean_text(text):
    """去标点、统一小写、拆词"""
    for ch in ".,!?;:\"'()":
        text = text.replace(ch, " ")
    return text.lower().split()

def count_words(words):
    """词频统计,返回 {词: 次数}"""
    count = {}
    for w in words:
        count[w] = count.get(w, 0) + 1
    return count

def top_words(count, n=5):
    """按次数降序取前 n 个 [(词, 次数)]"""
    return sorted(count.items(), key=lambda x: x[1], reverse=True)[:n]

Step 2:写主程序调用它

# main.py(和 text_tools.py 放同一目录)
import text_tools

text = input("粘贴英文文本:")
words = text_tools.clean_text(text)
top = text_tools.top_words(text_tools.count_words(words))
for w, n in top:
    print(f"{w}: {n} 次")
这就是"模块化":逻辑拆成独立函数,主程序读起来像讲故事。以后任何脚本都能 import text_tools 复用——你的第一份"自己的库"诞生了。

第 7 步 · 报错手册(本节点新增)

1. NameError: name 'clean_text' is not defined —— 忘了 import,或函数名拼错。修法:检查 import text_tools 是否在文件顶部、调用是否带 text_tools. 前缀。
2. TypeError: greet() missing 1 required positional argument —— 调用少传了参数。修法:数一数 def 行有几个参数。
3. UnboundLocalError —— 函数里用了和全局同名的变量又赋值。修法:改名,或把数据作为参数传入。
4. ModuleNotFoundError —— import 的模块不存在(拼错,或第三方库没装)。修法:检查拼写;第三方库 pip install 库名

节点自测清单

全勾 → 节点 ③ 完成,进入节点 ④(文件与异常)。未勾 → 回看对应步骤。

推荐资料