闭包,装饰器

#闭包

内层函数对外层函数非全局变量的引用就叫闭包。

判断是不是闭包

函数名.__closur__

返回NONE就不是闭包,返回cell就是闭包

闭包的作用

当执行一个函数时,如果解释器判断此韩式内部存在闭包,这样python就有一个机制,闭包所在的临时名称空间不会随着函数的执行完毕而关闭

def func1():
    name = '老男孩'

    def inner():
        print(name)
    inner()
    print(inner.__closure__)  0x0000000002856E10>

func1()


# <cell at 0x000000000282A768: str object at   闭包

#装饰器

第一个版本

 import  time

'''第一版本,测试函数low'''
# def login():
#     time.sleep(0.3)
#     print('洗洗更健康...')
#
# def timmer():
#     start_time = time.time()
#     login()
#     end_time = time.time()
#     print('此函数的执行时间%s' % (end_time - start_time))
# timmer()

 

改变了我原来执行函数的执行方式,不好

 def login():
    time.sleep(0.3)
    print('洗洗更健康...')
# login()

def register():
    time.sleep(0.4)
    print('洗洗更健康22222...')
# register()
def timmer(f):
    start_time = time.time()
    f()
    end_time = time.time()
    print('此函数的执行时间%s' % (end_time - start_time))

timmer(login)
timmer(register)

 

虽然执行函数的方式已经无限接近于原方式,但是更麻烦了,增加了二步代码,改

 

def login():
    time.sleep(0.3)
    print('洗洗更健康...')
# login()

def timmer(f):
    start_time = time.time()
    f()
    end_time = time.time()
    print('此函数的执行时间%s' % (end_time - start_time))

f1 = login  # 将login函数名给了f1
login = timmer  # 将timmer函数名给了login
login(f1)  # timmer(login)

 

#初级装饰器

 

def login():
    time.sleep(0.3)
    print('洗洗更健康...')
# login()

def timmer(f):  # f = login函数名

    def inner():
        start_time = time.time()
        f()  # login()
        end_time = time.time()
        print('此函数的执行时间%s' % (end_time - start_time))
    return inner

login = timmer(login)  # inner 此login是新变量
login()  # inner()

 

  

 

#简单版装饰器,语法糖

 

def timmer(f):  # f = login函数名
    def inner():
        start_time = time.time()
        f()  # login()
        end_time = time.time()
        print('此函数的执行时间%s' % (end_time - start_time))
    return inner

@timmer  # login = timmer(login)  # inner 此login是新变量   @timmer就是语法糖
def login():
    time.sleep(0.3)
    print('洗洗更健康...')
login()

@timmer  # register = timmer(register)
def register():
    time.sleep(0.2)
    print('洗洗更健康22...')

login()  # inner()

 

 

#被装饰的函数带参数的装饰器

 

def timmer(f):  # f = login函数名
    def inner(*args,**kwargs):  # args (2, 3)
        start_time = time.time()
        f(*args,**kwargs)  # login() *(2, 3) 2,3
        end_time = time.time()
        print('此函数的执行时间%s' % (end_time - start_time))
    return inner

@timmer  # login = timmer(login)  # inner 此login是新变量
def login(a,b):
    print(a,b)
    time.sleep(0.3)
    print('洗洗更健康...')

login(2,3)  # inner(2,3)

 

  

 

#函数带返回值的装饰器(万能装饰器)

 

def timmer(f):  # f = login函数名
    def inner(*args,**kwargs):  # args (2, 3)
        start_time = time.time()
        ret = f(*args,**kwargs)  # login() *(2, 3) 2,3
        end_time = time.time()
        print('此函数的执行时间%s' % (end_time - start_time))
        return ret
    return inner

@timmer  # login = timmer(login)  # inner 此login是新变量
def login(a,b):
    print(a,b)
    time.sleep(0.3)
    print('洗洗更健康...')
    return 666

print(login(2,3))  # inner(2,3)

 

  

 

 

 

def wrapper(f):
def inner(*args,**kwargs):
'''执行被装饰函数之前的操作'''
ret = f(*args,**kwargs)
"""执行被装饰函数之后的操作"""
return ret
return inner

