python基础2_闭包函数和装饰器

闭 包:

参考学习地址:https://blog.csdn.net/qq_27825451/article/details/84627016
在函数中可以(嵌套)定义另一个函数时,若内部的函数引用了外部的函数的变量,则可能产生闭包
闭包的作用:
1.保存函数的运行环境状态
2. 保存闭包环境内的局部变量
闭包的特征:
1.必须要有函数的嵌套
2. 内层函数一定要用到外层函数中定义的变量(自由变量)
3.闭包函数必须返回内嵌函数
闭包一般模板:

def decorator(c):  #外层函数,产生包装环境——即闭包
    d=200#自由变量区域                 # 包含形参,都是包装环境中的局部变量——即自由变量python
    def wrapper(a,b):  #内层函数
        return (a+b)*c/d
    return wrapper  #返回内层函数
wrapper=decorator(150)      #创建唯一的闭包环境
wrapper(100,300)            #内层函数的调用

内层函数的__closure__属性返回一个元组;
通过wrapper.closure[i].cell_contents 查看第几个自由变量的值,如果闭包函数没有返回wrapper,即外层函数没有返回内层函数,内层函数是没有__closure__属性的。
c ,d 作为局部变量,在函数调用结束后还能够查看到它的值,变量保存

python装饰器

装饰器(Decorators)是Python的⼀个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,。⼤多数初学者不知道在哪⼉使⽤它们,所以我将要分享下,哪些区域⾥装饰器可以让你的代码更简洁。⾸先,让我们讨论下如何写你⾃⼰的装饰器。这可能是最难掌握的概念之⼀。

学习地址:https://blog.csdn.net/qq_27825451/article/details/84396970
就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能
执行顺序:先执行装饰器,在执行装饰下的函数
理解:将装饰器下的函数对象作为装饰器函数的参数进行,如下相当于deco(myfunc)
函数装饰器模板:

def decorator(function):
    def wrapper(*arg,**args)#参数保持与需要装饰的函数参数一致
        #这里就是额外功能代码
        xxx=function()   #执行原函数
        #这里就是额外功能代码
        return xxx  #被装饰的函数有返回时,此处也需要有返回
    return wrapper #需要返回该函数

#装饰器使用:
@decorator
def myfunc(*arg,**args):   #被装饰的函数
    pass
    return yyy  #被装饰的函数有返回
myfunc(*arg,**args)

运行原理:装饰器在包装函数的时候运行外层,在运行被包装函数的时候才运行内层wrapper
(1)在使用@decorator定一个被装饰的函数的时候,就意味着要进入装饰器函数了,C_function=A_Decorator(C_function) 这句话与@定义的是等价的,意味着外层装饰器中的代码运行完了,返回了一个wrapper对象。从被装饰函数的定义跳到外层装饰器的函数体,这称之为第一次跳跃。
(2)然后运行C_function,实际上也就是运行返回的wrapper,会跳入到wrapper内部执行。运行被装饰的函数,跳入到内层的wrapper执行,这称之为第二次跳跃。
(3)在wrapper内部的时候,因为wrapper内部的function实际上就是定义的函数,故而在运行wrapper内部的function函数的时候,又会重新跳跃到被装饰函数的函数体,这称之为第三次跳跃。
(4)当被装饰的函数执行完了,然后再继续回到wrapper内部执行function后面未执行完的部分。

多层装饰器嵌套:
https://blog.csdn.net/qq_27825451/article/details/84635071
多层装饰器定义

def A_Decorator(function):
       pass
def B_Decorator(function)pass
装饰
@A_Decorator
@B_Decorator
def  C_function():
        pass

以上等价于:C_function=A_Decorator(B_Decorator(C_function))
即等价于:
C_C_function=B_Decorator(C_function)
C_function=A_Decorator(C_C_function)

(1)有内外层函数的单个装饰器,装饰一个函数执行顺序例子:

def decoration1(func):
    print('外层---装饰器1:函数执行----前')
    def wrapper():
        print('内层---装饰器1:函数执行----前')
        func()
        print('内层---装饰器1:函数执行----后')
    print('外层---装饰器1:函数执行----后')
    return wrapper

@decoration1
def func():
    print('原有函数的执行')

func()

执行顺序自己理解:
1.需要先按代码顺序执行外层代码
2.再按代码顺序执行内层函数

外层---装饰器1:函数执行----前
外层---装饰器1:函数执行----后
内层---装饰器1:函数执行----前
原有函数的执行
内层---装饰器1:函数执行----

(2)只有内层函数的多个装饰器,装饰一个函数执行顺序例子

def decoration1(func):
    def wrapper():
        print('内层---装饰器1:函数执行----前')
        func()
        print('内层---装饰器1:函数执行----后')
    return wrapper

def decoration2(func):
    def wrapper():
        print('内层---装饰器2:函数执行----前')
        func()
        print('内层---装饰器2:函数执行----后')
    return wrapper

@decoration2
@decoration1
def func():
    print('原有函数的执行')

func()

理解:
装饰器装饰原函数,无非是在两个地方执行,一个是在原函数执行前执行,一个是在原函数后执行
如代码所示:
装饰器装饰顺序如下:装饰器2—>装饰器1—>原函数func()
那内层函数执行顺序就是:

  1. 先分别执行装饰器2,1中原函数func()前面的代码
  2. 执行原函数func()
  3. 分别执行装饰器1,2中原函数func()后面的代码
    ------>所以执行结果是:
