skip to content
Logo Lostman_Wang的小站

Python函数-函数基础

一、函数基础

1、函数简介

  • 函数是具有某种特定功能的代码块,可以重复使用

2、函数定义

def 函数名(参数1, 参数2=默认值, *args, **kwargs):
"""可选文档字符串"""
函数体
return 返回值

二、函数参数概述

1、5 种参数类型速查

类型关键字语法示例调用示例说明
位置参数(positional-only)def f(a, b, /):f(1, 2)必须按位置,禁止关键字
位置或关键字def f(a, b):f(1, 2)f(a=1, b=2)默认形态
关键字参数(keyword-only)*,def f(*, k):f(k=3)必须显式 k=...
默认参数=def f(a, b=0):f(1)缺省值
可变位置*argsdef f(*args):f(1, 2, 3)多余位置收集成元组
可变关键字**kwargsdef f(**kwargs):f(a=1, b=2)多余关键字收集成字典

2、4 阶顺序规则(PEP 570/PEP 3102)

def f(pos_only, /, pos_or_kwd, *, kwd_only, **extra):
... ↑ ↑ ↑
位置限定 默认区 关键字限定
  • / 左侧:仅限位置
  • * 左侧:位置或关键字
  • * 右侧:仅限关键字
  • **kwargs 最后收集剩余关键字

三、函数参数类型

1、位置参数

1.1、简介
  • 位置参数是最常见的函数形参类型,它要求调用者 按形参在定义中的顺序 依次传入实参。
  • 在 没有 /* 限定符 时,位置参数也允许 关键字传参;一旦加了 /,则强制“仅限位置”
1.2、语法规则
def 函数名(位置参数1, 位置参数2, ...):
函数体
  • 根据函数定义的参数位置来传递参数,要求传递的参数与函数定义的参数两者一一对应
  • 如果 “传递的参数个数” 不等于 “函数定义的参数个数”,运行时会报错
# 错误栗子
def add(a, b):
return a + b
sum = add(1, 2, 3)
# 输出结果
sum = add(1, 2, 3)
E TypeError: add() takes 2 positional arguments but 3 were given

2、关键字参数

2.1、简介
  • 关键字参数允许调用者 以“键=值”形式 传参,不再受形参顺序限制,提高可读性、容错性和可扩展性。可与位置参数混用,但需遵循 位置在前、关键字在后 的顺序。
2.2、语法规则
定义端:
  • 默认形态:形参无特殊符号 → 支持位置或关键字
  • 强制关键字:在形参列表中插入 *,*, kw → 其后形参 必须 用关键字传值
调用端:func(key=value) 或 func(pos, key=value)
顺序约束:位置实参 → *args → 关键字实参 → **kwargs
# 普通关键字(位置或关键字)
def power(base, exp=2):
return base ** exp
# 合法调用
power(2, 3) # 位置
power(base=2, exp=3) # 关键字
power(exp=3, base=2) # 关键字顺序无关
# 强制关键字(keyword-only)
def connect(host, port, *, ssl=True, timeout=30):
return f"{host}:{port} ssl={ssl} timeout={timeout}"
# 正确
connect("api.io", 443, ssl=False, timeout=10)
# 错误
connect("api.io", 443, False) # TypeError: missing keyword
# 混用可变参数
def log(msg, *tags, level="INFO", **extra):
print(msg, tags, level, extra)
log("error", "tag1", "tag2", level="ERROR", user="bob")
# 输出: error ('tag1', 'tag2') ERROR {'user': 'bob'}

3、默认参数

3.1、简介
  • 默认参数允许在 函数定义 时为形参指定一个 缺省值,调用者可选择省略该参数,从而简化调用并增强向后兼容性。
3.2、语法规则
def func(形参1, 形参2=默认值, 形参3=默认值2):
...
  • 默认值可以是任意 不可变或可变的 Python 对象。
  • 默认值只在函数定义时求值一次,并在后续所有调用中共享(见常见陷阱)。
  • 默认参数 必须排在非默认参数之后。
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Alice")) # Hello, Alice!
print(greet("Bob", "Hi")) # Hi, Bob!
3.3、调用规则
调用方式结果
省略默认参数使用默认值
显式传值覆盖默认值
3.4、默认参数陷阱 —— 可变对象共享
def append(item, lst=[]):
lst.append(item)
return lst
print(append(1)) # [1]
print(append(2)) # [1, 2] ← 共享同一列表
# 修复:None + 新建
def append(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst

4、可变位置

4.1、简介
  • 可变位置参数允许函数接收 任意数量的“多余”位置实参,并将它们打包成一个 元组。常用于需要“不定数量输入”的场景,如求和、日志格式化、装饰器封装等。
4.2、语法规则
def func(pos1, pos2, *args, kw_only="default"):
...
  • 定义端:在形参名前加 单个星号 *,习惯命名为 *args(args 不是关键字,可改)。
  • 位置约束:*args 必须位于 普通位置参数之后、默认参数之前(若有默认参数需放在 *args 之后,见 PEP 3102)。
  • 调用端:多余的 位置实参 被 依次收集到元组。
4.3、常见错误
  • 位置实参在前*args 之后不能再出现 普通位置参数(会触发语法错误)。
  • 默认参数位置:若需要默认参数,应放在 *args 之后,并用 仅限关键字 或 **kwargs 接收。
# 基础用法:求任意个数之和
def add(*nums):
return sum(nums)
print(add(1, 2)) # 3
print(add(1, 2, 3, 4)) # 10
# 与位置参数混用
def log(level, *messages):
print(f"[{level}]", messages)
log("INFO", "start", "process", "done")
# 输出: [INFO] start process done
# 与关键字参数(**/ 或 *)组合
def show(title, *items, sep=" "):
print(title + sep.join(items))
show("Tags", "A", "B", sep=" | ")
# 输出: Tags A | B

