Python函数参数非常灵活,支持多种传参方式。掌握这些参数形式是写出优雅Python代码的关键。

目录

  1. 位置参数
  2. 默认参数
  3. 关键字参数
  4. 可变参数
  5. 仅关键字参数
  6. 参数组合使用
  7. 参数解包
  8. 类型提示与参数
  9. 实际应用场景

位置参数

基本用法

位置参数是最基本的参数形式,按顺序传递:

def greet(name, message):
    """简单的问候函数"""
    return f"{message}, {name}!"

# 按位置传递参数
result = greet("Alice", "Hello")
print(result)  # Hello, Alice!

# 参数顺序很重要
result = greet("Hello", "Alice")  # 错误顺序
print(result)  # Alice, Hello! (逻辑错误)

多个位置参数

def calculate_volume(length, width, height):
    """计算长方体体积"""
    return length * width * height

# 必须按正确顺序传递
volume = calculate_volume(10, 5, 3)
print(volume)  # 150

# 顺序错误会导致错误结果
wrong_volume = calculate_volume(3, 10, 5)  # 3*10*5=150 (巧合相同)

默认参数

基本用法

为参数提供默认值,调用时可省略:

def greet(name, message="Hello"):
    """带默认值的问候函数"""
    return f"{message}, {name}!"

# 使用默认参数
result1 = greet("Alice")          # Hello, Alice!
result2 = greet("Bob", "Hi")      # Hi, Bob!

# 多个默认参数
def create_user(name, age, role="user", active=True):
    """创建用户信息"""
    return {
        "name": name,
        "age": age,
        "role": role,
        "active": active
    }

user1 = create_user("Alice", 25)  # 使用默认role和active
user2 = create_user("Bob", 30, "admin", False)

默认参数陷阱

重要:默认参数只计算一次,不要使用可变默认值:

# 错误示例:使用可变默认值
def add_item(item, items=[]):
    items.append(item)
    return items

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2] - 意外!

