3.2 函数定义与调用
目标
- 读懂
def、return、文档字符串;知道没有return时返回None。 - 区分位置参数与关键字参数,理解默认参数值。
- 避开“可变默认值”陷阱。
- 理解函数是对象:可以赋值、存入字典、作为参数传递。
核心概念
定义与返回
Python · 可运行
python
def get_weather(city):
"""返回城市天气(演示用固定结果)。"""
return f"{city}:晴,22°C"
def log(msg):
print("[log]", msg) # 没有 return → 返回 None
print(get_weather("上海"))
print(log("hi"))return a, b 返回的是一个元组,调用方常直接解包:
Python · 可运行
python
def min_max(nums):
return min(nums), max(nums)
lo, hi = min_max([3, 1, 4])
print(lo, hi)位置参数与关键字参数
调用时可以按位置传参,也可以写 参数名=值(关键字参数)。关键字参数必须放在位置参数之后,顺序随意。
Python · 可运行
python
def create_message(model, max_tokens, temperature=1.0):
return f"model={model}, max_tokens={max_tokens}, temperature={temperature}"
print(create_message("deepseek-flash", 1024)) # 全部按位置
print(create_message(max_tokens=1024, model="deepseek-flash")) # 全部按关键字,顺序无关
print(create_message("deepseek-flash", max_tokens=512, temperature=0)) # 混合真实项目(尤其 SDK)几乎总用关键字参数调用:可读性好,参数增减时不易出错。
默认参数值
带默认值的参数可以不传。默认值在函数定义时求值一次,之后每次调用共享同一个对象。
Python · 可运行
python
def append_to(item, bucket=[]): # 错误示范:可变默认值
bucket.append(item)
return bucket
print(append_to(1))
print(append_to(2)) # [1, 2]:上次的列表还在!
def append_to_fixed(item, bucket=None): # 正确写法
if bucket is None:
bucket = []
bucket.append(item)
return bucket
print(append_to_fixed(1), append_to_fixed(2))函数是对象
def 创建一个函数对象并绑定到函数名。不带括号的函数名就是这个对象本身;带括号才是调用。
Python · 可运行
python
def get_weather(city):
return f"{city}:晴,22°C"
def get_time(city):
return f"{city}:10:00"
f = get_weather # 赋值给另一个名字
print(f("北京"))
print(get_weather.__name__, callable(get_weather))
TOOL_FUNCTIONS = {"get_weather": get_weather, "get_time": get_time} # 存进字典
name = "get_time"
print(TOOL_FUNCTIONS[name]("上海")) # 先取出函数,再调用
def apply(func, value): # 作为参数传入(高阶函数)
return func(value)
print(apply(len, "hello"), apply(str.upper, "hello"))易错点
- 漏写括号:
print(get_weather)打印的是函数对象<function get_weather at 0x…>,不是结果。 - 漏写
return:函数默认返回None,后续使用时出现TypeError: 'NoneType' object …。 - 可变默认值:
def f(x, cache=[])/def f(x, opts={})会在多次调用间共享状态;用None作默认值。 - 参数个数或名字不对:抛
TypeError,错误信息会指出缺少或多余的参数。
Python · 可运行演示报错
python
def create_message(model, max_tokens):
return model, max_tokens
create_message(model="deepseek-flash", max_token=1024) # 参数名拼错对照
| 概念 | Python | JS | Java |
|---|---|---|---|
| 定义 | def f(a, b=1): | function f(a, b = 1) {} | 方法 + 重载模拟默认值 |
| 关键字参数 | f(b=2, a=1) | 无(用对象参数 f({a, b}) 模拟) | 无 |
| 默认值求值时机 | 定义时一次 | 每次调用时 | — |
| 多返回值 | return a, b(元组) | 返回数组/对象再解构 | 返回对象/record |
| 函数是一等对象 | 是 | 是 | 方法引用 Foo::bar / lambda |
读代码
python
def get_weather(city):
"""工具的真实实现:这里用固定结果代替真实天气接口。"""
return f"{city}:晴,22°C"
TOOL_FUNCTIONS = {"get_weather": get_weather}TOOL_FUNCTIONS的值是函数对象(没有括号)。如果写成{"get_weather": get_weather()},会在定义字典时就调用函数,而且因为缺少参数直接报错。- 这种“名字 → 函数”的字典叫分发表(dispatch table),用来代替一长串
if name == ...: elif ...。 - SDK 调用全部用关键字参数:
client.messages.create(model=model, max_tokens=1024, tools=tools, messages=messages)。
练习
练习 1:分发表
补全 TOOLS 字典与 dispatch(name, arg):dispatch("upper", "abc") 返回 "ABC",dispatch("reverse", "abc") 返回 "cba";名字不存在时返回 None。
练习
def upper(s):
return s.upper()
def reverse(s):
return s[::-1]
TOOLS = {}
def dispatch(name, arg):
...
快捷键:⌘/Ctrl + Enter 提交检查
练习 2:修复可变默认值
add_message 有可变默认值缺陷,修复它,使每次不传 history 时都从空列表开始。
练习
def add_message(content, history=[]):
history.append({"role": "user", "content": content})
return history
快捷键:⌘/Ctrl + Enter 提交检查
小结
def定义函数,没有return返回None;return a, b返回元组。- 关键字参数让调用自解释,SDK 代码大量使用。
- 默认值只在定义时求值一次,可变默认值用
None代替。 - 函数是对象:可存进字典做分发表,
f是对象,f()是调用。