D11 闭包、装饰器

1、闭包

  参考 http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html 阮一峰网络日志

  闭包概念:

  闭包就是能够从外部读取目标函数内部变量的函数。在一些编程语言中,只有函数内部的子函数才能读取局部变量,

  因此可以把闭包简单理解成"定义在一个函数(目标函数)内部的函数(闭包函数)"。

  所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

  关于判断是否是闭包:

  如果此函数拥有自由变量,那么就可以侧面证明其是否是闭包函数了。

def wrapper():
    a = 1
    def inner():
        b = 2
        print('使用函数内部变量a:',a)
    return inner
ret = wrapper()
ret()

# 函数名.__code__.co_freevars 查看函数的自由变量
print(ret.__code__.co_freevars)

# 函数名.__code__.co_varnames 查看函数的局部变量
print(ret.__code__.co_varnames)

# 函数名.__closure__ 获取具体的自由变量对象,也就是cell对象。
print(ret.__closure__)

# cell_contents 自由变量具体的值
print(ret.__closure__[0].cell_contents)

运行结果:
使用函数内部变量a: 1
('a',)
('b',)
(<cell at 0x00000000006BABE8: int object at 0x000007FEE3E77100>,)
1
View Code

  闭包用途:

  闭包可以用在许多地方。它的最大用处有两个。

  一个是前面提到的可以读取目标函数内部的变量(装饰器),另一个就是让这些变量的值始终保持在内存中。

  (注意:由于闭包会使得目标函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,

  可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。)

 

2、装饰器

def wrapper(func):
    def inner(*args, **kwargs):
        """装饰器inner函数的注释部分"""
        """原函数func执行前的操作"""
        ret = func(*args, **kwargs)
        """原函数func执行后的操作"""
        return ret
    return inner

  什么是装饰器?从字面意思来分析,先说装饰,什么是装饰? 装饰就是添加新的,比如你家刚买的房子,下一步就是按照自己的喜欢的方式设计,进行装修,装饰,地板,墙面,家电等等。什么是器?器就是工具,也是功能,那装饰器就好理解了:就是添加新的功能。

  比如我现在不会飞,怎么才能让我会飞?给我加一个翅膀,我就能飞了。那么你给我加一个翅膀,它会改变我原来的行为么?我之前的吃喝拉撒睡等生活方式都不会改变。它就是在我原来的基础上,添加了一个新的功能。

  今天我们讲的装饰器(装修,翅膀)是以功能为导向的,就是一个函数。

  被装饰的对象:比如毛坯房,我本人,其实也是一个函数。

  所以装饰器最终最完美的定义就是:在不改变原被装饰的函数的源代码以及调用方式下,为其添加额外的功能。

  参考  https://www.cnblogs.com/jin-xin/articles/10871410.html 太白老师讲装饰器

 

  func.__name__   此函数的函数名字(字符串)  注意:前后都是 两个下划线。
  func.__doc__    此函数的注释文档。
def wrapper(func):
    def inner(*args, **kwargs):
        """装饰器inner函数的注释部分"""
        """原函数func执行前的操作"""
        ret = func(*args, **kwargs)
        """原函数func执行后的操作"""
        return ret
    return inner

@wrapper
def func():
    """原函数func的注释部分"""
    print('我是原函数func')
func()
print('--------')
print(func.__name__, type(func.__name__))
print(func.__doc__)

执行结果:
我是原函数func
--------
inner <class 'str'>
装饰器inner函数的注释部分
View Code

  恢复装饰器装饰后的原函数名的方法:

  1.利用func.__name__

def wrapper(func):
    def inner(*args, **kwargs):
        """装饰器inner函数的注释部分"""
        """原函数func执行前的操作"""
        ret = func(*args, **kwargs)
        """原函数func执行后的操作"""
        return ret
    inner.__name__ = func.__name__
    inner.__doc__ = func.__doc__
    return inner

@wrapper
def func():
    """原函数func的注释部分"""
    print('我是原函数func')
func()
print('--------')
print(func.__name__, type(func.__name__))
print(func.__doc__)

执行结果:
我是原函数func
--------
func <class 'str'>
原函数func的注释部分
View Code

  2.利用functool模块的warp装饰器

import functools
def wrapper(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        """装饰器inner函数的注释部分"""
        """原函数func执行前的操作"""
        ret = func(*args, **kwargs)
        """原函数func执行后的操作"""
        return ret
    return inner

@wrapper
def func():
    """原函数func的注释部分"""
    print('我是原函数func')
func()
print('--------')
print(func.__name__, type(func.__name__))
print(func.__doc__)

执行结果:
我是原函数func
--------
func <class 'str'>
原函数func的注释部分
View Code

 

01-08 22:53