函数是Python编程的核心基石,掌握函数的定义、调用及参数使用,能让你的代码从「线性堆砌」升级为「模块化设计」。本文聚焦Python函数的核心知识点——参数类型与默认参数,用实战案例拆解用法,解决新手最易踩的参数传值坑。
一、先搞懂:函数的基本定义与调用
在学参数之前,先掌握函数的基础语法,这是理解参数的前提。
1. 函数定义的核心结构
Python用def关键字定义函数,最基础的格式如下:
def 函数名(参数列表):
"""函数文档字符串(可选,用于说明函数功能)"""
函数体(核心逻辑)
return 返回值(可选,无return则默认返回None)
2. 最简示例:无参数函数
先从最简单的无参数函数入手,理解「定义-调用」的基本流程:
定义一个打印问候语的无参数函数
def print_greeting():
"""打印简单的问候语"""
print("你好,欢迎学习Python函数!")
调用函数(必须调用才会执行函数体)
print_greeting()
输出:你好,欢迎学习Python函数!
二、核心重点:函数的参数类型
参数是函数的「输入接口」,不同参数类型适配不同的传值场景,新手需重点掌握以下4类常用参数。
1. 位置参数(必选参数)
最基础的参数类型,调用时必须按「定义顺序」传值,数量不能多也不能少,是Python函数的默认参数类型。
用法示例:
定义计算两数之和的函数,a和b是位置参数
def add_numbers(a, b):
"""计算两个数的和"""
result = a + b
return result
调用:按位置传值(a=3,b=5)
total = add_numbers(3, 5)
print(total) 输出:8
错误示例:少传参数(必选参数缺失)
add_numbers(3) 报错:TypeError: add_numbers() missing 1 required positional argument: 'b'
新手避坑:
- 位置参数的传值顺序必须和定义顺序一致,比如
add_numbers(5, 3)会让a=5、b=3; - 调用时参数数量必须与定义完全匹配,多传或少传都会报错。
2. 关键字参数
调用函数时,通过「参数名=值」的形式传值,无需严格按位置顺序,适合参数较多的场景,能避免传值顺序混乱。
用法示例:
定义包含多个参数的函数
def print_user_info(name, age, city):
"""打印用户信息"""
print(f"姓名:{name},年龄:{age},城市:{city}")
方式1:纯关键字参数(顺序可随意)
print_user_info(age=28, name="张三", city="北京")
输出:姓名:张三,年龄:28,城市:北京
方式2:位置参数+关键字参数(关键字参数必须在位置参数后)
print_user_info("李四", city="上海", age=30)
输出:姓名:李四,年龄:30,城市:上海
错误示例:关键字参数在前
print_user_info(city="广州", "王五", 25) 报错:SyntaxError
3. 默认参数(重点)
给参数设置「默认值」,调用时可省略该参数(使用默认值),也可主动传值覆盖默认值,适合「大部分场景用固定值,少数场景需修改」的需求。
核心语法与示例:
定义带默认参数的函数(city默认值为"深圳")
注意:默认参数必须放在位置参数之后!
def print_student_info(name, grade, city="深圳"):
"""打印学生信息,城市默认为深圳"""
print(f"姓名:{name},年级:{grade},城市:{city}")
调用1:省略默认参数(使用默认值"深圳")
print_student_info("小明", 3)
输出:姓名:小明,年级:3,城市:深圳
调用2:覆盖默认参数(传值"杭州")
print_student_info("小红", 4, "杭州")
输出:姓名:小红,年级:4,城市:杭州
调用3:用关键字参数覆盖默认值(更清晰)
print_student_info("小刚", 5, city="成都")
输出:姓名:小刚,年级:5,城市:成都
默认参数的关键注意事项(新手必看):
- 默认参数的位置:必须放在所有位置参数之后,否则会报语法错误。
错误示例:
def func(city="北京", name): ...(默认参数在前,报错) - 默认参数的赋值时机:默认参数的值在「函数定义时」确定,而非调用时,避免使用可变对象(如列表、字典)作为默认参数。
反面示例(踩坑):
正确写法(用None作为占位符):错误示范:用列表作为默认参数 def add_item(item, lst=[]): lst.append(item) return lst print(add_item(1)) 输出:[1] print(add_item(2)) 输出:[1, 2](而非预期的[2])def add_item(item, lst=None): if lst is None: lst = [] lst.append(item) return lst print(add_item(1)) 输出:[1] print(add_item(2)) 输出:[2]
4. 可变长度参数(拓展)
若不确定需要接收多少个参数,可用*args(接收任意数量位置参数)或**kwargs(接收任意数量关键字参数),补充学习能应对更灵活的场景。
示例:
*args:接收多个位置参数(打包成元组)
def sum_all(*args):
"""计算任意多个数的和"""
total = 0
for num in args:
total += num
return total
print(sum_all(1, 2, 3)) 输出:6
print(sum_all(5, 10, 15, 20)) 输出:50
**kwargs:接收多个关键字参数(打包成字典)
def print_details(**kwargs):
"""打印任意关键字参数"""
for key, value in kwargs.items():
print(f"{key}:{value}")
print_details(subject="数学", score=95, teacher="李老师")
输出:
subject:数学
score:95
teacher:李老师
三、实战案例:用默认参数写实用函数
结合默认参数和位置参数,封装一个「计算商品折扣价」的函数,加深理解:
def calculate_discount(price, discount=0.1):
"""
计算商品折扣价
:param price: 商品原价(必选参数)
:param discount: 折扣率,默认0.1(即9折)
:return: 折扣后的价格
"""
final_price = price * (1 - discount)
保留2位小数,符合金额格式
return round(final_price, 2)
场景1:使用默认折扣(9折)
price1 = calculate_discount(100)
print(f"原价100元,9折后:{price1}元") 输出:原价100元,9折后:90.0元
场景2:自定义折扣(8折)
price2 = calculate_discount(200, 0.2)
print(f"原价200元,8折后:{price2}元") 输出:原价200元,8折后:160.0元
场景3:用关键字参数传折扣(更清晰)
price3 = calculate_discount(150, discount=0.05)
print(f"原价150元,95折后:{price3}元") 输出:原价150元,95折后:142.5元
四、常见错误与解决方法
| 错误现象 | 根本原因 | 解决方法 |
|---|---|---|
TypeError: func() missing 1 required positional argument: 'x' | 必选参数未传值 | 检查调用时的参数数量,补充缺失的位置参数 |
SyntaxError: non-default argument follows default argument | 默认参数放在了位置参数前面 | 调整参数顺序,默认参数必须在所有位置参数之后 |
| 默认参数使用列表/字典时,多次调用结果叠加 | 可变对象作为默认参数,定义时初始化一次 | 用None作为默认值,在函数内部重新初始化可变对象 |
TypeError: func() got multiple values for argument 'x' | 同一参数既按位置传值,又按关键字传值 | 避免重复传值,比如func(1, x=2)会触发该错误 |