当前位置: 首页 > 编程笔记 >

深入理解python中的闭包和装饰器

钱和安
2023-03-14
本文向大家介绍深入理解python中的闭包和装饰器,包括了深入理解python中的闭包和装饰器的使用技巧和注意事项,需要的朋友参考一下

python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。

以下说明主要针对 python2.7,其他版本可能存在差异。

也许直接看定义并不太能明白,下面我们先来看一下什么叫做内部函数:

def wai_hanshu(canshu_1):

  def nei_hanshu(canshu_2): # 我在函数内部有定义了一个函数
    return canshu_1*canshu_2

  return nei_hanshu  # 我将内部函数返回出去

a = wai_hanshu(123)   # 此时 canshu_1 = 123
print a
print a(321)  # canshu_2 = 321

我在函数里面有嵌套了一个函数,当我向外层函数传递一变量的之后,并赋值给 a ,我们发现 a 变成了一个函数对象,而我再次为这个函数对象传参的时候,又获得了内部函数的返回值。我们知道,按照作用域的原则来说,我们在全局作用域是不能访问局部作用域的。但是,这里通过讨巧的方法访问到了内部函数。。

下面我们继续看一个例子:

def wai_hanshu():
  a = []
  def nei_hanshu(canshu):
    a.append(canshu)
    return a

  return nei_hanshu

a = wai_hanshu()
print a(123)
print a(321)

可以看出函数位于外部函数中的列表 a 竟然改变了。要知道为什么,就要先知道什么是python的命名空间,而命名空间就是作用域表现的原因,这里我简要说明一下。

引入命名空间的主要原因还是为了避免变量冲突,因为python中的模块众多,模块中又有函数,类等,它们都要使用到变量。但如果每次都要注意不和其他变量名冲突,那就太麻烦了,开发人员应该专注于自己的问题,而不是考虑别人写的程序中用到了什么变量,所以python引入了命名空间。命名空间分为模块层,模块内又分为全局作用域和局部作用域,用一个图来表示的话:

模块之间命名空间不同,而里面还有全局作用域和局部作用域,局部作用域之前还能嵌套,这样就能保证变量名不冲突了。这里顺便补充一下,可以通过 __name__ 属性获取命名空间的名字:

主文件的命名空间是叫做 '__main__',而模块的命名空间就是模块名。

作用域的诞生,是因为当python在寻找一个变量的时候,首先会在当前的命名空间中寻找,如果当前命名空间中没有,就到上一级的命名空间中找,以此类推,如果最后都没找到,则触发变量没找到的异常。

我们之前一直说:全局作用域无法访问局部作用域,而局部作用域能够访问全局作用域就这这个原因。而当我在局部作用域创建了一个和外面同名的变量时,python在找这个变量的时候首先会在当前作用域中找,找到了,就不继续往上一级找了。

在早期的python版本时,局部作用域是不能访问其他的局部作用域的,只能访问全局的,而现在的版本都是依次向上一级找,这里就提一下。

也就是因为这个特性,我们可以在内部函数中访问外部函数中的变量,这也就是所谓的闭包了。

注意:这里要做好对象之间的区分,例如:

def wai_hanshu():
  a = []
  def nei_hanshu(canshu):
    a.append(canshu)
    return a

  return nei_hanshu

a = wai_hanshu()  # 我创建了一个对象
b = wai_hanshu()  # 我又创建了一个对象
print a
print b
print a(123)
print b(321)

在这里,我们虽然都是操作 wai_hanshu 中的变量,但是 a 和 b 完全是两个对象,它们所在的内存空间也是不同的,所以里面的数据也是独立的。要注意不要搞混。

装饰器

其实装饰器就是在闭包的基础上多进行了几步,看代码:

def zsq(func): # 装饰函数
  def nei():
    print '我在传入的函数执行之前做一些操作'
    func() # 执行函数
    print '我在目标函数执行后再做一些事情'
  return nei

def login():  # 被装饰函数
  print '我进行了登录功能'

login = zsq(login)  # 我将被装饰的函数传入装饰函数中,并覆盖了原函数的入口

