函数闭包与装饰器

一、闭包

闭包:1,闭:内部的函数

   2,包:包含了对外部函数作用域中变量的应用

外部可以执行内部函数,并且还可以用内部函数作用域中的值

闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

def func():
    n = 1
    def func2():
        '''闭包'''
        print("from func2:",n)
    return func2
f = func()
print(f)
f()

判断闭包函数的方法:__closure__

#判断闭包函数的方法,有cell就是闭包函数,None则不是
def func():
    n = 1
    def func2():
        '''闭包'''
        print("from func2:",n)
    print(func2.__closure__)
    return func2
f = func()
f()

#非闭包函数
n = 1
def func():
    def func2():
        print("from func2:",n)
    print(func2.__closure__)
    return func2
f = func()
f()
判断闭包函数

查看闭包的元素

def func():
    n = 1
    def func2():
        print("from func2:",n)
    print(func2.__closure__)
    return func2
f = func()
f()
print(f.__closure__[0].cell_contents)  #查看闭包元素
__closure__[0].cell_contents

应用领域:延迟计算

from urllib.request import urlopen
# res = urlopen('http://www.baidu.com').read()
# print(res.decode('utf-8'))
def index(url):
    def get():
        return urlopen(url).read()
    return get
baidu = index('http://www.baidu.com')
print(baidu().decode('utf-8'))
print(baidu.__closure__[0].cell_contents) #查看闭包的元素
先用传参,后用闭包
def func():
    money = 1000
    def func1():
        name = 'chris'
        def func2():
            print(name,money)
        return func2
    return func1
f = func()  #拿到func的内存地址
a = f()   #拿到func2的内存地址
a()
闭包嵌套

 二、装饰器

装饰器的功能:在不修改原函数(代码)及其调用方式的情况下对原函数功能进行扩展

装饰器的本质:就是一个闭包函数

简单装饰器:实现函数执行时间

 

import time
def timer(func):
    def inner():
        start_time = time.time()
        func() #timer函数的参数
        stop_time = time.time()
        print('run time is ',stop_time-start_time)
    return inner
def func():
    time.sleep(2)
    print("from func")
func = timer(func)  #拿到的是inner的内存地址
func()

 

第7/8可使用语法糖改进(装饰器)

import time

def timer(func):
    def inner():
        start_time = time.time()
        func()
        stop_time = time.time()
        print('run time is ', stop_time - start_time)

    return inner

@timer  #把整下方的函数当做参数传递,相当于implement=timer(implement)
def implement():   
    time.sleep(2)
    print("from func")
implement()

import time

def timer(func):
    def inner(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        stop_time = time.time()
        print('run time is ', stop_time - start_time)
        return res
    return inner

@timer  #把整下方的函数当做参数传递,相当于implement=timer(implement)
def implement(a):
    time.sleep(2)
    print("from func :%s"%a)
@timer
def implement2(a,b):
    time.sleep(0.1)
    print("from func:",a,b)
implement('abcd')
implement2(3,4)
带参数的装饰器
import time

def timer(func):
    def inner(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        stop_time = time.time()
        print('run time is ', stop_time - start_time)
        return res
    return inner

@timer  #把整下方的函数当做参数传递,相当于implement=timer(implement)
def implement(a):
    time.sleep(0.2)
    print("from func :%s"%a)
    return 'implement over'
# implement('abc')
print(implement('abc'))
带返回值的装饰器

三、开放封闭原则

1,对外部扩展是开放的

2,对内部修改是封闭的

四、装饰器的固定结构

import time
def wrapper(func):  # 装饰器
    def inner(*args, **kwargs):
        '''函数执行之前的内容扩展'''
        ret = func(*args, **kwargs)
         '''函数执行之前的内容扩展'''
        return ret
    return inner

@wrapper  # =====>implement=timmer(implement)
def implement():
    time.sleep(1)
    print('abcd')
implement()
固定格式

五、带参数的装饰器

带参数的装饰器顾名思义就是给装饰器传参

用处:当加了很多装饰器的时候,忽然不想加装饰器了想把装饰器给去掉,但代码比较多,删起来比较麻烦,那么我们可以利用带参数的装饰器去装饰它,这就像一个开关,要的时候调用,不用的时候去掉。给装饰器里面传个参数,那么语法糖也要加括号【eg:@timer()】。在语法糖的括号内传参。我们可以用三层嵌套,弄一个标识位去标识。如下代码:

# 带参数的装饰器:(相当于开关)为了给装饰器传参
# F=True#为True时就把装饰器给加上了
F=False#为False时就把装饰器给去掉了
def outer(flag):
    def wrapper(func):
        def inner(*args,**kwargs):
            if flag:
                print('before')
                ret=func(*args,**kwargs)
                print('after')
            else:
                ret = func(*args, **kwargs)
            return ret
        return inner
    return wrapper

@outer(F)#@wrapper
def hahaha():
    print('hahaha')

@outer(F)
def shuangwaiwai():
    print('shuangwaiwai')

hahaha()
shuangwaiwai()
给装饰器加参数

六、多个装饰器装饰一个函数

import time
user_status = False
def auth(func):
    '''auth.txt内容为{"name":"chris","password":"123"}'''
    file = 'auth.txt'
    with open(file,'r+',encoding='utf-8') as f:
        data = eval(f.read())
        global user_status
        if user_status == False:
            user_name = input('username:').strip()
            pass_word = input('password:').strip()
            if data['name'] == user_name and data['password'] == pass_word:
                print("welcome %s".center(20,'-')%user_name)
                user_status = True
            else:
                print("wrong username or password")
        # else:
        #     print('无需验证')
    return func

def timer(func):
    def inner():
        start_time = time.time()
        func()
        stop_time = time.time()
        print('run time is ',stop_time-start_time)
    return inner

@auth
@timer
def func():
    time.sleep(2)
    print("from func")


func()
'''
@auth和@timer的顺序是先执行 auth里面的认证信息,再执行timer函数中的时间
‘’‘
多个装饰器装饰一个函数
def qqqxing(fun):
    def inner(*args,**kwargs):
        print('in qqxing: before')
        ret = fun(*args,**kwargs)
        print('in qqxing: after')
        return ret
    return inner

def pipixia(fun):
    def inner(*args,**kwargs):
        print('in qqxing: before')
        ret = fun(*args,**kwargs)
        print('in qqxing: after')
        return ret
    return inner
@qqqxing
@pipixia
def dapangxie():
    print('饿了吗')
dapangxie()

'''
@qqqxing和@pipixia的执行顺序:先执行qqqxing里面的 print('in qqxing: before'),然后跳到了pipixia里面的
        print('in qqxing: before')
        ret = fun(*args,**kwargs)
        print('in qqxing: after'),
        完了又回到了qqqxing里面的print('in qqxing: after')。所以就如下面的运行结果截图一样
'''
多个装饰器修饰一个函数

七、统计多少个函数被装饰了的应用

F=False
l = []
def outer(flag):
    def wrapper(func):
        l.append(func)
        def inner(*args,**kwargs):
            if flag:
                print('before')
                ret = func(*args,**kwargs)
                print('after')
            else:
                ret = func(*args, **kwargs)
            return ret
        return inner
    return wrapper

@outer(F)#@wrapper
def hahaha():
    print('hahaha')

@outer(F)
def shuangwaiwai():
    print('shuangwaiwai')

hahaha()
shuangwaiwai()
print(l)
View Code

 

posted on 2018-05-22 16:51  海深深_蓝  阅读(158)  评论(0编辑  收藏  举报

导航