本篇是《Python 从入门到初级》第 8 / 20 篇。示例使用 Python 3.12 兼容语法,完整目录结构与数据见配套源码包。
同样的价格计算出现在多个地方时,复制代码会让规则越来越难同步。函数把一段有明确职责的逻辑封装起来,通过参数接收输入,通过返回值交出结果。

1. 函数由输入、处理和返回值组成
def greet(name):
return f"你好,{name}"
message = greet("小林")
print(message)
def 定义函数,定义时不会立即执行函数体。greet("小林") 才是调用。name 是参数名,传进来的具体文字是参数值。
把函数看成一个可复用的小步骤:别人无需知道内部每一行,只需知道输入约定和结果形式。
2. 完整示例:商品小计、运费与总价
保存为 lesson08.py:
def calculate_total(unit_price_cents, quantity, shipping_cents=0):
if unit_price_cents < 0 or quantity <= 0 or shipping_cents < 0:
raise ValueError("价格、数量或运费不符合规则")
subtotal = unit_price_cents * quantity
return {
"subtotal_cents": subtotal,
"shipping_cents": shipping_cents,
"total_cents": subtotal + shipping_cents,
}
def add_tag(tag, tags=None):
if tags is None:
tags = []
tags.append(tag)
return tags
print(calculate_total(5900, 2))
print(calculate_total(5900, 2, shipping_cents=1000))
print(add_tag("python"))
print(add_tag("linux"))
第一笔计算单价 5900 分、数量 2、默认运费 0,合计 11800 分;第二笔指定运费 1000 分,合计 12800 分。
返回字典能让调用方分别读取商品小计和总价。这里假定价格、数量由调用方按约定提供为整数;如果用于接收外部输入,还需要先转换并验证类型。负值和非正数量会触发 ValueError,第 9 篇会继续解释异常。
3. return 和 print 不要混淆
print 用于显示,return 用于把结果交给调用者。一个只打印结果却没有 return 的函数,调用结果通常是 None,后续就无法直接拿来继续计算。
例如报表函数最好返回统计结果,让调用者决定写 JSON、显示终端还是存数据库。这样同一计算逻辑可以被不同入口重复使用。
一旦执行 return,当前函数调用就结束。函数定义和参数机制见 官方函数说明。
4. 默认参数与关键字参数
shipping_cents=0 表示调用时没提供就使用 0。shipping_cents=1000 这样的关键字调用,让读者更容易知道这个数字表示什么。
默认参数放在非默认参数之后。给函数起名时,尽量说明它做什么,例如 calculate_total、read_orders,而不是 process1 或 func2。
函数内部的局部变量通常不应靠外面的同名变量来“偷偷提供”。把依赖写进参数,函数就更容易理解和测试。
5. 为什么 tags=None 而不是 tags=[]
可变默认值在函数定义时建立,可能被多次调用共享。把列表直接写成默认参数,容易让前一次调用加入的内容出现在下一次里。
示例使用 None 表示没有传入列表,然后在每次调用内部创建新列表。因此 add_tag("python") 和 add_tag("linux") 分别得到独立的一项列表。
如果调用方明确传入一个列表,该函数会修改传入的列表。这也应当写进函数约定,不能以为所有函数都自动复制参数。
6. 练习:折扣函数
编写 discounted_price(amount_cents, percent),约定金额与百分比都是整数,percent 在 0~100,返回折扣后的整数分金额。先明确小数分如何舍入,再实现计算。
例如按向下取整的教学规则,10000 分打 90% 应得到 9000 分。这里重要的不只是写出乘法,还要让边界、单位和舍入约定一目了然。