当前位置:首页 > 技术 > 正文内容

Python 函数高阶特性深度剖析:参数机制与函数式编程实战

访客 技术 2026年7月16日 1

函数参数高级特性

位置参数与关键字参数的区别

位置参数依靠参数顺序进行传递,实参按照函数定义时形参的顺序依次赋值。关键字参数则通过参数名明确指定对应关系,传递顺序可以灵活调整。

# 位置参数传递方式
def display_info(name, age):
    return f"姓名:{name}, 年龄:{age}"

# 按照定义顺序依次传递
print(display_info("小明", 25))

# 关键字参数传递方式
print(display_info(age=30, name="大明"))

混合使用规则:位置参数必须出现在关键字参数之前,否则会触发语法错误。

# 正确混合使用
print(display_info("小红", age=28))

# 错误示例 - 位置参数不能出现在关键字参数之后
# print(display_info(name="小绿", 28))  # SyntaxError

仅限位置参数与仅限关键字参数

使用斜杠/可以定义仅限位置传递的参数,使用星号*可以定义仅限关键字传递的参数。

# 使用 / 标记仅限位置参数
def restricted_func(a, b, /, c):
    return f"a={a}, b={b}, c={c}"

# 可以正常调用
print(restricted_func(1, 2, 3))
print(restricted_func(1, 2, c=3))

# 错误 - a和b不能使用关键字传递
# restricted_func(a=1, b=2, c=3)  # TypeError

# 使用 * 标记仅限关键字参数
def keyword_only_func(a, b, *, c, d):
    return f"a={a}, b={b}, c={c}, d={d}"

# 必须使用关键字参数传递c和d
print(keyword_only_func(1, 2, c=3, d=4))

# 错误 - c和d不能使用位置参数
# keyword_only_func(1, 2, 3, 4)  # TypeError

默认参数值的正确使用

默认参数在函数定义时进行求值,这一点至关重要。如果使用可变对象作为默认值,可能导致意外的状态共享问题。

# 错误示例 - 可变默认参数导致的状态共享
def append_value(item, storage=[]):
    storage.append(item)
    return storage

print(append_value("第一"))  # ['第一']
print(append_value("第二"))  # ['第一', '第二'] - 意外!

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

print(append_value_fixed("第一"))  # ['第一']
print(append_value_fixed("第二"))  # ['第二'] - 符合预期

可变位置参数与关键字参数

星号参数允许函数接收任意数量的位置参数或关键字参数。

# 可变位置参数 - 接收任意数量的位置参数
def calculate_sum(base, *values, multiplier=1):
    total = base
    for v in values:
        total += v * multiplier
    return total

print(calculate_sum(10))  # 10
print(calculate_sum(10, 1, 2, 3, multiplier=2))  # 10 + (1+2+3)*2

# 使用解包语法传递参数
numbers = [1, 2, 3, 4, 5]
print(calculate_sum(10, *numbers, multiplier=3))

# 可变关键字参数 - 接收任意数量的关键字参数
def build_user_profile(**information):
    result = {}
    for key, value in information.items():
        result[key] = value
    return result

profile = build_user_profile(username="admin", email="admin@example.com", role="superuser")
print(profile)

# 字典解包传递
config = {"host": "localhost", "port": 3306, "database": "testdb"}
print(build_user_profile(**config))

参数顺序规则

定义函数时,参数必须遵循以下顺序:位置参数 → 默认参数 → 可变位置参数 → 仅关键字参数 → 可变关键字参数

def complete_signature(pos_only, /, normal, *args, kw_only, **kwargs):
    print(f"位置限定: {pos_only}")
    print(f"普通参数: {normal}")
    print(f"可变参数: {args}")
    print(f"关键字限定: {kw_only}")
    print(f"关键字可变: {kwargs}")

complete_signature("位置", "普通", 1, 2, 3, kw_only="关键字", extra="附加")

函数高级特性

函数注解

函数注解为参数和返回值提供类型提示信息,这些信息存储在函数的__annotations__属性中,但不会影响函数执行。

def process_data(data: str, count: int) -> list:
    """处理数据并返回结果列表"""
    return [data * count]

# 查看注解信息
print(process_data.__annotations__)

# 注解可以是任意表达式
def complex_annotation(
    items: "可迭代对象",
    operation: callable = lambda x: x * 2
) -> "处理结果":
    return [operation(i) for i in items]

print(complex_annotation.__annotations__)

闭包函数

闭包是指内部函数引用外部函数作用域中的变量,即使外部函数执行完毕,这些变量依然被内部函数引用着。

# 闭包的基本结构
def multiplier_factory(factor):
    def multiply(value):
        return value * factor  # 引用外部函数的factor变量
    return multiply

