Python——嵌套函数、闭包、装饰器和lambda匿名函数

2024-08-26 20:28

本文主要是介绍Python——嵌套函数、闭包、装饰器和lambda匿名函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

嵌套函数

Python中的嵌套函数是指在一个函数内部定义的另一个函数。这种结构允许内部函数访问外部函数的作用域(包括参数和局部变量),即使外部函数已经执行完毕。嵌套函数是Python闭包(Closure)的基础,因为闭包就是那些引用了其外部函数作用域中变量的内部函数。

嵌套函数的基本结构

def outer_function(outer_arg):  def inner_function(inner_arg):  # 这里可以访问 outer_arg  print(f"Outer: {outer_arg}, Inner: {inner_arg}")  # 可以选择性地返回内部函数,或者在其他地方调用它  inner_function(5)  # 直接在外部函数中调用内部函数  return inner_function  # 返回内部函数,创建闭包  # 调用外部函数  
result = outer_function(10)  
# 现在result是一个闭包,因为它引用了outer_function的局部变量  
result(20)  # 调用闭包,输出 Outer: 10, Inner: 20

嵌套函数的作用

  1. 封装:嵌套函数提供了一种封装代码的方式,使得内部函数只能被外部函数访问(如果外部函数不返回内部函数的话)。这有助于隐藏实现细节,只暴露必要的接口。

  2. 闭包:如上所述,当外部函数返回内部函数时,就创建了一个闭包。闭包可以记住并访问其外部函数的局部变量,即使外部函数已经执行完毕。

  3. 装饰器:Python的装饰器通常是通过嵌套函数实现的。装饰器允许我们在不修改原有函数代码的情况下,给函数添加新的功能。

  4. 函数工厂:嵌套函数可以用来创建具有特定行为的函数。外部函数可以接收参数,这些参数随后被用来定义内部函数的行为。然后,外部函数返回这个内部函数,这样我们就得到了一个“函数工厂”。

注意事项

  • 嵌套函数可以访问外部函数的局部变量,但不能修改外部函数的局部变量(除非这些变量是可变的,如列表或字典)。
  • 嵌套函数可以访问外部函数的参数。
  • 如果外部函数返回了内部函数,那么内部函数将保持对外部函数局部变量的引用,这可能会导致内存使用增加,因为Python的垃圾回收机制不会回收这些变量,直到闭包不再被引用。
  • 嵌套函数提供了一种强大的编程范式,但应谨慎使用,以避免代码过于复杂和难以理解。

闭包

在Python中,闭包(Closure)是一个非常重要的概念,它涉及到函数及其外部作用域(非全局作用域)的变量之间的关系。简单来说,闭包是一个函数值,它引用了其外部作用域中的变量。即使外部函数已经执行完毕,闭包中的这些变量依然可以被访问和修改。

闭包通常包含两个部分:

  1. 函数:一个内部函数,它引用了外部函数的局部变量。
  2. 这些局部变量的环境:即使外部函数已经执行完毕,闭包依然可以访问这些局部变量。

闭包的创建

闭包通常通过嵌套函数来实现。外部函数定义了局部变量,内部函数(闭包)则引用了这些局部变量。当外部函数返回内部函数时,就创建了一个闭包。

示例

下面是一个简单的闭包示例:

def outer_function(text):  def inner_function():  print(text)  return inner_function  # 创建闭包  
my_closure = outer_function("Hello, World!")  # 调用闭包  
my_closure()  # 输出: Hello, World!

在这个例子中,outer_function 是一个外部函数,它定义了一个局部变量 textinner_function 是一个内部函数,它引用了外部函数的局部变量 text。当 outer_function 被调用时,它返回了 inner_function,此时 inner_function 就是一个闭包,因为它引用了外部函数的局部变量 text,即使 outer_function 已经执行完毕。

闭包的应用