内层---装饰器2:函数执行----前
内层---装饰器1:函数执行----前
原有函数的执行
内层---装饰器1:函数执行----后
内层---装饰器2:函数执行----

(3)只有外层函数的多个装饰器,装饰1个函数例子

def decoration1(func):
    print('外层---装饰器1:函数执行----前')
    def wrapper():
        func()
    print('外层---装饰器1:函数执行----后')
    return wrapper
def decoration2(func):
    print('外层---装饰器2:函数执行----前')
    def wrapper():
        func()
    print('外层---装饰器2:函数执行----后')
    return wrapper

@decoration2
@decoration1
def func():
    print('原有函数的执行')

func()

自己理解:

  1. 先执行外层代码,但是外层代码是先执行装饰器1,还是装饰器2?
  2. 因为调用执行整个代码是从原函数func()开始的,所以需要先执行最接近func()函数的装饰器1的外层函数
  3. 再执行装饰“装饰器1”的装饰器2
  4. 最后执行原函数
    ----->所以执行结果是:
外层---装饰器1:函数执行----前
外层---装饰器1:函数执行----后
外层---装饰器2:函数执行----前
外层---装饰器2:函数执行----后
原有函数的执行

(4)有内外层函数的多个装饰器,装饰一个函数

def decoration1(func):
    print('外层---装饰器1:函数执行----前')
    def wrapper():
        print('内层---装饰器1:函数执行----前')
        func()
        print('内层---装饰器1:函数执行----后')
    print('外层---装饰器1:函数执行----后')
    return wrapper
def decoration2(func):
    print('外层---装饰器2:函数执行----前')
    def wrapper():
        print('内层---装饰器2:函数执行----前')
        func()
        print('内层---装饰器2:函数执行----后')
    print('外层---装饰器2:函数执行----后')
    return wrapper

@decoration2
@decoration1
def func():
    print('原有函数的执行')

func()

---->执行结果

外层---装饰器1:函数执行----前
外层---装饰器1:函数执行----后
外层---装饰器2:函数执行----前
外层---装饰器2:函数执行----后
内层---装饰器2:函数执行----前
内层---装饰器1:函数执行----前
原有函数的执行
内层---装饰器1:函数执行----后
内层---装饰器2:函数执行----

装饰器搭配实现:
函数装饰函数,函数装饰类,类装饰函数,类装饰类
注意点:
函数装饰器 装饰一个函数(被装饰的函数有参数,而且具有返回值)
6. 装饰器里的函数(wrapper)参数保持与被装饰的函数(myfunc)参数一致
7. 如果被装饰函数(myfunc)有返回值,那么装饰器里的函数(wrapper)也需要有返回值
函数装饰器 装饰一个类(仅适用于单例模式:某一个例只有一个实例)

类装饰器模板:

class ClassDecorator:        #类装饰器的名称
    def __init__(self,function_or_cls):  #这里相当于是第一层,作用是将需要装饰的类名、或者是函数名传递进来
        #这里可以添加额外信息
        self.cls=cls         #或者是self.function=function,本质是要构造 一个属性
        #这里可以添加额外信息
    def __call__(self,name,age):  #这相当于是第二层的wrapper,参数需要与被装饰的类、被装饰的函数,参数相同
        #这里可以增加额外信息
        s=self.cls(name,age)       #本质是调用原来的函数或者类的构造函数
        #这里可以增加额外信息
        return s                  #返回创建的学生实例s

注意:类装饰器,对象调用__call__是不可或缺
装饰器的作用——两方面
(1)抽离雷同代码,加以重用
(2)为函数添加额外的功能

classmethod 和staticmethod装饰器(目的:利于组织代码),@property属性方法:
学习地址:https://blog.csdn.net/weixin_41010198/article/details/84828022
某个类的方法,使用@staticmethod或@classmethod装饰,就可以不需要实例化,直接类名.方法名()来调用。
实例方法:实例化方法是操作实例化对象时候定义的,一般参数有self,没有这两个装饰器装饰
@staticmethod:静态方法(与类无关,就是独立的逻辑单元)

  1. 不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样
  2. @staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名
  3. 用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系
    classmethod:类方法(是直接对类操作时候定义的)
  4. 不需要self参数,但第一个参数需要是表示自身类的cls参数
  5. @classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,如:cls.类里的方法
  6. 重构类时不必要修改构造函数,只需额外添加要处理的函数,然后使用装饰符 @classmethod 就可以了,如:类中的方法A使用某个参数B前需要处理一下,则可以在类中添加一个类方法C处理(返回处理后的值),然后先调用该类方法d=类名.C(B),再d.A()走下一步
    @property:属性方法(将实例方法封装成一个类属性)
  7. 在实例方法的基础上添加@property装饰器,调用时不需要括号,如A.name
  8. @property修饰的方法必须只有一个self参数,且需要有返回值
  9. @property 新式类中具有三种:(未定义修改和删除默认只读)
    @property获取属性
    @方法名.setter 修改属性
    @方法名.deleter 删除属性
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值