Python中闭包和装饰器的学习攻略

 更新时间:2026年05月19日 10:09:08   作者:颂love  
Python中的闭包和装饰器是两种非常重要的编程概念,它们都是基于函数的特性,特别是涉及到作用域和函数的嵌套,这篇文章主要介绍了Python中闭包和装饰器的相关资料,需要的朋友可以参考下

一、闭包

(1)作用域

学习闭包前先要回顾一下作用域的知识:作用域一般分为全局作用域和局部作用域,对应使用的就是全局变量和局部变量;

值得注意的是在局部作用域中可以访问全局变量,而全局作用域中是不能访问局部变量的

原因:Python的底层存在一个内存回收空间,用于加快计算机的运行;变量同样需要占用内存,当局部作用域所代表的函数在运行过后,其内部的变量和程序会被Python当作已经使用过的内存进行回收

既然是范围方面的程序就会有解决的方法,当程序中需要在全局作用域实现对局部变量的访问时,就要用到闭包了

(2)闭包的含义

闭包:函数嵌套的前提下,内部的函数使用了外部函数的变量,外部函数又返回了内部函数,这时这个内部函数就是闭包

(3)闭包的构成

如何区分一个程序是否存在闭包,闭包一般有三步构成的条件

1、存在函数的嵌套

2、有内部函数的对于外部函数的引用

3、有外部函数对内部函数进行返回(即return)

这里需要注意的是,闭包引用了外部函数的变量,所以外部函数的变量运行完外部函数之后其内存并没有得到释放,会消耗内存

经典闭包的构成例子:

def outer():
     num = 20
     def inner():
         print(num)
     return inner

f = outer()
f()

1、存在嵌套函数:outer是外部函数,inner是内部函数

2、内部函数inner引用了外部函数outer中的自由变量num

3、外部函数outer返回了内部函数inner的引用

4、当outer()执行完毕后,返回的inner函数依然可以访问并保留对变量num的绑定,形成闭包

(4)闭包实现对外部变量的修改

这里要引用一个新的关键词nonlocal;它是用于声明函数内部修改函数外部的变量,这个变量不是全局变量

它和global关键字不同就在于global在函数内部声明变量,但这个变量是全局变量

二者在实际的使用是相似的,只是使用的场景和作用不同

闭包实现修改的案例:

def outer():
     res = 20

     def inner(num):
         nonlocal res
         res += num
         print(res)
     return inner

f = outer()
f(1)
f(2)

res作为外部函数的局部变量,num作为内部函数的变量;res+=num就能直接修改res变量,再打印res引用外部函数变量,outer()再返回内部函数inner形成闭包,最后全局使用外部函数,可以看到这时的f(1)和f(2)中res发生了变化,而且是递进改变的

二、装饰器

(1)什么是装饰器

装饰器:在不改变现有函数代码函数调用的前提下,实现给函数增加额外的功能

装饰器本质上也是一个闭包函数

(2)装饰器的定义

def register(fn):
    def inner():
        print('开始注册')
        fn()
    return inner

@register
def login():
    print('登录成功')

login()

register就是一个装饰器函数,接收函数fn为参数;

@register语法就是将装饰器应用于login函数中

调用login时其实是调用了装饰器register中的inner函数,所以先打印开始注册,然后打印登录成功

效果如下:

(3)装饰器的简单使用

import time
def get_time(fn):
    def inner():
        start = time.time()
        fn()
        end = time.time()
        print(f"执行时间为:{end - start}s")
    return inner

@get_time
def demo():
    for i in range(1000000):
        print(i)

demo()

这个装饰器功能用于可以计算下面demo()函数运行完的执行时间,感兴趣可以深入了解一下

(4)装饰器的形式(了解即可)

带参数的装饰器

def log(fn):
    def inner(*args, **kwargs):
        fn(*args, **kwargs)
    return  inner

@log
def demo_1(*args, **kwargs):
    res = 0
    for i in args:
        res += i

    for i in kwargs.values():
        res += i
    print(res)

demo_1(10, 20, a=30, b=40)

关于不定长参数,在之前的Python学习中已经了解了,这里不多阐述

带返回的装饰器

def log(fn):
    def inner(*args, **kwargs):
        return fn(*args, **kwargs)
    return inner

@log
def demo_1(a, b):
    res = a - b
    return res

print(demo_1(20,10))

通用装饰器

def log(fn):
    def inner(*args, **kwargs):
        return fn(*args, **kwargs)
    return inner

