闭包函数与装饰器

一:闭包函数

【1】

定义:

(1)内部函数被外部函数包裹住

(2) 内部函数包含对外部函数作用域名字的引用

 

【2】外部函数传参

方法一:直接传参

例如:

def index(args):
    print('位置传参')
index(args='传参')  # 位置传参

方法二:闭包传参

def outter():
    def inner():
        x = 1
        print('from inner' ,x)
    return inner
res = outter()  # 获取的是inner的内存地址 因为内部地址返回值是inner 将内部地址赋值给一个变量        
res()           # from inner 因为res此时获取的是inner的内存地址 通过该地址可以调用内部函数

PS:

(1)闭包函数 打破了层级关系的限制 可以在任意位置调用

(2)函数作用域在固定阶段就已经固定死了 与其调用位置无关

例如:

def outter():
    x = 2      # 次优先调用
    def inner():
        x = 1  # 优先调用
        print('from inner' ,x)
    return inner
res = outter()
x = 111       # 最后调用
res()         # 因为其调用的是inner这个函数

基本定义模块:

def outter(x):
    def inner():
        print('你要执行的操作')
    return inner        # 返回内部函数的内存地址
res = outter('参数值')   # 接收内部函数地址 并向外部函数传参
res()                   # 调用内部函数

 

 二:装饰器

【1】

无参装饰器:

开放封闭原则:

(1)开放:在原有的软件功能进行扩展 开发新的功能

(2)封闭:不能修改源代码 以及源代码的调用方式

 

(1)无参装饰器的基础

装饰器:在不修改被装饰器源代码以及调用方式的基础上 添加新的功能

 例如:

import time

def index():
    time.sleep(1)
    print('index原函数')
    return 'index_SR'

# 方法一:创建新函数 直接传参法
def inner(func):
    start_time = time.time()
    func()                      # 写变量的方法可以同时允许多个函数调用
    end_time = time.time()
    print('相差时间%s'%(end_time-start_time))
inner(index)                    # 相差时间1.0
# PS:虽然添加新功能且没有修改源代码 但是调用方式发生改变

