Python 函数进阶:深入理解参数、装饰器与函数式编程

发布于:2025-08-20 ⋅ 阅读:(12) ⋅ 点赞:(0)

Python 的成功很大程度上归功于其清晰、简洁且功能强大的语法,而函数在其中扮演了核心角色。从简单的代码封装到复杂的函数式编程范式,理解函数的方方面面是成为一名优秀 Python 开发者的必经之路。本文将深入探讨 Python 函数的几个关键高级特性。

1. 灵活多变的函数参数

Python 的函数参数处理非常灵活,主要支持以下四种类型:

1.1 位置参数

这是最常用的参数类型。调用函数时,实参的顺序和数量必须与形参的定义完全匹配。

def greet(name, greeting):
    print(f"{greeting}, {name}!")

greet("Alice", "Hello")  # 输出: Hello, Alice!
# greet("Hello")        # 错误:缺少一个必需的位置参数

1.2 默认参数

在定义函数时,可以为参数指定一个默认值。调用时如果未传递该参数,则使用默认值。默认参数必须指向不可变对象,否则可能引发意想不到的行为。

def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

greet("Bob")            # 输出: Hello, Bob!
greet("Charlie", "Hi") # 输出: Hi, Charlie!

1.3 可变参数 (*args)

当你不确定要传递多少个位置参数时,可以使用 *args。它会将传入的所有额外位置参数收集到一个元组中。

def add_numbers(*args):
    total = 0
    for num in args:
        total += num
    return total

result = add_numbers(1, 2, 3, 4, 5)
print(result)  # 输出: 15

1.4 关键字参数 (**kwargs)

用于处理不定数量的关键字参数(如 key=value 形式)。它会将这些参数收集到一个字典中。

def print_user_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_user_info(name="Dave", age=30, city="New York")
# 输出:
# name: Dave
# age: 30
# city: New York

混合使用顺序:在定义一个函数时,这四种参数必须遵循严格的顺序:
位置参数 -> 默认参数 -> *args -> **kwargs

def complex_function(a, b=2, *args, **kwargs):
    print(f"a={a}, b={b}")
    print(f"args: {args}")
    print(f"kwargs: {kwargs}")

complex_function(1, 3, 4, 5, 6, name='John', age=25)
# 输出:
# a=1, b=3
# args: (4, 5, 6)
# kwargs: {'name': 'John', 'age': 25}

2. 函数也是一种对象:一等函数与高阶函数

在 Python 中,函数是第一类对象。这意味着函数可以:

  • 被赋值给一个变量

  • 作为参数传递给另一个函数

  • 作为另一个函数的返回值

2.1 把函数赋值给变量

def say_hello(name):
    return f"Hello, {name}!"

greet = say_hello  # 将函数对象赋值给变量 greet
print(greet("World"))  # 输出: Hello, World!

2.2 高阶函数

接收函数作为参数,或者返回函数作为结果的函数,被称为高阶函数mapfiltersorted 等都是经典的高阶函数。

# 1. 作为参数
def apply_func(func, data):
    return [func(item) for item in data]

numbers = [1, 2, 3, 4]
squared = apply_func(lambda x: x**2, numbers)
print(squared)  # 输出: [1, 4, 9, 16]

# 2. 作为返回值
def get_multiplier(factor):
    def multiplier(x):
        return x * factor
    return multiplier

double = get_multiplier(2)
triple = get_multiplier(3)

print(double(5))  # 输出: 10
print(triple(5))  # 输出: 15

2.3 Lambda 匿名函数

lambda 关键字用于创建小巧的匿名函数。它只是一个表达式,函数体比 def 简单的多。

# 语法: lambda arguments: expression
square = lambda x: x ** 2
print(square(5)) # 输出: 25

# 常用于高阶函数中作为参数
numbers = [1, 4, 2, 9, 5]
sorted_numbers = sorted(numbers, key=lambda x: -x)
print(sorted_numbers)  # 输出: [9, 5, 4, 2, 1]

3. 迭代器 (Iterator) 与生成器 (Generator)

3.1 迭代器 (Iterator)

迭代器是实现了迭代器协议的对象,该协议包含两个方法:

  • __iter__(): 返回迭代器对象本身。

  • __next__(): 返回容器的下一个元素。如果没有更多元素,则抛出 StopIteration 异常。

列表、元组、字典、集合都是可迭代对象 (Iterable),但不是迭代器。可以使用 iter() 函数将它们转换为迭代器。

my_list = [1, 2, 3]
my_iter = iter(my_list) # 获取迭代器

print(next(my_iter)) # 输出: 1
print(next(my_iter)) # 输出: 2
print(next(my_iter)) # 输出: 3
# print(next(my_iter)) # 抛出 StopIteration 异常

3.2 生成器 (Generator)

生成器是一种特殊的迭代器,它延迟计算,按需产生值,而不是一次性在内存中构建整个序列,非常节省内存。

创建生成器有两种主要方法:

方法一:生成器函数 (使用 yield)
使用 yield 关键字代替 return。每次调用 next() 时,函数会从上次 yield 的位置继续执行。

def countdown(n):
    print("Starting countdown!")
    while n > 0:
        yield n  # 产生值 n,并在此暂停
        n -= 1
    print("Blastoff!")