login()   # 此时执行的就是被装饰后的函数了

在看这段代码的时候,要知道几件事:

1.函数的参数传递的其实是引用,而不是值。

2.函数名也是一个变量,所以可以重新赋值。

3.赋值操作的时候,先执行等号右边的。

只有明白了上面这些事之后,再结合一下代码,应该就能明白什么是装饰器了。所谓装饰器就是在闭包的基础上传递了一个函数,然后覆盖原来函数的执行入口,以后调用这个函数的时候,就可以额外实现一些功能了。装饰器的存在主要是为了不修改原函数的代码,也不修改其他调用这个函数的代码,就能实现功能的拓展。

而python觉得让你每次都进行重命名操作实在太不方便,于是就给出了一个便利的写法:

def zsq(func):
  def nei():
    print '我在传入的函数执行之前做一些操作'
    func() # 执行函数
    print '我在目标函数执行后再做一些事情'
  return nei

@zsq  # 自动将其下面的函数作为参数传到装饰函数中去
def login():
  print '我进行了登录功能'


login()

这些小便利也叫做python的语法糖,你可能在很多地方见过这个说法。

带参数的装饰器:

def zsq(a):
  print '我是装饰器的参数', a
  def nei(func):
    print '我在传入的函数执行之前做一些操作'
    func() # 执行函数
    print '我在目标函数执行后再做一些事情'
  return nei


@zsq('123')
def login():
  print '我进行了登录功能'

相当于: login = zsq(123)(login) ,所以在这里没有调用就执行了。

装饰器的嵌套:

这里就不完整写个例子了:

@deco1(deco_arg) 
@deco2 
def func(): 
  pass

相当于: func = deco1(deco_arg)(deco2(func)) 

也就是从上到下的嵌套了。

关于闭包和装饰器就先讲到这里,以后有需要再补充。

以上这篇深入理解python中的闭包和装饰器就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文向大家介绍深入理解Python中装饰器的用法,包括了深入理解Python中装饰器的用法的使用技巧和注意事项,需要的朋友参考一下 因为函数或类都是对象,它们也能被四处传递。它们又是可变对象,可以被更改。在函数或类对象创建后但绑定到名字前更改之的行为为装饰(decorator)。 “装饰器”后隐藏了两种意思——一是函数起了装饰作用,例如,执行真正的工作,另一个是依附于装饰器语法的表达式,例如,at

  • 本文向大家介绍详解Python装饰器由浅入深,包括了详解Python装饰器由浅入深的使用技巧和注意事项,需要的朋友参考一下 装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码。装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们以装饰函数为例子介绍其用法。要理解在Python中装饰器的原理,需要一步一步

  • 装饰器(decorator)是一种高级Python语法。装饰器可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果。相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。 装饰器最早在Python 2.5中出现,它最初被用于加工函数和方法这样的可调用对象(ca

  • 本文向大家介绍Python闭包和装饰器用法实例详解,包括了Python闭包和装饰器用法实例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python闭包和装饰器用法。分享给大家供大家参考,具体如下: Python的装饰器的英文名叫Decorator,作用是完成对一些模块的修饰。所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装

  • 本文向大家介绍Python闭包与装饰器原理及实例解析,包括了Python闭包与装饰器原理及实例解析的使用技巧和注意事项,需要的朋友参考一下 一、闭包 闭包相当于函数中,嵌套另一个函数,并返回。代码如下: 二、装饰器 装饰器:把函数test当成变量传入装饰函数deco --> 执行了装饰操作后,变量传回给了函数test()。比如装饰器效果是test = test-1,test函数经过deco装饰后,

  • 本文向大家介绍实例详解Python装饰器与闭包,包括了实例详解Python装饰器与闭包的使用技巧和注意事项,需要的朋友参考一下 闭包是Python装饰器的基础。要理解闭包,先要了解Python中的变量作用域规则。 变量作用域规则 首先,在函数中是能访问全局变量的: 然后,在一个嵌套函数中,内层函数能够访问在外层函数中定义的局部变量: 闭包 上面的嵌套函数就是闭包。 闭包 是指延伸了作用域的函数,在