装饰器功能:在不改变原函数的基础上,为原函数增加一些额外的功能,log,登录注册等

 

#函数的有用信息

def login(username, password):
    """
    此函数需要用户名,密码两个参数,完成的是登录的功能。
    :return: True 登录成功。 False登录失败。
    """
    # print(login.__name__)
    # print(login.__doc__)
    print('登录成功...')
    return True

print(login.__name__)
print(login.__doc__)

#输出:login

    此函数需要用户名,密码两个参数,完成的是登录的功能。
    :return: True 登录成功。 False登录失败。

  

def wrapper(f):
    def inner(*args, **kwargs):
        print(f.__name__)
        print(f.__doc__)
        """执行函数之前的操作"""
        ret = f(*args, **kwargs)
        """执行函数之后的操作"""
        return ret
    return inner

@wrapper
def login(username, password):
    """
    此函数需要用户名,密码两个参数,完成的是登录的功能。
    :return: True 登录成功。 False登录失败。
    """
    print('登录成功...')
    return True
login(1, 2)

  引入一个模块

from functools import wraps

def wrapper(f):
    @wraps(f)
    def inner(*args, **kwargs):
        """执行函数之前的操作"""
        ret = f(*args, **kwargs)
        """执行函数之后的操作"""
        return ret
    return inner

@wrapper
def login(username, password):
    """
    此函数需要用户名,密码两个参数,完成的是登录的功能。
    :return: True 登录成功。 False登录失败。
    """
    a = 2
    c = 4
    print('登录成功...')
    return True

print(login.__name__)
print(login.__doc__)

带参数的装饰器

 

import time


def timer_out(flag1):  #falg1 = flag
    def timer(f):
        def inner(*args, **kwargs):
            if flag1:
                start_time = time.time()
                time.sleep(0.3)
                ret = f(*args, **kwargs)
                end_time = time.time()
                print('执行效率%s' % (end_time-start_time))
                return ret
            else:
                ret = f(*args, **kwargs)
                return ret
        return inner
    return timer

flag = True        #如果不想装饰,把TURE改成False

@timer_out(flag)  # 1,步 timer_out(flag) == timer 2,@与timer结合,变成你熟悉的装饰器 @timer
def func1():
    print(111)


@timer_out(flag)
def func2():
    print(222)


@timer_out(flag)
def func3():
    print(333)

func1()
func2()
func3()

#

111
执行效率0.3004300594329834
222
执行效率0.30065345764160156
333
执行效率0.3003878593444824

 

 局部只能引用全局的变量,不能修改,如果要修改,global。

count = 1

def func4():
    count = count + 1
    print(count)

func4()


#报错,coun在局部没有定义
# 子函数只能引用父函数的变量,不能修改,如果要修改,nonlocal。
def func4():

    count = 3
    def inner():
        nonlocal count
        count = count + 1
        print(count)
func4()

多个装饰器装饰一个函数

def wrapper1(func): # func = f函数名
    def inner1():
        print('wrapper1 ,before func')  # 2
        func()
        print('wrapper1 ,after func')  # 4
    return inner1


def wrapper2(func):  # func = inner1
    def inner2():
        print('wrapper2 ,before func')  # 1
        func()  # inner1()
        print('wrapper2 ,after func')  # 5
    return inner2

@wrapper2  # f = wrapper2(f) 里面的f新变量 = inner1 外面的f最新变量 = inner2
@wrapper1  # f = wrapper1(f) 里面的f函数名  外面的f新变量=inner1
def f():
    print('in f')  # 3

f()  # inner2()
'''
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
'''

开放封闭原则:

 

1.对扩展是开放的

 

    为什么要对扩展开放呢?

 

    我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。

 

  2.对修改是封闭的

 

    为什么要对修改封闭呢?

 

    就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。

 

装饰器完美的遵循了这个开放封闭原则。

 

 

 

posted @ 2018-05-15 16:42  huangliang2  阅读(145)  评论(0)    收藏  举报