Maya 把同一个总价公式粘贴到四个地方,其中一份已经算错了。函数给这个公式一个名字、一个家。订单为空时,它应该返回什么?
函数是一段有名字、可以接收输入并返回结果的代码。函数让程序更容易测试、复用和阅读。用 def 定义函数,然后用名字调用它。 你还会把计算和展示分开,并在函数边界做校验。
定义与调用
定义函数只是创建它,不会立即运行。在函数名后加括号调用才会执行函数体。参数是定义中的名字;实参是调用时传入的值。
def greet(name):
return f"你好,{name}!"
print(greet("Maya"))可复用的消息
返回值
return 把值送回调用者,并结束函数。print 只负责显示,不会给调用者一个可用的结果。没有 return 语句的函数会返回 None。
def total(price, quantity):
return price * quantity
result = total(4.5, 2)
print(result)返回计算结果
默认值与关键字参数
调用者省略某个参数时,会使用默认参数。带默认值的参数必须放在没有默认值的参数后面。函数有多个参数时,关键字参数可以让调用更易读。
def total(price, quantity=1):
return price * quantity
print(total(4.5))
print(total(price=4.5, quantity=3))默认值与命名参数
返回值,而不是打印
会打印的函数不好复用;会返回的函数可以组合、测试,再由调用方决定怎么显示。把计算和展示分开,在程序边缘打印,不要在计算中间打印。
def line_total(qty, price):
return round(qty * price, 2)
subtotal = line_total(2, 4.5) + line_total(1, 3.0)
print(f"subtotal: {subtotal:.2f}")返回值可以被组合
在函数边界校验
在参数进入函数时校验,并抛出具体异常和有用信息。调用方可以决定重试、跳过这一行还是停止。悄悄返回 None 会隐藏失败。
def line_total(qty, price):
if qty <= 0:
raise ValueError("qty must be positive")
if price < 0:
raise ValueError("price must be non-negative")
return round(qty * price, 2)
print(line_total(2, 4.5))
try:
line_total(0, 4.5)
except ValueError as error:
print(type(error).__name__, error)一次校验,清楚失败
不要使用可变默认参数
默认参数只在函数定义时求值一次。列表默认值会被所有没有传参的调用共享。正确做法是用 None 作为默认值,在函数内部新建列表。这不是风格偏好,而是防止数据在多次调用之间泄漏。
def add_item(item, basket=None):
if basket is None:
basket = []
basket.append(item)
return basket
print(add_item("latte"))
print(add_item("tea"))每次调用都得到新列表
本课要点
- def 定义函数,括号调用函数。
- return 把值送回调用者,print 只负责显示。
- 默认参数让可选参数更方便。
- 每个函数只专注做一件事。
- 返回值可以组合;print 只是副作用。
- 当真正的默认值是可变对象时,用 None 作为默认参数。
常见错误
- 忘记调用函数,只写了函数定义,所以函数体没有运行。
- 调用者需要返回值时,函数里却只用了 print。
- 把没有默认值的参数放在有默认值的参数后面。
- 调用方需要结果时,函数却只打印不返回。
- 写 def add(item, basket=[]),让所有调用共享同一个列表。
写一个函数,接收价格和数量并返回总价,然后打印结果。
动手试试
改改变量、先预测输出,再运行代码。第一次点击“运行代码”时会下载 Python 运行时,可能需要几秒钟。
练习本课
12 道题,作答后立即看到解释。