闭包函数,函数装饰器,语法糖

一.闭包函数:

闭包函数:
闭:定义在函数内部的函数
包:内部的函数引用了外部函数作用域的名(变量名)
闭包也是一种传参方式

def outter(x,y):
    # x = 1
    # y = 2
    def my_max():
        if x > y:
            return x
        return y
    return my_max
res = outter(1,2)   # outter加()本身会得到一个返回值my_max,实参1和2相当于变量值传给了x和y两个变量名
print(res())

import requests  # 爬虫模块

#方式一 直接给函数传参
info1 =  'https://www.baidu.com'
info2 = '......'
def my_get(rul):
    resuit = requests.get(rul)
    if resuit.status_code == 200:
        print(len(resuit.text))
my_get(info1)
my_get(info2)
'.....'


#方式二 用闭包的方式给函数传参
def outter(func):
    # func =  'https://www.jd.com'
    def my_get(func):
        resuit = requests.get(func)
        if resuit.status_code == 200:
            print(len(resuit.text))
    return my_get
res_jd = outter( 'https://www.jd.com')  # res = my_get
res_jd()  # my_get()

二.装饰器:

装饰器
器:就是一个工具
装饰:给被装饰对象(函数)添加功能
开放封闭原则:
开放:对扩展开放
封闭:对修改封闭

装饰器(被调用对象)必须遵循的两大原则:
1.不改变装饰对象(被装饰函数)的源码
2.不改变被装饰对象的调用方式
 import time
print(time.time())
# 1562812014.731474 时间戳  当前时间距离1970-1-1 00:00:00相差的秒数
# 1970-1-1 00:00:00是Unix诞生元年


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

 通用装饰器模板

def outter(func):
    def inner(*args,**kwargs):
        print('执行被装饰函数之前 你可以做的操作')
        res = func(*args,**kwargs)
        print('执行被装饰函数之后 你可以做的操作')
        return res
    return inner

 

def auth(driver='file'):
    def auth2(func):
        def wrapper(*args,**kwargs):
            name=input("user: ")
            pwd=input("pwd: ")

            if driver == 'file':
                if name == 'egon' and pwd == '123':
                    print('login successful')
                    res=func(*args,**kwargs)
                    return res
            elif driver == 'ldap':
                print('ldap')
        return wrapper
    return auth2

@auth(driver='file')
def foo(name):
    print(name)

foo('egon')

有参装饰器

 

统计func函数运行时间:
# 简单版:
def func():
    time.sleep(2)  # 让cpu睡眠2秒
    print('form func')

star_res = time.time()
func()
over_res = time.time()
print('运行时间: %s'%(over_res - star_res))
# >>> 运行时间: 2.00064754486084
#此时的计算时间功能只能func函数单独使用,如果其他函数也要用到时间计算功能需要重新编写代码,
# 可以把计算时间功能封装成一个函数给其他函数使用


#有装饰器版

def func():
    time.sleep(2)  # 让cpu睡眠2秒
    print('form func')

def outter(info):  # info = 原始func的内存地址
    def time_func():
        star_res = time.time()
        info()  # 相当于 func() 函数运行
        over_res = time.time()
        print('运行时间: %s'%(over_res - star_res))
    return time_func
func = outter(func)  # 新 func = time_func的内存地址
func()  # 相当于 time_func()函数运行

# >>> form func
# >>> 运行时间: 2.0006558895111084
import time
def index():
    time.sleep(3)
    print('澳门最大线上赌场开业啦 性感tank在线发牌!')
    return 'index'
# res1 = index()

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

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)
# >>>egon is sb
# >>>func run time:1.000328779220581
# >>>login

index = outter(index)
res1 = index()
print(res1)
# >>>澳门最大线上赌场开业啦 性感tank在线发牌!
# >>>func run time:3.0011234283447266
# >>>index
利用*args和**args解决有参无参均可调用问题

在装饰器内,定义形参 *args ,**kwargs 可以接收有参无参函数

def func():
    time.sleep(2)  # 让cpu睡眠2秒
    print('form func')
    return '函数func的返回值'

def user(name):
    time.sleep(1)
    print('welcome %s'%name)
    return '函数user的返回值'

def outter(info):  # info = 原始func的内存地址  # info = 原始user的内存地址
    def time_get(*args,**kwargs):
        # args = ' '
        # kwargs = ' '  闭包函数的特性
        star_res = time.time()
        res = info(*args,**kwargs)  # 相当于 func() 函数运行  # 相当于user()函数运行,但函数user必须要传参才能执行
        over_res = time.time()
        print('运行时间: %s'%(over_res - star_res))
        return res
    return time_get
func = outter(func)  # 新 func = time_get的内存地址
res_1 =func()  # 相当于 time_get()函数运行
print(res_1)   # res_1 = res = 函数func的返回值
# >>> form func
# >>> 运行时间: 2.0006558895111084
# >>> 函数func的返回值

user = outter(user)  # 新 user = rime_get 的内存地址
res_2 = user('wong')  # 相当于 time_get()运行函数
print(res_2)
# >>> welcome wong
# >>> 运行时间: 1.000464677810669
# >>> 函数user的返回值

 

三.语法糖 @+装饰器函数名

语法糖在书写的时候应该与被装饰对象紧紧挨着 
两者之间不要有空格

@+装饰器函数名        相当于它拿到了它所装饰的哪个函数的内存地址,当作实参传给装饰器的形参

import time

def outter(info):  # info = 原始func的内存地址  # info = 原始user的内存地址
    def time_get(*args,**kwargs):
        # args = ' '
        # kwargs = ' '  闭包函数的特性
        star_res = time.time()
        res = info(*args,**kwargs)  # 相当于 func() 函数运行  # 相当于user()函数运行,但函数user必须要传参才能执行
        over_res = time.time()
        print('运行时间: %s'%(over_res - star_res))
        return res
    return time_get
# func = outter(func)  # 新 func = time_get的内存地址
# res_1 =func()  # 相当于 time_get()函数运行
# print(res_1)

@outter  # func = outter(func)
def func():
    time.sleep(2)  # 让cpu睡眠2秒
    print('form func')
    return '函数func的返回值'
func()

@outter  # user = outter(func)
def user(name):
    time.sleep(1)
    print('welcome %s'%name)
    return '函数user的返回值'
user('wong')

# 装饰器在装饰的时候  顺序从下往上
# 装饰器在执行的时候 顺序从上往下
def outter1(func1): #func1=wrapper2的内存地址
    print('加载了outter1')
    def wrapper1(*args,**kwargs):
        print('执行了wrapper1')
        res1=func1(*args,**kwargs)  # func1=wrapper2的内存地址
        return res1  
    return wrapper1

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

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

@outter1 # outter1(wrapper2的内存地址)======>index=wrapper1的内存地址
@outter2 # outter2(wrapper3的内存地址)======>wrapper2的内存地址
@outter3 # outter3(最原始的那个index的内存地址)===>wrapper3的内存地址  # wrapper = outter3(index)
def index():  # func3(*args,**kwargs)的时候运行此函数
    print('from index')  # 最后一步
index()  # 相当于 wrapper1()
多层装饰器

 详情分析链接



posted @ 2019-07-11 17:32  waller  阅读(287)  评论(0编辑  收藏  举报