闭包与装饰器

闭包和装饰器

一、闭包

二、装饰器

回到顶部

 

一、闭包

  1.闭包的定义

    闭包是一种高阶函数, 函数名代表函数的引用, 函数名可以作为另一个函数的参数和返回值作用

    • 一个外部函数内定一个内函数
    • 内函数使用外函数的临时变量
    • 外函数返回内函数的引用

  2.闭包的作用

    隐藏功能的实现细节 

    闭包比类更加节省资源

    但是闭包不能完全代替类

  3.注意点

    当在内函数中使用外函数的局部变量时,可直接使用

    当在内函数中修改外函数的局部变量时,需要使用nonlocal声明

二、装饰器

  1.装饰器概述

    功能:在已有函数基础上,在不改变函数代码及调用方式的基础前提下,为函数添加额外的功能

    语法:@xxxx

    装饰器原理:被装饰函数名指向了闭包中的内函数  # func = wrapper(func)

  2.装饰器的几种例子

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang
"""
    根据被装饰函数的定义形式不同(参数返回值)
    可以将装饰器定义成四种
    # 1. 无参 无返回值
    # 2. 有参 无返回值
    # 3. 无参 有返回值
    # 4. 有参 有返回值
"""
# 1. 无参 无返回值
def set_func1(func):
    def inner():
        print("调用前的装饰语句...")
        func()
        print("调用后的装饰语句...")
    return inner

@set_func1
def show1():
    print("show1...")

# 2. 有参 无返回值
def set_func2(func):
    def inner(string):
        print("调用前的装饰语句...")
        func(string)
        print("调用后的装饰语句...")
    return inner

@set_func2
def show2(string):
    print("show2...",  string)

# 3. 无参 有返回值
def set_func3(func):
    def inner():
        print("调用前的装饰语句...")
        res =  func()
        print("调用后的装饰语句...")
        return res
    return inner

@set_func3
def show3():
    return "show3..."

# 4. 有参 有返回值
def set_func4(func):
    def inner(string, n):
        print("调用前的装饰语句...")
        res =  func(string, n)
        print("调用后的装饰语句...")
        return res
    return inner

@set_func4
def show4(string, n):
    return "show4..." + string + str(n)

if __name__ == '__main__':
    # show1()
    # show2('hello world')
    # print(show3())
    print(show4('哈哈', 666))
闭包实现装饰器
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang
"""
    根据被装饰函数的定义形式不同(参数返回值)
    可以将装饰器定义成四种
"""
# def set_func(func):
#     def inner(*args, **kwargs):
#         print("装饰语句1...")
#         res = func(*args, **kwargs)
#         print("装饰语句2...")
#         return res
#     return inner

# 使用通用装饰器实现计算时间的功能
import time
# 定义一个外函数,实现用作装饰器的闭包
def set_func(func):
    def inner(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print("公用 %.2f 秒" % (end - start))
        return res
    return inner

@set_func
def show1():
    print("show1...")

@set_func
def show2(string):
    print("show2...",  string)

@set_func
def show3():
    return "show3..."

@set_func
def show4(string, n):
    return "show4..." + string + str(n)

@set_func
def show5(n1, n2, n3):
    return n1 + n2 + n3

if __name__ == '__main__':
    show1()
    show2('hello world')
    print(show3())
    print(show4('哈哈', 666))
    print(show5(1,2,3))
通用闭包实现装饰器
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang
"""
    使用类来实现来实现装饰器
"""
# 实现装饰器类
# 实现两个方法
# init方法,用来接收被装饰函数的引用
# call方法, 用让被装饰函数名调用时, 可以执行, 因为使用类装饰器后
# 被装饰函数就不在指向原函数对象, 而是指向类的实例对象
import time
class CountTime(object):
    def __init__(self, func):
        self.__func = func

    # 这个方法才可以被装饰函数执行时, 真正执行的方法, 也就是闭包的内函数
    def __call__(self, *args, **kwargs):
        start = time.time()
        res = self.__func(*args, **kwargs)
        end = time.time()
        print("公用了 %s 秒" % ( end - start))
        return res


@CountTime      # show1 = CountTime(show1)
def show1():
    print("show1...")

@CountTime
def show2(string):
    print("show2...",  string)

@CountTime
def show3():
    return "show3..."

@CountTime
def show4(string, n):
    return "show4..." + string + str(n)

@CountTime
def show5(n1, n2, n3):
    return n1 + n2 + n3

if __name__ == '__main__':
    show1()
    show2('hello world')
    print(show3())
    print(show4('哈哈', 666))
    print(show5(1,2,3))
实现类装饰器

  3.装饰器传参

    概念:在使用过程中,除被装饰器函数外,还需要额外传入数据时,需要进行装饰器传参

    过程步骤:

1. 先执行 set_args('参数') 得到 set_args 函数中的返回值,也就是 set_fun 函数的引用
2. 然后返回的引用和 @ 进行组合,变成装饰器形式 @set_fun , 但是这时 set_fun 函数因为是返回的闭包引用,所以保留了args的参数值
3. 再调用 show 的时候, show 还是指向的 wrapper 函数,但是在这个函数中,可以使用外面两层函数的变量或参数
4. 无论在何时,闭包有几层,最终被装饰的函数永远指向 wrapper 函数

    代码示例:

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang

"""

"""
# 路由表
router_table = {}

# 装饰器
def router(url):
    def set_func(func):
        def inner(*args, **kwargs):
            return func(*args, **kwargs)

        # 实现将 url 作为key, 然后将 被装饰的函数作为值, 保存在路由表
        router_table[url] = inner
        return inner
    return set_func

# 定义页面功能函数
@router('index.html')
def index():
    print('Index...')

@router('center.html')
def center():
    print('Center...')

@router('new.html')
def news():
    print('New...')

def other():
    print("404...")

# 模拟请求的方法
def request_url(url):
    # 根据传入的请求地址, 来找到对应的页面
    print("请求的地址是 %s" % url)
    print("页面的内容是:")

    # 判断地址是否是某一个
    # if url == 'index.html':
    #     index()
    # elif url == 'center.html':
    #     center()
    # elif url == 'news':
    #     news()
    # else:
    #     other()

    if url in router_table:
        func = router_table[url]
    else:
        func = other
    func()

if __name__ == '__main__':
    request_url('index.html')
    request_url('center.html')
    request_url('new.html')
    request_url('aaa.html')
    print(router_table)
posted @ 2018-12-02 20:37  Mr。yang  阅读(246)  评论(0编辑  收藏  举报