# 方法二:创建新函数 闭包传参
def outer(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print('相差时间%s'%(end_time-start_time))
    return inner
index = outer(index)    # 获取inner的内存地址 并赋值给和原函数名一样的变量
index()                 # 通过获取的内存地址 调用内部的函数
无参函数的简单实现

 

(2)无参装饰器升级版:

简易版问题一:不能获取原始函数的返回值

例如:

def index():
    time.sleep(1)
    print('index原函数')
    return 'index_SR'

def outer(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print('相差时间%s'%(end_time-start_time))
        return
    return inner
index = outer(index)
res = index()
print(res)              # None 因为我此时调用的是inner内部函数 内部函数无返回值
简单装饰器,无返回值

 解决办法:

def index():
    time.sleep(1)
    print('index原函数')
    return 'index_SR'

def outer(func):
    def inner():
        start_time = time.time()
        res = func()        #调用的是最原始的函数
        end_time = time.time()
        print('相差时间%s'%(end_time-start_time))
        return res          # 返回原始函数的返回值
    return inner
index = outer(index)
res = index()
print(res)              # index_SR 此时inner内部有返回原始函数的返回值
无参装饰器,返回值

简易版问题二:是否携带形参

例如:

def index():
    time.sleep(1)
    print('index原函数')
    return 'index_SR'

def home(name):
    time.sleep(1)
    print('home原函数')
    return 'home_SR'

def outer(func):
    def inner(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)        #调用的是最原始的函数
        end_time = time.time()
        print('相差时间%s'%(end_time-start_time))
        return res          # 返回原始函数的返回值
    return inner
index = outer(index)
index()

home = outer(home)
home('SR')

'''
问题现象:
(1)
函数home会报错:TypeError: inner() takes 0 positional arguments but 1 was given
因为home调用的是内部函数inner 但是此时inner属于无参函数 home传参导致报错
(2)
如果将inner内部传参 但是index属于无参函数 如果传参导致index不能正确调用

解决办法:在内部函数在允许任意函数调用 *args,**kwargs
'''
装饰器是否携带形参

 

(3) 无参函数的表达式:

def outer(func):
    def warpper(*args,**kwargs):
        print('你要执行的动作')
        res = func(*args,**kwargs)  # 原函数的返回值赋值给变量 允许所有函数调用
        return res                  # 返回原函数返回值
    return warpper                  # 将内部函数的内存地址返回
name = outer('原函数')               # 内部函数的内存地址 name等于原函数的函数名
name()                              # 调用内部函数

 

【2】

装饰器语法糖:

(1)产生背景:

  (1)当我们想要调用装饰器的时候 需要将原函数名赋值给装饰器 并且将赋值后的函数名更改为与原函数一模一样

  (2)大量的重复赋值更名动作比较繁琐

(2)解决办法:

(1)当采用语法糖的时候 语法糖会自动将与自己紧挨的函数当做变量赋值给装饰器

(2)并且将赋值后的名称更改为与原函数一模一样

例如:

def outer(func):
    def inner(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        end_time = time.time()
        print('延迟时间%s'%(end_time-start_time))
        return res
    return inner


@outer  # index = outer(index)
def index():
    time.sleep(1)
    print('index原函数')
    return 'index_SR'

@outer # index = outer(home)
def home(name):
    time.sleep(1)
    print('home原函数')
    return 'home_SR'
语法糖

 

例题:用户登录验证

current_user = {'usernmae':None}   # 存放登录的用户
def auth_login(func):
    def inner(*args,**kwargs):
        if current_user['usernmae']:  # 如果已经登录 不用再次登录
            res = func(*args, **kwargs)
            return res
        username = input('请输入用户名>>:').strip()
        password = int(input('请输入密码>>:'.strip()))
        if username == 'SR' and password == 123:
            print('登录成功')
            current_user['usernmae'] = username
            res = func(*args,**kwargs)
            return res
        else:
            print('登录失败')
    return inner

@auth_login
def index():
    time.sleep(1)
    print('index原函数')
    return 'index_SR'

@auth_login
def home(name):
    time.sleep(1)
    print('home原函数')
    return 'home_SR'
index()
home('SR')
用户登录验证

 

【3】有参装饰器

import time

current_user = {'usernmae':None}
def timer(func):
    def inner(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        end_time = time.time()
        print('延迟时间%s'%(end_time-start_time))
        return res
    return inner

def auth_login2(source):
    def auth_login(func):
        def wrapper(*args,**kwargs):
            if current_user['usernmae']:
                res = func(*args, **kwargs)
                return res
            else:
                username = input('请输入用户名>>:').strip()
                pwd = int(input('请输入密码>>:'.strip()))
                if source == 'file':
                    if username == 'SR' and pwd == 123 :
                        current_user['usernmae'] =True
                        print('登录成功')
                        res = func(*args,**kwargs)
                        return res
                    else:
                        print('登录失败')
                else:
                    print('MySql')
        return wrapper
    return auth_login


@auth_login2('file')    # 调用装饰器最外部函数
@timer                  
def index():
    time.sleep(1)
    print('form index')
    return 'index_SR'
index()
有参装饰器

 

【4】装饰器修复技术

作用:

(1)返回原函数真正的内存地址

(2)返回原函数的注释等

例如

import time

from functools import wraps
current_user = {'usernmae':None}
def timer(func):
    @wraps(func)
    def inner(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        end_time = time.time()
        print('延迟时间%s'%(end_time-start_time))
        return res
    return inner

def auth_login2(source):
    def auth_login(func):
        def wrapper(*args,**kwargs):
            if current_user['usernmae']:
                res = func(*args, **kwargs)
                return res
            else:
                username = input('请输入用户名>>:').strip()
                pwd = int(input('请输入密码>>:'.strip()))
                if source == 'file':
                    if username == 'SR' and pwd == 123 :
                        current_user['usernmae'] =True
                        print('登录成功')
                        res = func(*args,**kwargs)
                        return res
                    else:
                        print('登录失败')
                else:
                    print('MySql')
        return wrapper
    return auth_login


@auth_login2('file')    # 调用装饰器最外部函数
@timer
def index():
    time.sleep(1)
    print('form index')
    return 'index_SR'
index()
装饰器修复技术

 

posted @ 2019-07-11 18:28  SR丶  阅读(271)  评论(0编辑  收藏  举报