闭包函数、装饰器

一、补充知识点

1、可调用的callable(可以加括号执行某个特定功能):函数名,类名

2、import this:查看Python之禅

二、闭包函数

1、定义

  闭:定义在函数内部的函数

  包:内部函数引用了外部函数作用域的名字

2、形式

def outter(x,y):
    def inner():
        代码1
        代码2
    return inner
 
res = outter(1, 2)
res()

3、作用

  给函数体传参有两种方式,第一种是直接给函数体传参,第二种就是用闭包函数,它是利用外部函数给内部函数传参,这样在调用内部函数的时候,就可以不写参数。

4、举例

import requests  # requests是python实现的简单易用的HTTP库
def outter(url):
    def my_get():
        response = requests.get(url)
        if response.status.code == 200:
            print(len(response.text))
        return my_get
my_jd = outter("https://www.jd.com")
my_jd()

三、装饰器

1、定义

  器:就是一个工具

  装饰:给被装饰对象添加新的功能

2、开放封闭原则

  开放:对扩展开放

  封闭:对修改封闭

3、装饰器必须遵守的两个原则

  ①、不改变被装饰对象源代码

  ②、不改变被装饰对象(可调用对象)调用方式

4、装饰器简单版

"""
统计index函数执行的时间
"""
import time  # 导入时间模块
def index():
    time.sleep(1)
#让程序暂停1秒,测量程序运行时间时,如果时间过短,测量时间会是0,加上延时后就可以测量
    print('澳门最大线上赌场开业啦 性感tank在线发牌!')

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()

5、装饰器升级版

解决了函数参数的问题,无参函数和有参函数都可以直接调用,可以接收任意数量的参数

import time
def index():
    time.sleep(1)
    print('from index')
    return index
res = index()  # from index

def login(name):
    time.sleep(1)
    print(name)
    return login
res1 = login('egon')  # egon

def outter(func):
    def get_time(*args, **kwargs):
# 可以传入任意参数,放入元组和字典中
        start = time.time()
        res = func(*args, **kwargs)
# 将元组和字典打散,将参数原封不动的传给func函数
        end = time.time()
        print(end-start)
        return res
    return get_time

index = outter(index)  
login = outter(login)
index()
# from index
# 1.0002615451812744
# 此时的index()已经多了计时功能
login('egon')
# egon
# 1.0002918243408203
# 此时的login()已经多了计时功能
print(res)
# <function index at 0x00DFA660>
print(res1)
# <function login at 0x028435D0>
print(index)
# <function outter.<locals>.get_time at 0x028436F0>
print(login)
# <function outter.<locals>.get_time at 0x02843660>

6、装饰器语法糖

  ①、形式

import time


def outter(func):
    def get_time(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print('func run time:%s'%(end - start))
        return res
    return get_time


@outter
def index():
    time.sleep(1)
    print('澳门最大线上赌场开业了!')
    return 'index'


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


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


res = index()
res1 = login('egon')
res2 = home()
print(res, res1, res2)


# 输出
澳门最大线上赌场开业了!
func run time:1.0009095668792725
egon is sb
func run time:1.0010344982147217
func run time:1.0009922981262207
index login home

  ②、作用

  书写代码的时候省去了login = outter(login),index = outter(index),home = outter(home)这三行代码,因为@outter自动帮你做了这件事,它会将下面最靠近它的函数的函数名当做参数传入outter()函数,并将返回值(内部函数的函数名)赋值给与该函数名同名的变量名,虽然这个地方并未出现函数名加括号,实际上已经调用了outter函数,如果outter函数内部除了定义新函数外还有打印操作,此时运行函数就会打印出内容。

  ③、书写规范

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

7、多层装饰器

  ①、

import time


user_dic = {'is_login':None}


def outter(func):
    def get_time(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print('func run time:%s'%(end-start))
        return res
    return get_time


def login_auth2(data_source,x,t):
    def login_auth(func):
        def inner(*args, **kwargs):
            if user_dic['is_login']:
                res = func(*args, **kwargs)
                return res
            else:
                if data_source == 'file':
                    username = input('please input your username:')
                    password = input('please input your password:')
                    if username == 'jason' and password == '123':
                        user_dic['is_login'] = True
                        res = func(*args, **kwargs)
                        return res
                    else:
                        print('username or password error')
                elif data_source == 'MySQL':
                    print('from MySQL')
                elif data_source == 'ldap':
                    print('ldap')
                else:
                    print('暂无该数据来源')
        return inner
    return login_auth


@login_auth2('file',1,2)
# 这一步相当于
# res = login_auth2('file',1,2)  # 这里的res就是login_auth2()的返回值login_auth
# @res
@outter
def index():
    time.sleep(1)
    print('index')
    return 'index'


index()
# 装饰器在装饰的时候,顺序从下往上
# 装饰器在执行的时候,顺序从上往下
# 这里就实现了给index函数增加了两个功能:计时和认证
# 这里的认证函数是三层嵌套的,最外层函数的作用就是给里层函数传参

  ②、

def outter1(func1):
    print('加载了outter1')
    def wrapper1(*args,**kwargs):
        print('执行了wrapper1')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1
def outter2(func2):
    print('加载了outter2')
    def wrapper2(*args,**kwargs):
        print('执行了wrapper2')
        res2 = func2(*args, **kwargs)
        return res2
    return wrapper2
def outter3(func3):
    print('加载了outter3')
    def wrapper3(*args,**kwargs):
        print('执行了wrapper3')
        res3 = func3(*args, **kwargs)
        return res3
    return wrapper3


@outter1
@outter2
@outter3
def index():
    print('from index')


index()
# 输出
# 加载了outter3
# 加载了outter2
# 加载了outter1
# 执行了wrapper1
# 执行了wrapper2
# 执行了wrapper3
# from index

8、装饰器修复技术

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
def index():
    """
    这是index函数
    :return:
    """
    print('from index')


print(index)
# <function index at 0x037646F0>
print(help(index))
# Help on function index in module __main__:
#
# index()
#     这是index函数
#     :return:
#
# None
print(index.__name__)
# index
index()
# 执行被装饰函数之前,你可以执行的操作
# from index
# 执行被装饰函数之后,你可以执行的操作
# 无论是打印index的函数名,还是查看函数的注释,还是查看函数名字的字符串形式,都与原来的index函数一样

9、装饰器模板

  ①、无参装饰器

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)

  ②、有参装饰器

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

  

原文地址:https://www.cnblogs.com/DcentMan/p/11171851.html