# 创建生成器对象
cd = countdown(3)
print(next(cd)) # 输出: Starting countdown! 然后输出 3
print(next(cd)) # 输出: 2
print(next(cd)) # 输出: 1
print(next(cd)) # 输出: Blastoff! 然后抛出 StopIteration

方法二:生成器表达式
语法类似列表推导式,但使用圆括号 ()

# 列表推导式 - 立即生成所有数据,耗内存
list_comp = [x*x for x in range(1000000)]

# 生成器表达式 - 几乎不占内存,按需生成
gen_exp = (x*x for x in range(1000000))

print(next(gen_exp)) # 输出: 0
print(next(gen_exp)) # 输出: 1
# ... 可以用于 for 循环
for num in gen_exp:
    if num > 25:
        break
    print(num, end=' ')
# 输出: 4 9 16 25

4. 常用内置函数 (Built-in Functions)

Python 提供了许多高效的内置函数,以下是一些非常常用的:

  • len(s): 返回对象长度。

  • range(stop) / range(start, stop[, step]): 生成一个整数序列。

  • type(obj): 返回对象的类型。

  • isinstance(obj, classinfo): 检查对象是否是某个类或其子类的实例。

  • input([prompt]): 从标准输入读取字符串。

  • print(*objects, sep=' ', end='\n'): 打印输出。

  • enumerate(iterable, start=0): 返回一个枚举对象,生成 (index, value) 元组。

  • zip(*iterables): 将多个可迭代对象中对应的元素打包成元组。

  • map(func, iterable, ...): 将函数应用于可迭代对象的每个元素,返回一个迭代器。

  • sorted(iterable, key=None, reverse=False): 返回一个新的排序列表。

5. 闭包 (Closure)

闭包是一个能够访问其外部函数作用域中变量的内部函数,即使外部函数已经执行完毕。

闭包的三个必要条件:

  1. 必须有一个嵌套函数(内部函数)。

  2. 嵌套函数必须引用外部函数中定义的变量。

  3. 外部函数必须返回内部函数。

def outer_func(msg):
    message = msg  # 外部作用域的变量

    def inner_func(): # 嵌套函数
        print(message) # 引用了外部变量 message

    return inner_func  # 返回内部函数对象

my_closure = outer_func("Hello, Closure!")
my_closure()  # 输出: Hello, Closure!
# 此时 outer_func 已执行完,但 inner_func 仍能记住并访问 message 变量

闭包是一种强大的技术,常用于数据隐藏和封装装饰器回调函数等场景。但闭包也有一个缺陷,外部函数的非局部变量一直被内部函数引用,长时间得不到回收,可能会导致内存泄漏,因此使用的优先级就进一步降低了。

6. 装饰器 (Decorator)

装饰器是 Python 中最具特色的功能之一。它本质上是一个接收函数作为参数并返回一个新函数的高阶函数。装饰器可以在不修改原函数代码的情况下,为其增加新的功能(如日志、计时、权限校验等)。

6.1 基本语法与原理

使用 @decorator_name 语法糖放在函数定义前。

def my_decorator(func):    # 接收一个函数作为参数
    def wrapper():         # 定义一个包装函数
        print("Something is happening before the function is called.")
        func()            # 执行原函数
        print("Something is happening after the function is called.")
    return wrapper         # 返回包装函数

@my_decorator  # 这相当于: say_hello = my_decorator(say_hello)
def say_hello():
    print("Hello!")

say_hello()
# 输出:
# Something is happening before the function is called.
# Hello!
# Something is happening after the function is called.

6.2 处理带参数的函数

为了让装饰器通用,内部的 wrapper 函数应使用 *args 和 **kwargs 来接受任意参数。

def decorator_with_args(func):
    def wrapper(*args, **kwargs):
        print("Decorator is working!")
        result = func(*args, **kwargs)  # 将参数原封不动传给原函数
        return result
    return wrapper

@decorator_with_args
def greet(name):
    print(f"Hello, {name}!")

greet("World")

6.3 带参数的装饰器

如果要让装饰器本身也能接收参数,就需要再嵌套一层函数。

def repeat(num_times): # 装饰器工厂,接收参数
    def decorator_repeat(func): # 真正的装饰器
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                result = func(*args, **kwargs)
            return result # 通常返回最后一次调用的结果
        return wrapper
    return decorator_repeat

@repeat(num_times=3)
def say_hi():
    print("Hi!")

say_hi()
# 输出:
# Hi!
# Hi!
# Hi!

6.4 类装饰器

除了函数,类也可以作为装饰器,只需实现 __call__ 方法。

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs): # 让实例变得可调用
        self.num_calls += 1
        print(f"Call {self.num_calls} of {self.func.__name__}")
        return self.func(*args, **kwargs)

@CountCalls
def example():
    print("This is an example.")

example()
example()
print(f"Function was called {example.num_calls} times.")
# 输出:
# Call 1 of example
# This is an example.
# Call 2 of example
# This is an example.
# Function was called 2 times.

总结

Python 的函数远不止是简单的代码块。从灵活的参数处理,到作为一等对象的特性,再到强大的迭代器、生成器和装饰器,它们共同构成了 Python 简洁而强大的表达能力。熟练运用函数能够加快开发工作的效率,也能在一定程度上提高代码的拓展性,是python中非常实用的功能。


网站公告

今日签到

点亮在社区的每一天
去签到