闭包在Python中有很多应用,比如:

  • 数据封装:通过闭包,可以隐藏数据,只提供操作数据的接口。
  • 装饰器:Python中的装饰器本质上就是闭包的一种应用。
  • 回调函数:闭包可以作为回调函数传递给其他函数,同时携带一些额外的信息。

注意事项

  • 闭包中的变量是延迟绑定的,这意味着闭包中的变量是在闭包被调用时查找的,而不是在闭包定义时。
  • 闭包可能会导致内存泄漏,因为闭包中的变量会一直存在,直到闭包不再被引用。

闭包是Python中一个非常强大且灵活的特性,它允许我们编写更加模块化和可重用的代码。

装饰器

ython的装饰器(Decorator)是一个非常强大且灵活的工具,它允许你在不修改原有函数或类定义的情况下,给函数或方法添加新的功能。装饰器本质上是一个函数,这个函数接收一个函数作为参数并返回一个新的函数。

装饰器的基本用法

  1. 定义一个装饰器函数:这个函数接收一个函数作为参数,并返回一个新的函数。
  2. 在新函数中调用原函数:可以在调用前后添加新的功能。
  3. 使用@符号将装饰器应用于目标函数

示例

下面是一个简单的装饰器示例,它计算并打印了被装饰函数的执行时间。

import time  def timer(func):  """装饰器,计算函数执行时间"""  def wrapper(*args, **kwargs):  start_time = time.time()  result = func(*args, **kwargs)  end_time = time.time()  print(f"{func.__name__} 执行了 {end_time - start_time:.6f} 秒")  return result  return wrapper  @timer  
'''等价于 test_function = timer(test_function)'''def test_function():  """一个示例函数,模拟一些操作"""  time.sleep(1)  # 模拟耗时操作  return "完成"  # 调用被装饰的函数  
result = test_function()  
print(result)#输出将是
test_function 执行了 1.00xxxx 秒  
完成

装饰器的进阶用法

  • 带参数的装饰器:如果装饰器本身需要参数,可以创建一个返回装饰器的高阶函数。
  • 多个装饰器:一个函数可以被多个装饰器装饰,Python会从下往上(从里到外)执行装饰器。
  • 装饰器类:装饰器不仅可以是函数,还可以是类。类的__call__方法会在实例被当作函数调用时执行。

带参数的装饰器示例

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(3)  
def greet(name):  print(f"Hello {name}!")  greet("Alice")#输出将是
Hello Alice!  
Hello Alice!  
Hello Alice!

在这个例子中,repeat 是一个高阶函数,它接收一个参数 num_times 并返回一个装饰器 decorator_repeat。这个装饰器则像之前一样工作,但它会基于 num_times 参数重复执行函数。

@wraps装饰器

Python的@wraps装饰器是functools模块中的一个非常有用的工具,它用于在创建装饰器时帮助保留被装饰函数的元信息(如名称、文档字符串、注解等)。默认情况下,当你使用装饰器包装一个函数时,原始函数的__name____doc__等属性会被装饰器函数的相应属性所覆盖。这可能会导致调试困难,因为日志和错误消息中显示的函数名将是装饰器的名称,而不是原始函数的名称。此外,如果原始函数有文档字符串,这个文档字符串也会被装饰器的文档字符串(如果有的话)所覆盖。

为了解决这个问题,functools.wraps装饰器被设计用来更新装饰器函数,使其看起来像是被装饰的函数。具体来说,@wraps会将被装饰函数的__name____doc____module____annotations__以及__wrapped__属性复制到装饰器函数上。这样,当装饰器函数被调用时,它就能够以被装饰函数的身份出现,包括在日志、调试和反射中。

下面是一个使用@wraps装饰器的简单示例:

from functools import wraps  def my_decorator(func):  @wraps(func)  def wrapper(*args, **kwargs):  print(f"Something is happening before the function {func.__name__} is called.")  result = func(*args, **kwargs)  print(f"Something is happening after the function {func.__name__} is called.")  return result  return wrapper  @my_decorator  
def say_hello(name):  """Greet the user by name."""  return f"Hello {name}!"  print(say_hello.__name__)  # 输出: say_hello  
print(say_hello.__doc__)   # 输出: Greet the user by name.  # 如果没有使用@wraps,则输出将是wrapper和wrapper的文档字符串(如果有的话)

