闭包函数和装饰器

一、闭包函数

  1.什么是闭包

    定义在函数内部的函数

    内部函数引用了外部函数名称空间作用域的名字

  2.给函数传参的两种方式:

    (1)直接传参

def index1(username):
    print(username)

    (2)闭包

def outter(name):
    # name = 'jason'
    def index():
        print(name)
    return index

  3.作用领域:延迟计算

from urllib.request import urlopen

def index(url):
    def get():
        return urlopen(url).read()
    return get

baidu=index('http://www.baidu.com')
print(baidu().decode('utf-8'))

二、装饰器

  1.什么是装饰器

    给被装饰的对象添加功能的工具,本身是可调用对象

  2.遵循的两个原则:

    (1)不修改被装饰对象的源代码

    (2)不修改被装饰对象的调用方式

  3.为什么要用装饰器

    开放封闭原则:对修改封闭,对扩展开放

  4.装饰器的使用

    时间戳的使用

import time
print(time.time())
# 1562812014.731474 时间戳  当前时间距离1970-1-1 00:00:00相差的秒数
# 1970-1-1 00:00:00是Unix诞生元年

    延迟程序运行时间

import time
time.sleep(3)  # 让cpu谁三秒   让你的程序暂停三秒
print('FBI warning!')

    统计index函数执行的时间

import time
def index():
    time.sleep(3)
    print('欢迎你')

start = time.time()  # 记录程序开始时间
index()
end = time.time()  # 记录程序结束时间
print('index run time:%s'%(end-start))  # 打印程序运行时间
import time
def index():
    time.sleep(3)
    print('欢迎你')

def outter(func):  # func = 最原始的index函数的内存地址
    def get_time():
        start = time.time()
        func()  # func = index函数的内存地址() 直接调用
        end = time.time()
        print('index run time:%s'%(end-start))
    return get_time
index = outter(index)  # outter(最原始的index函数内存地址)
# index指向get_time函数的内存地址
index()

    进阶版(函数可以接收任意数量的参数)

import time
def index():
    time.sleep(3)
    print('欢迎你')
    return 'index'

def login(name):
    time.sleep(1)
    print('%s is sb'%name)
    return 'login'

def outter(func):  # func = 最原始的login函数的内存地址
    def get_time(*args, **kwargs):  # args = ('egon',) kwargs = {}
        start = time.time()
        res = func(*args, **kwargs)  # 最原始的login函数的内存地址() 直接调用  func('egon')
        end = time.time()
        print('func run time:%s'%(end-start))
        return res
    return get_time
login = outter(login)  # outter(最原始的login函数的内存地址)
res = login('egon')
print(res)  # 返回值 login
index = outter(index)
res1 = index()
print(res1)  # 返回值 index

  5.装饰器语法糖

    @装饰器外部的函数名

    语法糖在书写的时候应该与被装饰对象紧紧挨着

    两者之间不要有空格

import time

def outter(func):  # func = 最原始的login函数的内存地址
    def get_time(*args, **kwargs):  # args = ('egon',) kwargs = {}
        start = time.time()
        res = func(*args, **kwargs)  # 最原始的login函数的内存地址() 直接调用  func('egon')
        end = time.time()
        print('func run time:%s'%(end-start))
        return res
    return get_time

@outter  # index = outter(index)  outter(最原始的index的函数的内存地址)
def index():
    time.sleep(3)
    print('欢迎你')
    return 'index'

@outter  # login = outter(login)
def login(name):
    time.sleep(1)
    print('%s is sb'%name)
    return 'login'

@outter  # home = outter(home)
def home(*args,**kwargs):
    time.sleep(1)
    return 'home'

index()
login('egon')
home()

  6.无参装饰器

from functools import wraps
def outter(func):
    @wraps(func)
    def inner(*args,**kwargs):  # * **在形参中使用
        # 执行被装饰函数之前你可以做的操作
        res = func(*args,**kwargs)  # * **在实参中使用
        # 执行被装饰函数之后你可以做到操作
        return res
    return inner

@outter
def index(username,*args,**kwargs):
    """index注释"""
    pass
print(index)

  7.有参装饰器

def wrappers(data):
    # data = 'file'
    def outter(func):
        def inner(*args,**kwargs):
            if data == 'file':
                # 执行被装饰函数之前你可以做的操作
                res = func(*args,**kwargs)  # * **在实参中使用
                # 执行被装饰函数之后你可以做到操作
                return res
        return inner
    return outter

  8.装饰器模板

def outter(func):
    def inner(*args,**kwargs):
        print("执行被装饰函数之前的操作")
        res = func(*args,**kwargs)  # 最原始函数的内存地址() 直接调用
        print("执行被装饰函数之后的操作")
        return res  # 返回最原始函数的内存地址()
    return inner

    认证装饰器

     执行函数index之前必须先输入用户名和密码,正确之后才能执行index,否则提示用户输入错误 结束程序

import time
user_dic = {'is_login':None}

def login_auth(func):
    def inner(*args,**kwargs):
        if user_dic['is_login']:
            res = func(*args,**kwargs)
            return res
        else:
            name = input("请输入用户名:")
            pwd = input("请输入密码:")
            if name == 'ylj' and pwd == '123':
                user_dic['is_login'] = True
                res = func(*args,**kwargs)
                print(res)
                return res
            else:
                print("用户名或者密码错误!")
    return inner

@login_auth
def index(name):
    time.sleep(3)
    print("欢迎你%s" %name)
    return index

index('ylj')
print(index)

  9.多层装饰器

    装饰器在装饰的时候,顺序从下往上,类似于将产品包装

    装饰器在执行的时候,顺序从上往下,类似于将包装的产品拆开

def outter1(func1): #func1=wrapper2的内存地址
    print('加载了outter1')
    def wrapper1(*args,**kwargs):
        print('执行了wrapper1')
        res1=func1(*args,**kwargs)
        print('结束了wrapper1')
        return res1
    return wrapper1

def outter2(func2): #func2=wrapper3的内存地址
    print('加载了outter2')
    def wrapper2(*args,**kwargs):
        print('执行了wrapper2')
        res2=func2(*args,**kwargs)
        print('结束了wrapper2')
        return res2
    return wrapper2

def outter3(func3): # func3=最原始的那个index的内存地址
    print('加载了outter3')
    def wrapper3(*args,**kwargs):
        print('执行了wrapper3')
        res3=func3(*args,**kwargs)
        print('结束了wrapper3')
        return res3
    return wrapper3



@outter1 # index = outter1(wrapper2)
@outter2 # wrapper2 = outter2(wrapper3)
@outter3 # wrapper3 = outter3(index)
def index():
    print('from index')
index()

  8.装饰器修复技术

    用户查看被装饰函数的函数名的时候查看到的就是被装饰函数本身

    用户查看被装饰函数的注释的时候查看到的就是被装饰函数的注释

    from functools import wraps

    @wrps()

from functools import wraps
def outter(func):
    @wraps(func)  # 装饰器修复技术
    def inner(*args,**kwargs):
        """
        我是inner函数
        :param args:
        :param kwargs:
        :return:
        """
        print('执行被装饰函数之前 你可以执行的操作')
        res = func(*args,**kwargs)
        print('执行被装饰函数之后 你可以执行的操作')
        return res
    return inner

@outter  # index = outter(最原始的index内存地址)
def index():
    """
    这是index函数
    :return:
    """
    pass

  ps:

  print(help(index))  查看函数的注释

  print(index._name_)  查看函数名字字符串形式

posted @ 2019-07-11 18:05  静心学  阅读(153)  评论(0)    收藏  举报