当前位置: 首页 > web >正文

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

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 = 0for num in args:total += numreturn totalresult = 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 * factorreturn multiplierdouble = 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 -= 1print("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:breakprint(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) # 引用了外部变量 messagereturn 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 resultreturn 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 wrapperreturn 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 = funcself.num_calls = 0def __call__(self, *args, **kwargs): # 让实例变得可调用self.num_calls += 1print(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中非常实用的功能。

http://www.xdnf.cn/news/18320.html

相关文章:

  • Java 大视界 -- Java 大数据在智能物流无人配送车路径规划与协同调度中的应用
  • 暴雨中的“天眼”:天通哨兵PS02卫星图传系统筑牢防汛安全网
  • 前端面试题1
  • 边缘智能体:Go编译在医疗IoT设备端运行轻量AI模型(上)
  • Springboot使用Selenium+ChormeDriver在服务器(Linux)端将网页保存为图片或PDF
  • Rust学习笔记(七)|错误处理
  • 0819 使用IP多路复用实现TCP并发服务器
  • 反向代理实现服务器联网
  • Auto-CoT:大型语言模型的自动化思维链提示技术
  • 微服务-08.微服务拆分-拆分商品服务
  • 深度学习环境搭建Windows+ TensorFlow 2.6.0 GPU 版
  • 亚矩阵云手机智能定位:助力Snapchat矩阵账号的本地化内容运营穿透技术
  • Apache IoTDB(4):深度解析时序数据库 IoTDB 在Kubernetes 集群中的部署与实践指南
  • 连接远程服务器上的 jupyter notebook,解放本地电脑
  • VSCode 从安装到精通:下载安装与快捷键全指南
  • 11.第11章 开发环境优化
  • 【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day7
  • Nacos-6--Naco的QUIC协议实现高可用的工作原理
  • 2025年- H98-Lc206--51.N皇后(回溯)--Java版
  • ARM架构下的cache transient allocation hint以及SMMUv2的TRANSIENTCFG配置详解
  • EasyExcel篇
  • OVS:ovn为什么默认选择Geneve作为二层隧道网络协议?
  • 【CV 目标检测】Fast RCNN模型③——模型训练/预测
  • c++最长上升子序列长度
  • 8.18网络编程——基于UDP的TFTP文件传输客户端
  • 力扣32:最长有效括号
  • 如何解决机器翻译的“幻觉“问题(Hallucination)?
  • 博客项目 Spring + Redis + Mysql
  • 深度研究系统、方法与应用的综述
  • android 实现表格效果