在这个例子中,my_decorator是一个装饰器,它接受一个函数func作为参数,并返回一个新的函数wrapperwrapper函数在调用func之前和之后执行一些操作。通过使用@wraps(func),我们确保了wrapper函数在运行时表现得就像是func函数一样,包括其名称和文档字符串。这在进行调试和记录日志时特别有用。

结论

Python的装饰器是一个非常强大的工具,它提供了一种优雅的方式来增强或修改函数的功能,而无需修改函数本身的代码。通过装饰器,你可以轻松地添加日志、性能测试、事务处理、缓存、权限校验等横切关注点(cross-cutting concerns)。

lambda匿名函数

Python中的匿名函数是通过lambda关键字来定义的。lambda函数是一种简洁的定义单行最小函数的方法。它通常用于需要函数对象的地方,但又不想正式命名一个函数的场景。lambda函数可以接受任意数量的参数,但只能有一个表达式。

lambda函数的一般语法是:

lambda arguments: expression

这里,arguments是传递给函数的参数(可以是一个或多个),expression是关于这些参数的单个表达式。这个表达式的计算结果就是lambda函数的返回值。

示例

简单的lambda函数

# 定义一个简单的lambda函数,接受两个参数并返回它们的和  
add = lambda x, y: x + y  # 使用这个lambda函数  
result = add(5, 3)  
print(result)  # 输出: 8

与高阶函数结合使用

lambda函数经常与Python中的高阶函数(接受函数作为参数或返回函数的函数)一起使用,比如filter()map(), 和sorted()等。

# 使用lambda函数与map函数结合,将列表中的每个元素乘以2  
numbers = [1, 2, 3, 4, 5]  
doubled = list(map(lambda x: x * 2, numbers))  
print(doubled)  # 输出: [2, 4, 6, 8, 10]  # 使用lambda函数与filter函数结合,过滤出列表中的偶数  
filtered = list(filter(lambda x: x % 2 == 0, numbers))  
print(filtered)  # 输出: [2, 4]  # 使用lambda函数作为sorted函数的key参数,对元组列表按第二个元素排序  
tuples = [(1, 'd'), (3, 'a'), (2, 'b'), (4, 'c')]  
tuples.sort(key=lambda x: x[1])  
print(tuples)  # 输出: [(3, 'a'), (2, 'b'), (4, 'c'), (1, 'd')]

注意事项

  • lambda函数本质上是一个表达式,它产生一个函数对象。
  • lambda函数可以有任意数量的参数,但只能有一个表达式。
  • lambda函数的语法非常紧凑,适合用在需要函数对象的简短代码中。
  • 尽管lambda函数很有用,但过度使用可能会使代码难以阅读和理解。在需要更复杂的逻辑时,定义一个标准的函数通常是更好的选择。

这篇关于Python——嵌套函数、闭包、装饰器和lambda匿名函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1109597

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

hdu1254(嵌套bfs,两次bfs)

/*第一次做这种题感觉很有压力,思路还是有点混乱,总是wa,改了好多次才ac的思路:把箱子的移动当做第一层bfs,队列节点要用到当前箱子坐标(x,y),走的次数step,当前人的weizhi(man_x,man_y),要判断人能否将箱子推到某点时要嵌套第二层bfs(人的移动);代码如下:

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

nudepy,一个有趣的 Python 库!

更多资料获取 📚 个人网站:ipengtao.com 大家好,今天为大家分享一个有趣的 Python 库 - nudepy。 Github地址:https://github.com/hhatto/nude.py 在图像处理和计算机视觉应用中,检测图像中的不适当内容(例如裸露图像)是一个重要的任务。nudepy 是一个基于 Python 的库,专门用于检测图像中的不适当内容。该

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip