Python 函数的参数
目录
函数基础
定义函数
Python 中使用 def 关键字定义函数:
def function_name(parameters):
"""文档字符串:描述函数的功能"""
# 函数体
return value # 可选
形参与实参
- 形参(Parameters):定义函数时声明的变量,用于接收传入的值
- 实参(Arguments):调用函数时传入的实际值
def greet(name): # name 是形参
return f"Hello, {name}!"
# 调用函数
greeting = greet("Alice") # "Alice" 是实参
print(greeting) # 输出: Hello, Alice!
返回值
函数可以使用 return 语句返回值。如果没有显式的 return 语句,函数将返回 None。
def add(a, b):
return a + b # 返回两数之和
def greet(name):
print(f"Hello, {name}!")
# 没有 return 语句,隐式返回 None
result = add(5, 3)
print(result) # 输出: 8
result = greet("Bob")
print(result) # 输出: None
多值返回:Python 函数可以返回多个值,实际上是返回一个元组
def stats(numbers):
return min(numbers), max(numbers), sum(numbers) / len(numbers)
minimum, maximum, average = stats([1, 2, 3, 4, 5])
print(f"最小值: {minimum}, 最大值: {maximum}, 平均值: {average}")
参数类型
位置参数
位置参数是最基本的参数类型,按照定义的顺序传递:
def describe_pet(animal_type, pet_name):
return f"{pet_name} is a {animal_type}."
# 按位置传递参数
print(describe_pet("hamster", "Harry")) # Harry is a hamster.
关键字参数
关键字参数通过参数名显式指定,可以不按顺序传递:
def describe_pet(animal_type, pet_name):
return f"{pet_name} is a {animal_type}."
# 使用关键字参数
print(describe_pet(pet_name="Harry", animal_type="hamster")) # Harry is a hamster.
默认参数
默认参数为形参提供默认值,如果调用时未指定对应的实参,则使用默认值:
def describe_pet(pet_name, animal_type="dog"):
return f"{pet_name} is a {animal_type}."
# 只提供必需的参数,使用 animal_type 的默认值
print(describe_pet("Willie")) # Willie is a dog.
# 同时提供两个参数,覆盖默认值
print(describe_pet("Harry", "hamster")) # Harry is a hamster.
注意事项:默认参数的值只在函数定义时计算一次,对于可变对象需要特别小心:
# 不推荐的做法
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
特殊参数语法
位置参数限定 (/)
Python 3.8 引入的语法,斜杠 / 左侧的参数只能作为位置参数传递:
def standard_arg(arg):
# 可以作为位置参数或关键字参数
return arg
def pos_only_arg(arg, /):
# 只能作为位置参数
return arg
# 正确调用方式
standard_arg(42) # 有效
standard_arg(arg=42) # 有效
pos_only_arg(42) # 有效
pos_only_arg(arg=42) # 错误 - TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg'
关键字参数限定 (*)
星号 * 右侧的参数只能作为关键字参数传递:
def kwd_only_arg(*, arg):
# 只能作为关键字参数
return arg
def combined_example(pos_only, /, standard, *, kwd_only):
# pos_only:只能是位置参数
# standard:可以是位置参数或关键字参数
# kwd_only:只能是关键字参数
return pos_only, standard, kwd_only
# 正确调用方式
kwd_only_arg(arg=42) # 有效
kwd_only_arg(42) # 错误 - TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
combined_example(1, 2, kwd_only=3) # 有效
combined_example(1, standard=2, kwd_only=3) # 有效
combined_example(pos_only=1, standard=2, kwd_only=3) # 错误 - pos_only 不能作为关键字参数
收集参数
收集位置参数 (*args)
使用 *args 收集任意多个位置参数,这些参数被打包成一个元组:
def sum_all(*numbers):
"""计算所有传入数字的和"""
return sum(numbers)
print(sum_all(1, 2, 3)) # 6
print(sum_all(10, 20, 30, 40)) # 100
print(sum_all()) # 0 (空元组)
# 带有普通参数的例子
def make_pizza(size, *toppings):
"""描述要制作的披萨"""
print(f"Making a {size}-inch pizza with the following toppings:")
for topping in toppings:
print(f"- {topping}")
make_pizza(16, "pepperoni")
make_pizza(12, "mushrooms", "green peppers", "extra cheese")
收集关键字参数 (**kwargs)
使用 **kwargs 收集任意多个关键字参数,这些参数被打包成一个字典:
def build_profile(**user_info):
"""创建用户信息字典"""
return user_info
profile = build_profile(first_name="Albert", last_name="Einstein",
field="physics", awards="Nobel Prize")
print(profile)
# 输出: {'first_name': 'Albert', 'last_name': 'Einstein', 'field': 'physics', 'awards': 'Nobel Prize'}
# 带有普通参数的例子
def create_car(manufacturer, model, **options):
"""创建描述汽车的字典"""
car_dict = {
'manufacturer': manufacturer,
'model': model
}
car_dict.update(options)
return car_dict
my_car = create_car('subaru', 'outback', color='blue', tow_package=True)
print(my_car)
同时使用两种收集参数
可以在同一个函数中同时使用 *args 和 **kwargs,但必须按顺序:先是普通位置参数,然后是 *args,然后是普通关键字参数,最后是 **kwargs:
def complex_function(a, b, *args, c=10, **kwargs):
print(f"a = {a}, b = {b}")
print(f"args = {args}") # 元组
print(f"c = {c}")
print(f"kwargs = {kwargs}") # 字典
complex_function(1, 2, 3, 4, 5, c=30, d=40, e=50)
# 输出:
# a = 1, b = 2
# args = (3, 4, 5)
# c = 30
# kwargs = {'d': 40, 'e': 50}
注意:在有 *args 的情况下,args 后面的普通参数必须作为关键字参数传递。
参数解包
位置参数解包
使用 * 运算符可以将序列(如列表或元组)解包为位置参数:
def add(a, b, c):
return a + b + c
numbers = [1, 2, 3]
print(add(*numbers)) # 相当于 add(1, 2, 3)
# 与字符串一起使用
chars = "abc"
print(add(*chars)) # 相当于 add('a', 'b', 'c')
关键字参数解包
使用 ** 运算符可以将字典解包为关键字参数:
def person_info(name, age, city):
return f"{name} is {age} years old and lives in {city}."
person = {"name": "Alice", "age": 30, "city": "New York"}
print(person_info(**person)) # 相当于 person_info(name="Alice", age=30, city="New York")
混合解包
def func(a, b, c, d):
return a, b, c, d
pos_args = (1, 2)
kwd_args = {"c": 3, "d": 4}
result = func(*pos_args, **kwd_args)
print(result) # (1, 2, 3, 4)
字符串格式化与函数参数
Python 的字符串 format() 方法与函数参数有相似之处:
# 基本使用
print("{} {}".format("Hello", "World")) # Hello World
# 位置参数
print("{0}, {1}, {0}".format("A", "B")) # A, B, A
# 关键字参数
print("{greeting}, {name}!".format(greeting="Hello", name="World")) # Hello, World!
# 解包字典作为关键字参数
data = {"greeting": "Hello", "name": "World"}
print("{greeting}, {name}!".format(**data)) # Hello, World!
# 混合使用位置参数和关键字参数
print("{}, {name}!".format("Hello", name="World")) # Hello, World!
自 Python 3.6 起,f-字符串提供了更简洁的字符串格式化方式:
name = "World"
greeting = "Hello"
print(f"{greeting}, {name}!") # Hello, World!
实际应用案例
1. 灵活的数据处理函数
def process_data(data, *, sort=False, filter_func=None, **format_options):
"""处理数据集合,支持多种选项"""
result = data.copy() # 创建副本以免修改原始数据
# 应用过滤函数
if filter_func:
result = [item for item in result if filter_func(item)]
# 排序
if sort:
result.sort()
# 应用格式化选项
if format_options:
# 这里可以根据 format_options 进行自定义处理
if 'prefix' in format_options:
result = [f"{format_options['prefix']}{item}" for item in result]
if 'suffix' in format_options:
result = [f"{item}{format_options['suffix']}" for item in result]
return result
# 使用示例
numbers = [3, 1, 4, 1, 5, 9, 2]
even_numbers = process_data(
numbers,
sort=True,
filter_func=lambda x: x % 2 == 0, # 只保留偶数
prefix="Number: ",
suffix="!"
)
print(even_numbers) # ['Number: 2!', 'Number: 4!']
2. 装饰器函数
装饰器是高阶函数的一个应用,使用了参数传递和返回函数的概念:
def log_function_call(func):
"""记录函数调用的装饰器"""
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
print(f"位置参数: {args}")
print(f"关键字参数: {kwargs}")
result = func(*args, **kwargs)
print(f"返回值: {result}")
return result
return wrapper
@log_function_call
def calculate_area(length, width=1):
"""计算矩形面积"""
return length * width
area = calculate_area(5, width=2)
# 输出:
# 调用函数: calculate_area
# 位置参数: (5,)
# 关键字参数: {'width': 2}
# 返回值: 10
3. 命令行参数解析
def parse_command(command_name, *args, **options):
"""解析类似命令行的命令和选项"""
print(f"执行命令: {command_name}")
# 处理位置参数
if args:
print(f"参数: {' '.join(map(str, args))}")
else:
print("没有参数")
# 处理选项
if options:
print("选项:")
for key, value in options.items():
print(f" --{key}={value}")
else:
print("没有选项")
# 模拟命令行调用
parse_command("copy", "file1.txt", "file2.txt", overwrite=True, recursive=False)
# 输出:
# 执行命令: copy
# 参数: file1.txt file2.txt
# 选项:
# --overwrite=True
# --recursive=False
4. 可配置的通用函数
def create_html_element(tag, content=None, /, *children, id=None, **attributes):
"""
创建HTML元素
参数:
tag: 标签名 (位置参数)
content: 内容 (位置参数)
*children: 子元素列表
id: 元素ID (关键字参数)
**attributes: 其他HTML属性
"""
# 开始标签
html = [f"<{tag}"]
# 添加ID和其他属性
if id:
html.append(f' id="{id}"')
for attr, value in attributes.items():
html.append(f' {attr.replace("_", "-")}="{value}"')
html.append('>')
# 添加内容或子元素
if content is not None:
html.append(str(content))
for child in children:
html.append(str(child))
# 结束标签
html.append(f"</{tag}>")
return ''.join(html)
# 使用示例
div = create_html_element("div", "Hello", id="greeting", class_name="container", data_value="42")
print(div) # <div id="greeting" class-name="container" data-value="42">Hello</div>
# 使用子元素
document = create_html_element(
"div",
create_html_element("h1", "Title"),
create_html_element("p", "Paragraph 1"),
create_html_element("p", "Paragraph 2"),
id="content"
)
print(document)
# <div id="content"><h1>Title</h1><p>Paragraph 1</p><p>Paragraph 2</p></div>
总结
- 形参:定义函数时声明的变量;实参:调用函数时传递的值
- 位置参数:按位置顺序传递的参数
- 关键字参数:按名称传递的参数
- 默认参数:有默认值的参数,可以在调用时省略
- 位置参数限定 (/):斜杠左侧的参数只能作为位置参数
- 关键字参数限定 (*):星号右侧的参数只能作为关键字参数
- 收集位置参数 (*args):收集额外的位置参数为元组
- 收集关键字参数 (
**kwargs):收集额外的关键字参数为字典 - 参数解包:使用
*和**将序列和字典解包为参数
1313

被折叠的 条评论
为什么被折叠?