5、可变关键字

5.1、简介
  • 可变关键字参数允许函数接收 任意数量的“多余”关键字实参,并将它们打包成一个 字典(key 为字符串)。常用于 动态配置、装饰器、插件系统、日志封装 等需要“不定名参数”的场景。
5.2、语法规则
def func(pos1, pos2, *, kw_only="default", **kwargs):
...
  • 定义端:在形参名前加 两个星号 **,习惯命名为 **kwargs(kwargs 不是关键字,可改)。
  • 位置约束:**kwargs 必须位于 所有其他形参之后。
  • 调用端:多余的 关键字实参 被 收集成 dict。
5.3、常见错误
  • ****kwargs 不在末尾**:语法错误。
  • 键冲突:实参名与显式形参同名 → TypeError: 重复关键字参数。
# 基础用法:动态配置
def connect(host, **options):
cfg = {"host": host, options}
return cfg
print(connect("api.io", ssl=True, timeout=30))
# {'host': 'api.io', 'ssl': True, 'timeout': 30}
# 与位置/关键字参数混用
def log(msg, level="INFO", **tags):
print(f"[{level}] {msg}", tags)
log("start", level="DEBUG", user="alice", code=200)
# [DEBUG] start {'user': 'alice', 'code': 200}
# 装饰器场景
def timer(func):
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
print("耗时", time.perf_counter() - start)
return result
return wrapper
@timer
def slow(n=1):
time.sleep(n)
slow(n=2)

四、函数返回值

1、语法规则

def 函数名(参数列表):
语句块
[return 表达式列表] # 可选
  • return 一旦执行,函数 立即终止,后续代码不再执行。
  • 没有 return 或 return 后面无表达式 → 隐式返回 None。

2、返回值的 6 种形态

形态示例调用者接收
单一值return 4242
多个值(打包元组)return a, b(a, b)
列表/字典/对象return [1, 2][1, 2]
生成器yield x生成器对象
None(空函数)returnNone
提前 returnif cond: return提前终止

3、None 的两种语义

  • 无意义函数:如纯副作用 print()。
  • 占位/默认:如未找到结果返回 None,调用者可 if result is None: 判断。

4、多值返回(元组打包)

def divmod(a, b):
return a // b, a % b
q, r = divmod(7, 3) # 元组自动解包
print(q, r) # 2 1

5、提前 return 与守卫语句

def sqrt(x):
if x < 0:
return None # 提前退出
return x ** 0.5

6、类型注解(PEP 484)

from typing import List, Optional, Tuple
def parse(data: str) -> Optional[Tuple[int, str]]:
if not data:
return None
return len(data), data.upper()

7、底层实现(CPython 简述)

调用时栈帧压入实参 → 执行字节码 → 遇到 RETURN_VALUE 指令:

  • 计算表达式结果 → 栈顶
  • 弹出当前帧 → 返回值压入调用者栈顶

因此 返回对象引用,不额外拷贝大对象。