double = multiplier_factory(2)
triple = multiplier_factory(3)

print(double(5))   # 10
print(triple(5))   # 15
print(multiplier_factory(4)(5))  # 20

# 使用闭包实现状态保存
def counter_factory():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

counter_a = counter_factory()
counter_b = counter_factory()

print(counter_a())  # 1
print(counter_a())  # 2
print(counter_a())  # 3
print(counter_b())  # 1 - 独立的计数器实例

装饰器

装饰器是一个接收函数作为参数并返回新函数的高阶函数,用于在不修改原函数的情况下扩展其功能。

# 日志记录装饰器
def log_calls(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_calls
def compute(x, y):
    return x ** y

compute(2, 8)
# 带参数的装饰器
def retry_on_failure(max_attempts=3):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_attempts - 1:
                        raise e
                    print(f"第{attempt + 1}次尝试失败,重试中...")
        return wrapper
    return decorator

@retry_on_failure(max_attempts=3)
def unstable_operation():
    import random
    if random.random() < 0.7:
        raise ValueError("操作失败")
    return "操作成功"

# 可能需要多次重试才能成功
# unstable_operation()
# 多个装饰器叠加
def uppercase_decorator(func):
    def wrapper(text):
        return func(text).upper()
    return wrapper

def add_prefix_decorator(func):
    def wrapper(text):
        return "PREFIX: " + func(text)
    return wrapper

@add_prefix_decorator
@uppercase_decorator
def process_text(text):
    return text

print(process_text("hello"))  # PREFIX: HELLO

函数作为一等公民

在Python中,函数可以像变量一样被传递、赋值、作为参数或返回值。

# 函数字典 - 根据操作符选择对应的函数
import operator

operations = {
    "add": lambda x, y: x + y,
    "sub": lambda x, y: x - y,
    "mul": lambda x, y: x * y,
    "div": lambda x, y: x / y,
    "+": operator.add,
    "-": operator.sub,
    "*": operator.mul,
    "/": operator.truediv,
}

def apply_operation(op_name, a, b):
    op_func = operations.get(op_name)
    if op_func:
        return op_func(a, b)
    raise ValueError(f"未知操作: {op_name}")

print(apply_operation("add", 10, 5))   # 15
print(apply_operation("-", 10, 5))     # 5
print(apply_operation("*", 10, 5))     # 50
print(apply_operation("/", 10, 5))     # 2.0

函数组合

函数组合将多个函数串联起来,前一个函数的输出作为后一个函数的输入。

def compose(*funcs):
    """将多个函数组合成一个函数"""
    def composed(initial):
        result = initial
        for func in reversed(funcs):
            result = func(result)
        return result
    return composed

def add_ten(x):
    return x + 10

def double(x):
    return x * 2

def square(x):
    return x ** 2

# f(g(x)) = square(double(add_ten(5)))
# = square(double(15)) = square(30) = 900
combined = compose(square, double, add_ten)
print(combined(5))  # 900

# 验证计算过程
step1 = add_ten(5)   # 15
step2 = double(15)  # 30
step3 = square(30)  # 900
print(f"验证: {step1} -> {step2} -> {step3}")

生成器

生成器函数使用yield关键字暂停并返回值,每次迭代时从暂停处继续执行,适合处理大数据流或无限序列。

基本生成器用法

# 生成指定范围的整数
def number_generator(limit):
    current = 1
    while current <= limit:
        yield current
        current += 1

gen = number_generator(3)
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3
# print(next(gen))  # StopIteration

# 使用for循环迭代
for num in number_generator(5):
    print(num, end=" ")  # 1 2 3 4 5
print()
# 无限序列生成器
def fibonacci_generator():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# 生成前10个斐波那契数
fib = fibonacci_generator()
fib_numbers = [next(fib) for _ in range(10)]
print(fib_numbers)  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

生成器表达式

生成器表达式使用圆括号,创建惰性迭代器,不会立即计算所有值。

# 列表推导式 - 立即计算所有值
squares_list = [x * x for x in range(5)]
print(squares_list)  # [0, 1, 4, 9, 16]

# 生成器表达式 - 惰性计算
squares_gen = (x * x for x in range(5))
print(squares_gen)   # 生成器对象
print(list(squares_gen))  # [0, 1, 4, 9, 16]

# 适合大数据场景
large_gen = (x ** 3 for x in range(1000000))
# 不会立即占用大量内存

yield from委托

yield from允许生成器将迭代委托给其他可迭代对象。

# 委托给其他生成器
def chain_generator(*iterables):
    for it in iterables:
        yield from it

def range_generator(n):
    for i in range(n):
        yield i

def string_generator(s):
    for char in s:
        yield char

# 组合多个数据源
combined = chain_generator(
    range_generator(3),
    string_generator("abc"),
    [100, 200]
)

print(list(combined))  # [0, 1, 2, 'a', 'b', 'c', 100, 200]

函数式编程范式

lambda表达式

lambda用于创建简单的匿名函数,适合临时使用的小型函数。

# 基本lambda语法
greeting = lambda name: f"你好, {name}!"
print(greeting("Python爱好者"))

# 多参数lambda
calculate = lambda x, y, z: (x + y) * z
print(calculate(2, 3, 4))  # 20

# 在高阶函数中使用
numbers = [5, 2, 8, 1, 9, 3]
sorted_desc = sorted(numbers, key=lambda x: -x)
print(sorted_desc)  # [9, 8, 5, 3, 2, 1]

# 复杂数据结构排序
products = [
    {"name": "手机", "price": 4999},
    {"name": "电脑", "price": 7999},
    {"name": "平板", "price": 2999},
]

sorted_by_price = sorted(products, key=lambda p: p["price"], reverse=True)
for p in sorted_by_price:
    print(f"{p['name']}: {p['price']}")

map函数

map函数将指定函数应用到可迭代对象的每个元素,返回迭代器。

numbers = [1, 2, 3, 4, 5]

# 计算每个数的平方
squared = list(map(lambda x: x ** 2, numbers))
print(squared)  # [1, 4, 9, 16, 25]

# 使用多个列表
list_a = [1, 2, 3]
list_b = [10, 20, 30]
added = list(map(lambda x, y: x + y, list_a, list_b))
print(added)  # [11, 22, 33]

# 结合使用内置函数
words = ["hello", "world", "python"]
uppercased = list(map(str.upper, words))
print(uppercased)  # ['HELLO', 'WORLD', 'PYTHON']

filter函数

filter函数根据条件筛选可迭代对象中的元素。

numbers = list(range(1, 21))

# 筛选偶数
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)  # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