# 正确做法:使用None作为默认值
def add_item_correct(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

print(add_item_correct(1))  # [1]
print(add_item_correct(2))  # [2] - 正确!

关键字参数

基本用法

通过参数名指定值,顺序不重要:

def describe_person(name, age, city):
    """描述个人信息"""
    return f"{name} is {age} years old and lives in {city}"

# 使用关键字参数
result = describe_person(name="Alice", age=25, city="Beijing")
print(result)  # Alice is 25 years old and lives in Beijing

# 顺序可以任意
result = describe_person(city="Shanghai", name="Bob", age=30)
print(result)  # Bob is 30 years old and lives in Shanghai

# 混合使用位置和关键字参数
result = describe_person("Charlie", age=35, city="Guangzhou")

关键字参数的优势

# 提高代码可读性
def connect_to_database(host, port, username, password, database, timeout=30):
    """连接数据库"""
    # 实现代码...
    return f"Connected to {database} on {host}:{port}"

# 使用关键字参数更清晰
connection = connect_to_database(
    host="localhost",
    port=5432,
    username="admin",
    password="secret",
    database="mydb",
    timeout=60
)

# 比位置参数更易读
# connect_to_database("localhost", 5432, "admin", "secret", "mydb", 60)

可变参数

*args - 可变位置参数

接收任意数量的位置参数:

def sum_numbers(*args):
    """计算任意数量数字的和"""
    print(f"接收到的参数: {args}")  # 元组形式
    return sum(args)

# 使用示例
result1 = sum_numbers(1, 2, 3)         # 6
result2 = sum_numbers(1, 2, 3, 4, 5)   # 15
result3 = sum_numbers()                # 0

# 与其他参数结合
def make_sentence(*words):
    """将单词组成句子"""
    return " ".join(words).capitalize() + "."

sentence = make_sentence("hello", "world", "from", "python")
print(sentence)  # Hello world from python.

**kwargs - 可变关键字参数

接收任意数量的关键字参数:

def print_info(**kwargs):
    """打印任意关键字参数"""
    for key, value in kwargs.items():
        print(f"{key}: {value}")

# 使用示例
print_info(name="Alice", age=25, city="Beijing")
# name: Alice
# age: 25
# city: Beijing

print_info(title="Python", version="3.9", author="Guido")
# title: Python
# version: 3.9
# author: Guido

# 空调用
print_info()  # 无输出

实际应用

def create_html_tag(tag_name, **attributes):
    """创建HTML标签"""
    attrs_str = " ".join(f'{k}="{v}"' for k, v in attributes.items())
    return f"<{tag_name} {attrs_str}>"

# 使用可变关键字参数
div = create_html_tag("div", class_="container", id="main", style="color: red")
print(div)  # <div class="container" id="main" style="color: red">

a = create_html_tag("a", href="https://python.org", target="_blank")
print(a)    # <a href="https://python.org" target="_blank">

仅关键字参数

基本用法

强制使用关键字传递的参数:

def calculate_total(price, *, tax_rate=0.1, discount=0):
    """计算总价,tax_rate和discount必须使用关键字"""
    total = price * (1 + tax_rate) * (1 - discount)
    return total

# 正确使用
total1 = calculate_total(100, tax_rate=0.15, discount=0.1)
total2 = calculate_total(100, discount=0.2)  # 使用默认tax_rate

# 错误使用
# total = calculate_total(100, 0.15, 0.1)  # TypeError

实际应用场景

def send_email(to, subject, body, *, cc=None, bcc=None, reply_to=None):
    """发送邮件,cc、bcc、reply_to必须使用关键字"""
    print(f"发送给: {to}")
    print(f"主题: {subject}")
    print(f"正文: {body}")
    if cc:
        print(f"抄送: {cc}")
    if bcc:
        print(f"密送: {bcc}")
    if reply_to:
        print(f"回复地址: {reply_to}")

# 强制使用关键字,提高代码可读性
send_email(
    "alice@example.com",
    "会议通知",
    "请参加明天的会议",
    cc=["bob@example.com", "charlie@example.com"],
    reply_to="admin@example.com"
)

参数组合使用

正确的参数顺序

参数定义必须遵循特定顺序:

  1. 位置参数
  2. 默认参数 / 关键字参数
  3. *args
  4. 仅关键字参数
  5. **kwargs
def complex_function(a, b, c=10, *args, d=20, e, **kwargs):
    """
    复杂的参数组合示例
    a, b: 位置参数
    c: 默认参数
    *args: 可变位置参数
    d: 仅关键字参数(有默认值)
    e: 仅关键字参数(无默认值)
    **kwargs: 可变关键字参数
    """
    print(f"a={a}, b={b}, c={c}")
    print(f"args={args}")
    print(f"d={d}, e={e}")
    print(f"kwargs={kwargs}")

# 调用示例
complex_function(1, 2, 3, 4, 5, e=30, f=40, g=50)
# a=1, b=2, c=3
# args=(4, 5)
# d=20, e=30
# kwargs={'f': 40, 'g': 50}

实际组合示例

def process_data(data, *filters, verbose=False, **options):
    """
    处理数据函数
    data: 位置参数(必需)
    *filters: 可变过滤条件
    verbose: 仅关键字参数
    **options: 其他选项
    """
    print(f"处理数据: {data}")
    
    if filters:
        print(f"应用过滤器: {filters}")
    
    if verbose:
        print("详细模式开启")
    
    if options:
        print(f"其他选项: {options}")

# 调用示例
process_data([1, 2, 3], "filter1", "filter2", verbose=True, timeout=30, retry=3)

参数解包

* 解包位置参数

def print_coordinates(x, y, z):
    """打印坐标"""
    print(f"坐标: ({x}, {y}, {z})")

# 使用解包
coordinates = (10, 20, 30)
print_coordinates(*coordinates)  # 相当于 print_coordinates(10, 20, 30)

# 列表解包
points = [1, 2, 3]
print_coordinates(*points)  # 坐标: (1, 2, 3)

# 部分解包
first, *rest = [1, 2, 3, 4, 5]
print(f"第一个: {first}, 其他: {rest}")  # 第一个: 1, 其他: [2, 3, 4, 5]

** 解包关键字参数

def create_person(name, age, city, occupation):
    """创建人员信息"""
    return {
        "name": name,
        "age": age,
        "city": city,
        "occupation": occupation
    }

# 使用字典解包
person_data = {
    "name": "Alice",
    "age": 25,
    "city": "Beijing",
    "occupation": "Engineer"
}

person = create_person(**person_data)
print(person)
# {'name': 'Alice', 'age': 25, 'city': 'Beijing', 'occupation': 'Engineer'}

# 混合解包
def complex_func(a, b, c, d, e):
    print(a, b, c, d, e)

args = [1, 2]
kwargs = {'d': 4, 'e': 5}
complex_func(*args, 3, **kwargs)  # 1 2 3 4 5

类型提示与参数

基本类型提示

from typing import List, Dict, Optional, Union

def process_user(
    name: str,
    age: int,
    hobbies: List[str],
    metadata: Optional[Dict[str, str]] = None,
    score: Union[int, float] = 0
) -> Dict[str, Union[str, int, List[str]]]:
    """
    处理用户信息
    """
    if metadata is None:
        metadata = {}
    
    return {
        "name": name,
        "age": age,
        "hobbies": hobbies,
        "metadata": metadata,
        "score": score
    }

# 使用示例
user = process_user(
    name="Alice",
    age=25,
    hobbies=["reading", "coding"],
    metadata={"department": "IT"},
    score=95.5
)

更复杂的类型提示

from typing import Callable, Tuple

def data_pipeline(
    data: List[int],
    *processors: Callable[[List[int]], List[int]],
    verbose: bool = False,
    **options: str
) -> Tuple[List[int], Dict[str, str]]:
    """
    数据处理管道
    """
    result = data.copy()
    
    for processor in processors:
        result = processor(result)
        if verbose:
            print(f"处理后: {result}")
    
    return result, options

# 使用示例
def double_numbers(nums):
    return [x * 2 for x in nums]

def filter_even(nums):
    return [x for x in nums if x % 2 == 0]

result, opts = data_pipeline(
    [1, 2, 3, 4, 5],
    double_numbers,
    filter_even,
    verbose=True,
    source="test",
    version="1.0"
)

实际应用场景

配置处理函数

def initialize_app(
    host: str,
    port: int,
    *,
    debug: bool = False,
    reload: bool = False,
    workers: int = 1,
    **extra_settings
):
    """应用初始化配置"""
    config = {
        "host": host,
        "port": port,
        "debug": debug,
        "reload": reload,
        "workers": workers,
        **extra_settings
    }
    
    print("应用配置:")
    for key, value in config.items():
        print(f"  {key}: {value}")
    
    return config

# 清晰的配置设置
app_config = initialize_app(
    "0.0.0.0",
    8000,
    debug=True,
    reload=True,
    database_url="postgresql://localhost/mydb",
    cache_enabled=True
)

数据验证函数

def validate_user_input(
    username: str,
    password: str,
    *,
    min_length: int = 6,
    require_special_chars: bool = True,
    require_numbers: bool = True,
    **validation_rules
) -> bool:
    """验证用户输入"""
    errors = []
    
    if len(username) < min_length:
        errors.append(f"用户名至少需要{min_length}个字符")
    
    if len(password) < min_length:
        errors.append(f"密码至少需要{min_length}个字符")
    
    if require_special_chars and not any(c in "!@#$%^&*" for c in password):
        errors.append("密码必须包含特殊字符")
    
    if require_numbers and not any(c.isdigit() for c in password):
        errors.append("密码必须包含数字")
    
    # 处理额外的验证规则
    for rule_name, rule_func in validation_rules.items():
        if not rule_func(username, password):
            errors.append(f"验证失败: {rule_name}")
    
    if errors:
        print("验证错误:")
        for error in errors:
            print(f"  - {error}")
        return False
    
    return True

# 使用示例
is_valid = validate_user_input(
    "alice",
    "password123!",
    min_length=8,
    custom_rule=lambda u, p: "admin" not in u.lower()
)

灵活的API包装器

def api_call(
    endpoint: str,
    method: str = "GET",
    *params: str,
    headers: dict = None,
    timeout: int = 30,
    **payload
):
    """灵活的API调用函数"""
    import requests
    
    if headers is None:
        headers = {}
    
    url = f"https://api.example.com/{endpoint}"
    
    # 构建查询参数
    query_params = list(params)
    
    # 处理不同的HTTP方法
    if method.upper() == "GET":
        response = requests.get(
            url,
            params=payload,
            headers=headers,
            timeout=timeout
        )
    elif method.upper() == "POST":
        response = requests.post(
            url,
            json=payload,
            headers=headers,
            timeout=timeout
        )
    else:
        raise ValueError(f"不支持的HTTP方法: {method}")
    
    return response.json()

# 使用示例
# GET请求
user_data = api_call("users", "GET", id=123, fields="name,email")

# POST请求
result = api_call(
    "users",
    "POST",
    headers={"Authorization": "Bearer token123"},
    name="Alice",
    email="alice@example.com",
    age=25
)

总结

Python函数参数提供了极大的灵活性:

参数类型 语法 特点 适用场景
位置参数 def func(a, b) 按顺序传递 必需参数
默认参数 def func(a=1) 有默认值 可选参数
关键字参数 func(a=1, b=2) 按名称传递 提高可读性
可变位置参数 def func(*args) 任意数量位置参数 处理不定数量输入
可变关键字参数 def func(**kwargs) 任意数量关键字参数 处理配置选项
仅关键字参数 def func(*, a) 必须关键字传递 强制明确参数含义

更多推荐