函数参数详解
掌握参数传递的艺术
参数类型总览
python
def function(
pos1, pos2, # 位置参数
default_arg=10, # 默认参数
*args, # 可变位置参数
kwonly_arg, # 仅限关键字参数
**kwargs # 可变关键字参数
):
pass位置参数 vs 关键字参数
python
def describe_person(name, age, city):
print(f"{name}, {age}岁, 来自{city}")
# 位置参数(顺序重要)
describe_person("Alice", 25, "Beijing")
# 关键字参数(顺序无关)
describe_person(city="Shanghai", name="Bob", age=30)
# 混合(位置参数必须在前)
describe_person("Carol", age=28, city="Guangzhou")默认参数
python
def calculate_income_tax(income, tax_rate=0.25):
"""默认税率25%"""
return income * tax_rate
print(calculate_income_tax(100000)) # 25000(用默认值)
print(calculate_income_tax(100000, 0.30)) # 30000(指定税率)️ 默认参数陷阱:
python
# 危险:可变对象作为默认参数
def add_student(name, courses=[]):
courses.append(name)
return courses
print(add_student("Alice")) # ['Alice']
print(add_student("Bob")) # ['Alice', 'Bob'] ← 共享同一个列表!
# 正确做法
def add_student(name, courses=None):
if courses is None:
courses = []
courses.append(name)
return courses可变参数(*args)
python
def calculate_average(*scores):
"""接受任意数量的分数"""
if not scores:
return 0
return sum(scores) / len(scores)
print(calculate_average(85, 90, 78)) # 84.33
print(calculate_average(95, 88, 92, 76, 85)) # 87.2
# 解包列表
my_scores = [85, 90, 78, 92]
print(calculate_average(*my_scores)) # 使用*解包实用案例:合并数据
python
def merge_survey_data(*surveys):
"""合并多个调查数据"""
all_respondents = []
for survey in surveys:
all_respondents.extend(survey)
return all_respondents
survey1 = [{"id": 1, "age": 25}, {"id": 2, "age": 30}]
survey2 = [{"id": 3, "age": 35}]
survey3 = [{"id": 4, "age": 40}, {"id": 5, "age": 45}]
all_data = merge_survey_data(survey1, survey2, survey3)
print(f"总受访者: {len(all_data)} 人")关键字可变参数(**kwargs)
python
def create_respondent(**info):
"""创建受访者记录"""
return {
'respondent_id': info.get('id', 0),
'name': info.get('name', 'Unknown'),
'age': info.get('age', 0),
'additional_info': {k: v for k, v in info.items()
if k not in ['id', 'name', 'age']}
}
# 灵活传参
resp = create_respondent(
id=1001,
name="Alice",
age=30,
income=75000,
education="Master's",
city="Beijing"
)
print(resp)解包字典:
python
def register_student(name, age, major):
print(f"{name}, {age}岁, {major}")
student_data = {'name': 'Alice', 'age': 25, 'major': 'Economics'}
register_student(**student_data) # 解包字典组合使用
python
def process_survey_data(survey_name, year, *respondents, **metadata):
"""
survey_name, year: 必须的位置参数
*respondents: 可变数量的受访者
**metadata: 额外的元数据
"""
print(f"=== {survey_name} ({year}) ===")
print(f"受访者数量: {len(respondents)}")
print(f"元数据: {metadata}")
for i, resp in enumerate(respondents, 1):
print(f" {i}. {resp}")
# 使用
process_survey_data(
"中国居民收入调查",
2024,
{"id": 1, "age": 30},
{"id": 2, "age": 35},
{"id": 3, "age": 40},
region="全国",
sample_method="分层抽样",
response_rate=0.85
)仅限关键字参数(Python 3+)
python
def calculate_tax(income, *, tax_rate, deduction=0):
"""
income: 位置参数
*: 之后的参数必须用关键字传递
tax_rate: 必须用关键字
deduction: 有默认值,但也必须用关键字
"""
taxable = income - deduction
return taxable * tax_rate
# 正确
result = calculate_tax(100000, tax_rate=0.25, deduction=10000)
# 错误
# result = calculate_tax(100000, 0.25) # TypeError为什么使用? 提高代码可读性,避免参数位置错误。
实战:数据分析函数库
python
def filter_data(data, *, min_age=None, max_age=None, gender=None, min_income=None):
"""筛选数据(仅限关键字参数保证清晰)"""
filtered = data
if min_age is not None:
filtered = [r for r in filtered if r.get('age', 0) >= min_age]
if max_age is not None:
filtered = [r for r in filtered if r.get('age', 0) <= max_age]
if gender is not None:
filtered = [r for r in filtered if r.get('gender') == gender]
if min_income is not None:
filtered = [r for r in filtered if r.get('income', 0) >= min_income]
return filtered
# 使用
respondents = [
{'id': 1, 'age': 25, 'gender': 'Female', 'income': 50000},
{'id': 2, 'age': 35, 'gender': 'Male', 'income': 80000},
{'id': 3, 'age': 45, 'gender': 'Female', 'income': 95000},
]
# 清晰的筛选
young_females = filter_data(respondents, max_age=30, gender='Female')
high_earners = filter_data(respondents, min_income=70000)最佳实践
1. 参数顺序
python
# 推荐顺序
def function(
required_positional, # 必须的位置参数
optional_positional=None, # 可选的位置参数
*args, # 可变位置参数
required_keyword_only, # 必须的关键字参数
optional_keyword=None, # 可选的关键字参数
**kwargs # 可变关键字参数
):
pass2. 何时使用各种参数
| 参数类型 | 使用场景 |
|---|---|
| 位置参数 | 参数少且明显(如 calculate_bmi(weight, height)) |
| 默认参数 | 常用默认值(如 tax_rate=0.25) |
| *args | 数量不定的同类参数(如 sum(*numbers)) |
| **kwargs | 灵活的配置选项 |
| 关键字专用 | 提高可读性,避免混淆 |
3. 函数签名要清晰
python
# 不清晰
def process(a, b, c, d, e, f):
pass
# 清晰
def process_survey_response(
respondent_id,
age,
gender,
income,
education,
satisfaction_score
):
pass练习题
练习 1:灵活的统计函数
python
# 编写函数 calculate_stats(*values, **options)
# values: 任意数量的数值
# options: 可选参数
# - include_std: 是否计算标准差
# - round_digits: 保留小数位数
# 示例
result = calculate_stats(1, 2, 3, 4, 5, include_std=True, round_digits=2)练习 2:数据筛选器
python
# 编写函数 filter_respondents(data, **criteria)
# criteria 可以包含: min_age, max_age, gender, education, city 等
# 返回符合所有条件的受访者列表
data = [
{'id': 1, 'age': 25, 'gender': 'F', 'city': 'Beijing'},
{'id': 2, 'age': 35, 'gender': 'M', 'city': 'Shanghai'},
# ...
]
result = filter_respondents(data, min_age=30, city='Shanghai')下一步
在下一节中,我们将学习 Lambda 函数和函数式编程。
继续!