首页 > 其他 > 详细

函数的闭包与装饰器

时间:2019-11-11 19:06:29      阅读:85      评论:0      收藏:0      [点我收藏+]

一、函数对象

  python一切皆对象,所以函数也是对象,也可以当做数据被处理

  • 函数可以被引用
  • 可以当作参数传递
  • 返回值可以是函数
  • 可以当作容器类型的元素

二、函数闭包

Python 支持函数式编程,所以存在闭包,闭包是由函数及其相关的引?环境组合?成的实体 , ?句话: 闭包 = 函数+引?环境,函数式编程中,当内嵌函数体内引?到体外的变量 时, 将会连同这些变量(引?环境)和内嵌函数体, ?块打包成?个整体返回。

如果在一个函数的内部定义了另一个函数,外部的我们叫它为外函数,内部的我们叫它内函数,那么闭包就是在一个外函数中定义了一个内函数,内函数里引用了外函数的临时变量,并且外函数的返回值是内函数的引用。

x = 1
def out_func():
    x =2
    def in_func():
        print(in the in_func, x)
    return in_func

f = out_func()
f()
# 通过调用__closure__属性查看闭包所包裹的外部变量
print(f.__closure__, f.__closure__[0].cell_contents)

""" 
in the in_func 2
(<cell at 0x00A27810: int object at 0x1D9DE320>,) 2
"""

 

 

三、装饰器----闭包的运用

  1 . 什么是装饰器? 

装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

   2 . 装饰器的使用

  • 装饰器的框架   

def ver_fun(func):
    def wrapper(*args, **kwargs): # 引用外部函数变量func
        # 需要增添的功能逻辑
        func() #这里就是将一开始没有装饰的test运行一次
    return wrapper


@ver_fun  # 实际上就相当于 test = ver_fun(test),此时的test就是return回来的wrapper
def test():
    print(hello world!)
test() # 实际上就是wrapper()

 

  • 无惨装饰器 
技术分享图片
mport time


def timmer(func):
    def wrapper():
        start_time = time.time()
        func()
        stop_time = time.time()
        print(函数运行的时间为%s % (stop_time - start_time))
    return wrapper


@timmer
def test():
    time.sleep(2)
    print(执行完毕)

test()

"""
执行完毕
函数运行的时间为2.000253677368164
"""
View Code

              当我们调用test函数时,实际上就是在调用wrapper函数,所以当我们的test函数有参数时,wrapper函数也要带上参数,为了统一,我们一般都会在wrapper函数和func函数上加上*args+**kwargs组合,即上

        述代码可以修改为

技术分享图片
import time


def timmer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        stop_time = time.time()
        print(函数运行的时间为%s % (stop_time - start_time))

    return wrapper


@timmer
def test(name, age):
    time.sleep(2)
    print(执行完毕)


test("jiang", 8)
View Code

 

  • 带参数的装饰器

   是为装饰器提供多样功能选择的实现提供的,实现原理是三层闭包。如当我们需要不同分认证方式时,可以使用有参装饰器

技术分享图片
import os


def file_handle(backend_data, res=None, type=fetch):
    ‘‘‘
    这是一个文件处理的函数,对查找和修改功能中的文件处理部分进行的程序解耦
    :return:
    ‘‘‘
    if type == fetch:
        with open(haproxy.conf, r) as read_f:
            tag = False
            ret = []
            for each_line in read_f:
                if each_line.strip() == backend_data:
                    tag = True
                    continue
                if tag and each_line.startswith(backend):
                    break
                if tag:
                    print(each_line, end=‘‘)
                    ret.append(each_line)
        return ret
    elif type == change:
        with open(haproxy.conf, r) as read_f,                 open(haproxy.conf_new, w) as write_f:
            tag = False
            write_tag = True
            for each_line in read_f:
                if each_line == backend_data:
                    tag = True
                    continue
                if tag and each_line.startswith(backend):
                    tag = False
                if not tag:
                    write_f.write(each_line)
                elif write_tag:
                    for record in res:
                        write_f.write(record)
                    write_tag = False
    os.rename(haproxy.conf, haproxy.conf.bak)
    os.rename(haproxy.conf_new, haproxy.conf)
    os.remove(haproxy.conf.bak)


def fetch(data):
    backend_data = backend %s % data
    return file_handle(backend_data)


def add():
    pass


def change(data):
    ‘‘‘
    这是修改功能,用户传入一个列表,列表第一个元素为原修改数据,第二个元素为修改后的数据
    :param data: 用户输入的列表
    :return:
    ‘‘‘
    # 提取出用户输入数据中的地址
    backend = data[0][backend]
    backend_data = backend %s\n % backend
    # 将用户中的server拼接起来
    old_server_record = %sserver %s %s weight %s maxconn %s\n % (  * 8, data[0][record][server],
                                                                   data[0][record][server],
                                                                   data[0][record][weight],
                                                                   data[0][record][maxconn])

    new_server_record = %sserver %s %s weight %s maxconn %s\n % (  * 8, data[1][record][server],
                                                                   data[1][record][server],
                                                                   data[1][record][weight],
                                                                   data[1][record][maxconn])
    print(用户想要修改的记录是, old_server_record)
    print(用户想要修改后的记录是, new_server_record)
    res = fetch(backend)
    print(res)
    if not res or old_server_record not in res:
        return 用户要修改的数据不存在
    else:
        index = res.index(old_server_record)
        res[index] = new_server_record

    res.insert(0, %s\n % backend_data)
    file_handle(backend_data, res=res, type=change)


def delete():
    pass


if __name__ == __main__:
    msg = ‘‘‘
    weibo:查询
    2:添加
    3:修改
    4:删除
    5:退出
    ‘‘‘

    menu_dic = {weibo: fetch, 2: add, 3: change, 4: delete}

    while True:
        print(msg)
        user_choice = input("请输入选项:").strip()
        if not user_choice: continue
        if user_choice == 5: break

        user_data = input("请输入你想要的数据:").strip()
        if user_choice != weibo:
            user_data = eval(user_data)
        res = menu_dic[user_choice](user_data)
        print(res)
View Code
  • wraps 的使用

   我们这里调用help方法查看一下test函数

print(help(test))

"""
Help on function wrapper in module __main__:

wrapper(*args, **kwargs)

None
"""

可以看到test函数的函数名为wrapper,证明装饰过后的函数函数名和函数的文档搜发生了变化,如果想保留原有函数的属性,除了我们自己手动在装饰器中修改wrapper的__name__和__doc__属性外,我们可

以还调用functools模块提供的装饰器来实现,具体如下:

技术分享图片
import time
from functools import wraps


def timmer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        stop_time = time.time()
        print(函数运行的时间为%s % (stop_time - start_time))

    return wrapper


@timmer
def test(name, age):
    time.sleep(2)
    print(执行完毕)


# test("jiang", 8)
print(help(test))

"""
Help on function test in module __main__:

test(name, age)

None
"""
View Code

 

 

函数的闭包与装饰器

原文:https://www.cnblogs.com/liangweijiang/p/11837432.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!