python 装饰器(2)调用过程,闭包

一.闭包

闭包函数:声明在一个函数中的函数,叫做闭包函数。

闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

想在全局情况下调用“全局函数”内部定义的函数,就必须令该全局函数返回“内部函数”的内存地址,然后将该内存地址赋值给一个变量,通过调用这个变量来实现“全局调用内部函数”,而此时,这个“内部的函数”就称为“闭包”


# f2即为闭包

def f1():
    n=999
    def f2():
        print(n)
    
    return f2

result = f1()
result()

# f2即为闭包

闭包的作用

  • 定义:闭包就是能够读取外部函数内的变量的函数。(前面已经讲解过)
  • 作用1:闭包是将外层函数内的局部变量和外层函数的外部连接起来的一座桥梁。
  • 作用2:将外层函数的变量持久地保存在内存中。
  • 参考:Python闭包(Closure)详解 - 知乎

二.python中的装饰器

#!/usr/bin/python
import time
 
def outter(func):
	def inner(*args,**kwargs):
		start_time = time.time()
		re = func(args[0])
		end_time = time.time()
		spend_time = end_time - start_time
		return({'spend_time':spend_time,'result':re})
	return inner
 
@outter          #等价于test = outter(test)
def test(x):
	time.sleep(5)
	return 'test'+str(x)
 
x = test(2)      
print(x)
 
》》》{'spend_time': 5.004472970962524, 'result': 'test2'}

因为:test  = outter(test)   

所以:test(2)  = outter(test)(2)

所以当装饰器要带参数时,装饰器定时时需要再加一层外部函数 成为三层嵌套函数

装饰器运行时间:

被装饰器装饰的函数名即使没有被调用(因为有@xxx,会触发运行装饰器),(装饰器工厂函数)定义装饰器的代码已经运行了(最内部的那个函数并没有运行)(把被装饰的原函数引用赋值给了装饰器内部的那个函数名),当下边通过该函数名调用时,会调用到装饰器内部的那个函数()

三层方法示例


def logging_function_doc(logger):
    """记录被调用方法的 doc"""

    def outter(func):
        @wraps(func)
        def inner(*args, **kwargs):
            if func.__doc__: logger.info("doc: " + func.__doc__)
            re = func(*args, **kwargs)
            return re

        return inner

    return outter


调用:

@logging_function_doc(logger_obj)
def test_1(p1,p2):
    print('test')
    return 1

通过使用方式可以看出,生效原理与上面二层方法一致 只是多传入参数可供内部方法使用,@logging_function_doc(logger_obj)返回了outter方法,

三.使用小技巧

3.1  wraps在装饰器中的作用

Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring。

不加wraps:

# -*- coding=utf-8 -*- 
from functools import wraps   
def my_decorator(func):
    def wrapper(*args, **kwargs):
        '''decorator'''
        print('Calling decorated function...')
        return func(*args, **kwargs)
    return wrapper  
 
@my_decorator 
def example():
    """Docstring""" 
    print('Called example function')
print(example.__name__, example.__doc__)

>>>
('wrapper', 'decorator')

加wraps:

# -*- coding=utf-8 -*- 
from functools import wraps   
def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        '''decorator'''
        print('Calling decorated function...')
        return func(*args, **kwargs)
    return wrapper  
 
@my_decorator 
def example():
    """Docstring""" 
    print('Called example function')
print(example.__name__, example.__doc__)

>>
('example', 'Docstring')

tips:

__name__: 执行当前文件时__name__ = ‘__main__’;被调用时:__name__ = 模块名

__doc__: 当前 文件/类/函数 的描述

参考:

Python闭包(Closure)详解 - 知乎

闭包,看这一篇就够了——带你看透闭包的本质,百发百中_羊二哥的博客-CSDN博客_闭包

Python装饰器的调用过程 - 江湖乄夜雨 - 博客园

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值