Python 函数—参数

Python 函数的参数

目录

  1. 函数基础
  2. 参数类型
  3. 特殊参数语法
  4. 收集参数
  5. 参数解包
  6. 字符串格式化与函数参数
  7. 实际应用案例

函数基础

定义函数

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>

总结

  1. 形参:定义函数时声明的变量;实参:调用函数时传递的值
  2. 位置参数:按位置顺序传递的参数
  3. 关键字参数:按名称传递的参数
  4. 默认参数:有默认值的参数,可以在调用时省略
  5. 位置参数限定 (/):斜杠左侧的参数只能作为位置参数
  6. 关键字参数限定 (*):星号右侧的参数只能作为关键字参数
  7. 收集位置参数 (*args):收集额外的位置参数为元组
  8. 收集关键字参数 (**kwargs):收集额外的关键字参数为字典
  9. 参数解包:使用 *** 将序列和字典解包为参数
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值