Python学习:函数的使用
函数是 Python 编程的核心构建块,掌握函数的参数类型和嵌套用法,能让代码更简洁、灵活且可复用。本文将系统讲解 Python 函数的五大核心知识点 —— 必备参数、缺省参数、可变参数、关键字参数以及函数嵌套
一、函数参数基础:为什么参数很重要?
函数的参数是实现 “输入 - 处理 - 输出” 逻辑的关键,它让函数摆脱固定值的束缚,能够根据不同输入产生不同结果。例如计算圆面积的函数,通过参数radius接收半径值,实现对任意圆的面积计算:
def circle_area(radius):return 3.14 * radius **2
print(circle_area(5)) # 输出:78.5
print(circle_area(10)) # 输出:314.0
二、必备参数:函数调用的 “硬性要求”
必备参数(Positional Arguments) 是指必须按顺序传递、且数量与函数定义完全匹配的参数,缺一不可。这是最基础也最常用的参数类型。
特点:
必须在函数调用时显式传递
顺序必须与函数定义一致
数量必须与函数定义的参数数量相同
#必备参数 (位置参数) 传递和接收参数的顺序,个数要一致
def function_name(name,age,gender):print("Hello " + name + ", you are " + str(age) + " years old" + ", your gender is " + gender)
function_name("zhangsan",25,"male")结果:
Hello zhangsan, you are 25 years old, your gender is male
三、缺省参数:带默认值的 “弹性选项”
缺省参数(Default Arguments) 是指在函数定义时指定默认值的参数,调用时可传可不传 —— 若不传,则使用默认值;若传,则覆盖默认值。
特点:
定义时用参数名=默认值格式声明
必须放在必备参数之后(否则语法报错)
默认值只在函数定义时初始化一次(注意 mutable 对象的坑)
实例 1:基础用法
def course_info(name, teacher="张教授"):print(f"课程:{name},授课教师:{teacher}")
# 不传缺省参数,使用默认值
course_info("Python编程") # 输出:课程:Python编程,授课教师:张教授
# 传递缺省参数,覆盖默认值
course_info("数据结构", "李教授") # 输出:课程:数据结构,授课教师:李教授
实例 2:缺省参数的位置限制
# 错误:缺省参数不能放在必备参数前面
def wrong_func(a=1, b): # 报错:SyntaxError: non-default argument follows default argumentpass
# 正确:缺省参数放在最后
def right_func(b, a=1):print(a + b)
实例 3:默认值为 mutable 对象的陷阱
def add_item(item, lst=[]): # 危险:默认值是可变列表lst.append(item)return lstprint(add_item(1)) # 输出:[1]
print(add_item(2)) # 输出:[1, 2](预期是[2],因默认列表被复用)# 正确写法:默认值设为None,在函数内初始化
def add_item_fixed(item, lst=None):if lst is None:lst = []lst.append(item)return lstprint(add_item_fixed(1)) # 输出:[1]
print(add_item_fixed(2)) # 输出:[2](符合预期)
四、可变参数:应对不确定数量的输入
当函数需要接收不确定数量的参数时,可变参数(Variable Arguments)就能派上用场。Python 支持两种可变参数:*args和**kwargs。
4.1 *args:接收任意数量的位置参数
*args 用于收集未命名的位置参数,将其打包成一个元组(tuple)。
特点:
定义时用*args表示(args 是约定俗成的名称,可改为其他名字,如*params)
接收所有未匹配的位置参数,类型为元组
必须放在必备参数和缺省参数之后
def sum_numbers(*args):print(f"接收的参数:{args}(类型:{type(args)})")return sum(args)print(sum_numbers(1, 2, 3)) # 输出:接收的参数:(1, 2, 3)(类型:<class 'tuple'>);6
print(sum_numbers(10, 20, 30, 40)) # 输出:100
print(sum_numbers()) # 输出:0(空元组sum为0)
结合必备参数使用:
def print_info(title, *args):print(f"标题:{title}")print(f"内容:{args}")
print_info("兴趣爱好", "读书", "跑步", "编程")
# 输出:
# 标题:兴趣爱好
# 内容:('读书', '跑步', '编程')
4.2 **kwargs:接收任意数量的关键字参数
**kwargs 用于收集命名的关键字参数,将其打包成一个字典(dict)。
特点:
定义时用**kwargs表示(kwargs 是约定俗成的名称,可改为** params)
接收所有未匹配的关键字参数,类型为字典(key 是参数名,value 是参数值)
必须放在参数列表的最后(所有参数之后)
def user_profile(**kwargs):print(f"接收的参数:{kwargs}(类型:{type(kwargs)})")for key, value in kwargs.items():print(f"{key}:{value}")user_profile(name="张三", age=20, city="北京")
# 输出:
# 接收的参数:{'name': '张三', 'age': 20, 'city': '北京'}(类型:<class 'dict'>)
# name:张三
# age:20
# city:北京
结合其他参数使用:
def order(goods, *args, **kwargs):print(f"商品:{goods}")print(f"附加服务:{args}")print(f"订单信息:{kwargs}")order("手机", "贴膜", "碎屏险", price=5999, pay_method="支付宝")
# 输出:
# 商品:手机
# 附加服务:('贴膜', '碎屏险')
# 订单信息:{'price': 5999, 'pay_method': '支付宝'}
4.3 参数解包:传递列表 / 字典给可变参数
当已有列表或字典,想将其元素作为可变参数传递时,可使用解包语法:
列表 / 元组前加*,解包为位置参数
字典前加**,解包为关键字参数
# 解包列表给*args
nums = [1, 2, 3, 4]
print(sum_numbers(*nums)) # 等价于sum_numbers(1, 2, 3, 4),输出:10# 解包字典给**kwargs
user_info = {"name": "李四", "age": 22, "city": "上海"}
user_profile(** user_info) # 等价于user_profile(name="李四", age=22, city="上海")
五、关键字参数:强制按名称传递的参数
关键字参数(Keyword-Only Arguments) 是指必须通过参数名传递的参数,不能按位置传递。定义时在参数前加*(或*args),*之后的参数即为关键字参数。
特点:
必须显式通过参数名传递(如func(key=value))
放在*args之后、**kwargs之前(如果存在)
避免因参数顺序导致的调用错误
# 用*分隔,*之后的参数必须为关键字参数
def calc(a, b, *, operator):if operator == "+":return a + belif operator == "-":return a - belse:return "未知操作符"# 正确调用:operator必须按关键字传递
print(calc(10, 5, operator="+")) # 输出:15# 错误调用:operator按位置传递
print(calc(10, 5, "+")) # 报错:TypeError: calc() takes 2 positional arguments but 3 were given
结合*args使用:
def print_details(*args, prefix, suffix):print(f"前缀:{prefix}")print(f"内容:{args}")print(f"后缀:{suffix}")print_details("a", "b", "c", prefix="start", suffix="end")
# 输出:
# 前缀:start
# 内容:('a', 'b', 'c')
# 后缀:end
六、函数嵌套:函数内部的 “函数工厂”
Python 允许在函数内部定义另一个函数,称为函数嵌套(Nested Functions)。内部函数可以访问外部函数的变量,形成闭包(Closure),增强代码封装性和灵活性。
6.1 基础用法:内部函数的定义与调用
def outer_func():print("这是外部函数")# 内部函数def inner_func():print("这是内部函数")# 外部函数中调用内部函数inner_func()outer_func()
# 输出:
# 这是外部函数
# 这是内部函数# 错误:内部函数不能在外部函数外直接调用
inner_func() # 报错:NameError: name 'inner_func' is not defined
6.2 闭包:内部函数访问外部变量
内部函数可以访问外部函数的局部变量,若内部函数引用了外部函数的变量且外部函数返回内部函数,则形成闭包。
def make_greeter(prefix):# 外部函数变量message = f"{prefix},欢迎!"# 内部函数引用外部变量messagedef greeter(name):return f"{message} 我是{name}"# 返回内部函数(不执行)return greeter# 创建两个不同的greeter函数
morning_greeter = make_greeter("早上好")
evening_greeter = make_greeter("晚上好")print(morning_greeter("张三")) # 输出:早上好,欢迎! 我是张三
print(evening_greeter("李四")) # 输出:晚上好,欢迎! 我是李四
闭包的价值在于保存外部函数的状态,如上面的prefix变量在make_greeter调用后仍被内部函数greeter引用。
6.3 嵌套函数的应用场景
1.** 代码封装 :将辅助逻辑放在内部函数,避免外部命名污染。
2. 闭包与装饰器 :装饰器(Decorator)的实现依赖函数嵌套(后续文章详解)。
3. 动态生成函数 **:根据外部参数动态定义内部函数的行为(如上面的make_greeter)。
七、参数定义的顺序总结
Python 函数参数的定义顺序必须严格遵守,否则会报语法错误,正确顺序为:
必备参数(positional arguments)
缺省参数(default arguments)
可变位置参数(*args)
关键字参数(keyword-only arguments)
可变关键字参数(**kwargs)
def func(a, b=10, *args, c, d=20, **kwargs):print(f"必备参数:a={a}, b={b}")print(f"可变位置参数:args={args}")print(f"关键字参数:c={c}, d={d}")print(f"可变关键字参数:kwargs={kwargs}")func(1, 2, 3, 4, c=5, e=6, f=7)
# 输出:
# 必备参数:a=1, b=2
# 可变位置参数:args=(3, 4)
# 关键字参数:c=5, d=20
# 可变关键字参数:kwargs={'e': 6, 'f': 7}
八、实战案例:综合运用多种参数类型
下面通过一个 “学生成绩管理” 函数,综合展示各种参数的用法:
def manage_scores(name, *scores, exam_type="期中", pass_line=60, **kwargs):"""管理学生成绩的函数:param name: 学生姓名(必备参数):param scores: 多门成绩(可变位置参数):param exam_type: 考试类型(缺省参数):param pass_line: 及格线(关键字参数,强制按名称传递):param kwargs: 额外信息(可变关键字参数):return: 成绩总结"""total = sum(scores)avg = total / len(scores) if scores else 0passed = [s for s in scores if s >= pass_line]summary = (f"学生:{name}\n"f"考试类型:{exam_type}\n"f"成绩列表:{scores}\n"f"总分:{total},平均分:{avg:.1f}\n"f"及格科目:{len(passed)}/{len(scores)}\n"f"额外信息:{kwargs}")return summary# 调用函数
result = manage_scores("张三", 85, 90, 75, 60, # name和scores(位置参数)exam_type="期末", # 缺省参数pass_line=60, # 关键字参数teacher="王老师", comment="进步明显" # 可变关键字参数
)
print(result)
结果:
学生:张三
考试类型:期末
成绩列表:(85, 90, 75, 60)
总分:310,平均分:77.5
及格科目:4/4
额外信息:{'teacher': '王老师', 'comment': '进步明显'}
九、总结
参数类型 | 定义方式 | 作用 | 位置要求 |
必备参数 | a,b | 必须传递的基础参数 | 最前面 |
缺省参数 | a=1,b=2 | 带默认值,可省略传递 | 必备参数之后 |
可变参数 | *args | 接收任意数量位置参数(元组) | 缺省参数之后 |
关键字参数 | *, c, d=3 | 强制按名称传递 | 可变参数之后 |
可变关键字参数 | **kwargs | 接收任意数量关键字参数(字典) | 最后面 |