@log
def demo_1(a, b):
    res = a + b
    return res

print(demo_1(20,10))

@log
def demo_2(a, b, c):
    res = a + b + c
    return res
print(demo_2(20,10,5))

一般装饰器形式以这个为准

可以看到装饰器的形式一般都大差不差,按照闭包的形式遵循一定的规则,然后调用函数即可

(5)装饰器的扩展(了解)

使用装饰器传递参数

基本语法:

def 装饰器名(形参):
    #代码
@装饰器名('参数')
def 被装饰函数():
    #代码

代码:

def log(flag):
    def f1(fn):
        def inner(*args, **kwargs):
            if flag == '+':
                print("正进行加法运算")
            elif flag == '-':
                print("正进行减法运算")
            return fn(*args, **kwargs)
        return inner
    return f1

@log('+')
def demo_1(a, b):
    res = a + b
    return res

@log('-')
def demo_2(a, b):
    res = a - b
    return res

print(demo_1(20,10))
print(demo_2(100,10))

效果如下:

类装饰器

基本语法:

class 类装饰器():
    #代码

@类装饰器名称
def 函数():
    #代码

代码:

class Check():
    def __init__(self, fn):
        self.__fn = fn

    def __call__(self, *args, **kwargs):
        print("开始检查")
        self.__fn(*args, **kwargs)

@Check
def comment():
    print("正在检查")

comment()

效果如下:

其实就是在装饰器的基础上用到了类的方法

总结

到此这篇关于Python中闭包和装饰器学习攻略的文章就介绍到这了,更多相关Python闭包和装饰器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python使用自带的base64库进行base64编码和解码

    Python使用自带的base64库进行base64编码和解码

    在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使用Python的base64库进行Base64编码和解码,需要的朋友可以参考下
    2025-04-04
  • python中的正则表达式,贪婪匹配与非贪婪匹配方式

    python中的正则表达式,贪婪匹配与非贪婪匹配方式

    这篇文章主要介绍了python中的正则表达式,贪婪匹配与非贪婪匹配方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • 轻松掌握Python爬虫,从入门到精通

    轻松掌握Python爬虫,从入门到精通

    Python爬虫学习完整版来了!想成为一名爬虫高手,掌握数据采集的技能吗?这份指南将带你从零开始,一步步掌握Python爬虫的各种技巧,让你轻松获取海量数据,需要的朋友可以参考下
    2024-03-03
  • 深入解析Python编程中的else块的隐藏用法

    深入解析Python编程中的else块的隐藏用法

    在 Python 的世界里,if 和 else 通常被视为基础搭档,本文深入解析了Python中else块的隐藏用法,突破了传统if-else的局限,感兴趣的小伙伴可以参考下
    2026-05-05
  • Python列表1~n输出步长为3的分组实例

    Python列表1~n输出步长为3的分组实例

    这篇文章主要介绍了Python列表1~n输出步长为3的分组实例,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • Python中operator模块的操作符使用示例总结

    Python中operator模块的操作符使用示例总结

    operator模块中包含了Python的各种内置操作符,诸如逻辑、比较、计算等,这里我们针对一些常用的操作符来作一个Python中operator模块的操作符使用示例总结:
    2016-06-06
  • Python中atexit模块的基本使用示例

    Python中atexit模块的基本使用示例

    这篇文章主要介绍了Python中atexit模块的基本使用示例,示例代码基于Python2.x版本,注意其和Python3的兼容性,需要的朋友可以参考下
    2015-07-07
  • 5款实用的python 工具推荐

    5款实用的python 工具推荐

    工欲善其事必先利其器,一个好的工具能让起到事半功倍的效果,Python 社区提供了足够多的优秀工具来帮助开发者更方便的实现某些想法,下面这几个工具给我的工作也带来了很多便利,推荐给追求美好事物的你。
    2020-10-10
  • Python中处理CSV文件的核心方法详解

    Python中处理CSV文件的核心方法详解

    本文介绍了Python标准库csv模块的基本功能和使用方法,包括读取、写入、处理带标题行的CSV文件,以及自定义分隔符和引用符,通过示例和代码优化建议,帮助读者更好地理解和应用CSV文件处理,需要的朋友可以参考下
    2026-03-03
  • Python通过paramiko远程下载Linux服务器上的文件实例

    Python通过paramiko远程下载Linux服务器上的文件实例

    今天小编就为大家分享一篇Python通过paramiko远程下载Linux服务器上的文件实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12

最新评论