# 筛选质数
def is_prime(num):
    if num < 2:
        return False
    for i in range(2, int(num ** 0.5) + 1):
        if num % i == 0:
            return False
    return True

primes = list(filter(is_prime, numbers))
print(primes)  # [2, 3, 5, 7, 11, 13, 17, 19]

# 筛选长度大于3的字符串
words = ["hi", "hello", "hey", "greetings", "yo"]
long_words = list(filter(lambda w: len(w) > 3, words))
print(long_words)  # ['hello', 'greetings']

reduce函数

reduce函数对序列中的元素进行累积操作,需要从functools模块导入。

from functools import reduce

numbers = [1, 2, 3, 4, 5]

# 求和
total = reduce(lambda acc, cur: acc + cur, numbers)
print(total)  # 15

# 求积
product = reduce(lambda acc, cur: acc * cur, numbers)
print(product)  # 120

# 找出最大值
maximum = reduce(lambda a, b: a if a > b else b, numbers)
print(maximum)  # 5

# 字符串连接
words = ["Python", "is", "awesome"]
sentence = reduce(lambda a, b: a + " " + b, words)
print(sentence)  # "Python is awesome"

综合示例

# 使用函数式编程风格处理数据
from functools import reduce

# 模拟学生成绩数据
students = [
    {"name": "张三", "scores": [85, 90, 78]},
    {"name": "李四", "scores": [92, 88, 95]},
    {"name": "王五", "scores": [70, 75, 80]},
]

# 计算每个学生的平均分
def calc_average(scores):
    return reduce(lambda a, b: a + b, scores) / len(scores)

averages = list(map(
    lambda s: {"name": s["name"], "average": calc_average(s["scores"])},
    students
))
print("学生平均分:", averages)

# 筛选平均分大于80的学生
high_achievers = list(filter(
    lambda s: s["average"] > 80,
    averages
))
print("高分学生:", high_achievers)

# 计算全年级平均分
all_scores = reduce(
    lambda acc, s: acc + s["average"],
    averages,
    0
)
grade_average = all_scores / len(averages)
print(f"年级平均分: {grade_average:.2f}")
标签: Python

相关文章

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

PHPStan 有什么用?怎么用?

PHPStan 是一个 PHP 的静态分析工具,在不运行代码的情况下就能帮你发现潜在问题,比如:传错类型(把 string 传给接受 int 的函数)访问不存在的属性 / 方法null 没处理好永远不会执行到的代码数组 key/值类型不一致返回值不符合声明注释和真实类型不匹配它非常适合:想提升代码质量、减少线上 bug、统一团队风格的人(尤其是中大型项目)。一、PHPStan 有什么用(通俗点说)...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。