什么是闭包函数与装饰器,它们有哪些作用?

图片[1]-什么是闭包函数与装饰器,它们有哪些作用?-不念博客
闭包函数与装饰器

闭包函数

  • 闭函数指的是在一个函数内部的函数,即嵌套在函数内部的函数。
  • 包函数指的是内部函数对外层函数(非全局作用域)作用域名字的引用。
  • 闭包函数基于函数对象,可以将函数返回到任意位置调用,但是作用域的关系在定义函数的时候就被确定了,与函数的调用位置无关。如果内嵌函数包含对外部函数作用域中名字的引用,该内嵌函数就是闭包函数。
# -*- coding: utf-8 -*-
def outer():
name = 'shisbuyu'
def inner():
print('外层函数的内层函数inner', name) # 内层函数使用到了外层函数名称空间中名字
inner()
return inner
res = outer() # 得到的返回值是函数名inner
# 输出
# 外层函数的内层函数inner shisbuyu
# -*- coding: utf-8 -*-
def outer():
    name = 'shisbuyu'

    def inner():
        print('外层函数的内层函数inner', name)  # 内层函数使用到了外层函数名称空间中名字

    inner()
    return inner


res = outer()  # 得到的返回值是函数名inner

# 输出
# 外层函数的内层函数inner shisbuyu
# -*- coding: utf-8 -*- def outer(): name = 'shisbuyu' def inner(): print('外层函数的内层函数inner', name) # 内层函数使用到了外层函数名称空间中名字 inner() return inner res = outer() # 得到的返回值是函数名inner # 输出 # 外层函数的内层函数inner shisbuyu

闭包函数作用

  1. 函数体传参方式之 形参
def index(username):
print(username)
index('shisbuyu') # 函数体代码需要什么就可以在形参里写什么
def index(username):
    print(username)


index('shisbuyu')  # 函数体代码需要什么就可以在形参里写什么
def index(username): print(username) index('shisbuyu') # 函数体代码需要什么就可以在形参里写什么
  1. 函数体传参方式之 闭包
def outter():
name = 'shisbuyu'
def index():
print(name) # name写死了, 调用res() name shisbuyu
return index
res = outer()
res()
def outter():
    name = 'shisbuyu'

    def index():
        print(name)  # name写死了, 调用res() name shisbuyu

    return index


res = outer()
res()
def outter(): name = 'shisbuyu' def index(): print(name) # name写死了, 调用res() name shisbuyu return index res = outer() res()

做成闭包函数通过形参传参给外层

def outter(name):
def index():
print(name)
return index
res = outter('shisbuyu')
res() # shisbuyu
res1 = outter('shisuiyi')
res1() # shisuiyi
def outter(name):
    def index():
        print(name)

    return index


res = outter('shisbuyu')
res()  # shisbuyu
res1 = outter('shisuiyi')
res1()  # shisuiyi
def outter(name): def index(): print(name) return index res = outter('shisbuyu') res() # shisbuyu res1 = outter('shisuiyi') res1() # shisuiyi

装饰器

装饰器可以在不改动原函数代码的情况下,添加其原本没有的功能。简单点说,就是 修改其它函数的功能的函数 。通过使用装饰器,我们可以让一个函数的功能变的更加强大,还可以让我们的代码更加简短整洁。

普通装饰器

方式一:不使用语法糖@符号的调用方法:

# -*- coding: utf-8 -*-
# 原函数
def one():
print("这是一个平平无奇的函数")
# 定义1个装饰器
def loop(func):
def wrapper(*args, **kw):
for i in range(2):
func(*args, **kw)
return wrapper
loop(one)()
# 输出
这是一个平平无奇的函数
这是一个平平无奇的函数
# -*- coding: utf-8 -*-

# 原函数
def one():
    print("这是一个平平无奇的函数")


# 定义1个装饰器
def loop(func):
    def wrapper(*args, **kw):
        for i in range(2):
            func(*args, **kw)

    return wrapper
    
loop(one)()

# 输出
这是一个平平无奇的函数
这是一个平平无奇的函数
# -*- coding: utf-8 -*- # 原函数 def one(): print("这是一个平平无奇的函数") # 定义1个装饰器 def loop(func): def wrapper(*args, **kw): for i in range(2): func(*args, **kw) return wrapper loop(one)() # 输出 这是一个平平无奇的函数 这是一个平平无奇的函数

方式二:使用语法糖@符号的调用方法:

# -*- coding: utf-8 -*-
# 定义1个装饰器
def loop(func):
def wrapper(*args, **kw):
for i in range(2):
func(*args, **kw)
return wrapper
@loop
def one():
print("这是一个平平无奇的函数")
one()
# 输出
这是一个平平无奇的函数
这是一个平平无奇的函数
# -*- coding: utf-8 -*-

# 定义1个装饰器
def loop(func):
    def wrapper(*args, **kw):
        for i in range(2):
            func(*args, **kw)

    return wrapper


@loop
def one():
    print("这是一个平平无奇的函数")


one()

# 输出
这是一个平平无奇的函数
这是一个平平无奇的函数
# -*- coding: utf-8 -*- # 定义1个装饰器 def loop(func): def wrapper(*args, **kw): for i in range(2): func(*args, **kw) return wrapper @loop def one(): print("这是一个平平无奇的函数") one() # 输出 这是一个平平无奇的函数 这是一个平平无奇的函数

函数带参数

# -*- coding: utf-8 -*-
def loop(func):
def wrapper(*args, **kw):
for i in range(2):
func(*args, **kw)
return wrapper
@loop
def one(num):
for i in range(num):
print("这是一个平平无奇的函数")
one(2)
#输出
这是一个平平无奇的函数
这是一个平平无奇的函数
这是一个平平无奇的函数
这是一个平平无奇的函数
# -*- coding: utf-8 -*-

def loop(func):
    def wrapper(*args, **kw):
        for i in range(2):
            func(*args, **kw)

    return wrapper


@loop
def one(num):
    for i in range(num):
        print("这是一个平平无奇的函数")


one(2)

#输出
这是一个平平无奇的函数
这是一个平平无奇的函数
这是一个平平无奇的函数
这是一个平平无奇的函数
# -*- coding: utf-8 -*- def loop(func): def wrapper(*args, **kw): for i in range(2): func(*args, **kw) return wrapper @loop def one(num): for i in range(num): print("这是一个平平无奇的函数") one(2) #输出 这是一个平平无奇的函数 这是一个平平无奇的函数 这是一个平平无奇的函数 这是一个平平无奇的函数

带返回值

# -*- coding: utf-8 -*-
def loop(func):
def wrapper(*args, **kw):
ret = func(*args, **kw)
return ret
return wrapper
@loop
def one(a, b):
return a + b
res = one(1, 2)
print(res)
# 当使用@loop对one()函数装饰以后,one指向了wrapper()函数,而wrapper()函数的返回值是ret,所以one()函数的返回值被ret接收了
#输出
3
# -*- coding: utf-8 -*-

def loop(func):
    def wrapper(*args, **kw):
        ret = func(*args, **kw)
        return ret

    return wrapper


@loop
def one(a, b):
    return a + b


res = one(1, 2)
print(res)

# 当使用@loop对one()函数装饰以后,one指向了wrapper()函数,而wrapper()函数的返回值是ret,所以one()函数的返回值被ret接收了

#输出
3
# -*- coding: utf-8 -*- def loop(func): def wrapper(*args, **kw): ret = func(*args, **kw) return ret return wrapper @loop def one(a, b): return a + b res = one(1, 2) print(res) # 当使用@loop对one()函数装饰以后,one指向了wrapper()函数,而wrapper()函数的返回值是ret,所以one()函数的返回值被ret接收了 #输出 3

实际案例

日志装饰器

# -*- coding: utf-8 -*-
import logging
import os
'''
* %(asctime)s 即日志记录时间,精确到毫秒@breif:
* %(levelname)s 即此条日志级别@param[in]:
* %(filename)s 即触发日志记录的python文件名@retval:
* %(funcName)s 即触发日志记录的函数名
* %(lineno)s 即触发日志记录代码的行号
* %(message)s 即这项调用中的参数
'''
if not os.path.exists('Log.log'):
file = open('Log.log', 'w')
logging.basicConfig(
filename='Log.log',
format="%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s"
)
'''
* @breif: 日志修饰器,为函数添加日志记录服务
* @param[in]: err -> 发生异常时返回的错误信息
* @retval: 加载日志服务的功能函数
'''
def logger(err):
def log(func):
def warp(*args, **kwargs):
try:
result = func(*args, **kwargs)
return result
except Exception as e:
logging.error(e)
return err
return warp
return log
@logger('出错了')
def add(a, b):
return a + b
print(add(1, 2))
#控制台输出
出错了
# Log.log日志显示
2022-12-13 14:11:22,772 - ERROR - 闭包函数.py - warp - 36 - unsupported operand type(s) for +: 'int' and 'str'
# -*- coding: utf-8 -*-

import logging
import os

'''
* %(asctime)s   即日志记录时间,精确到毫秒@breif: 
* %(levelname)s 即此条日志级别@param[in]: 
* %(filename)s  即触发日志记录的python文件名@retval: 
* %(funcName)s  即触发日志记录的函数名
* %(lineno)s    即触发日志记录代码的行号
* %(message)s   即这项调用中的参数
'''
if not os.path.exists('Log.log'):
    file = open('Log.log', 'w')

logging.basicConfig(
    filename='Log.log',
    format="%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s"
)

'''
* @breif: 日志修饰器,为函数添加日志记录服务
* @param[in]: err -> 发生异常时返回的错误信息
* @retval: 加载日志服务的功能函数
'''


def logger(err):
    def log(func):
        def warp(*args, **kwargs):
            try:
                result = func(*args, **kwargs)
                return result
            except Exception as e:
                logging.error(e)
                return err

        return warp

    return log


@logger('出错了')
def add(a, b):
    return a + b


print(add(1, 2))

#控制台输出
出错了
# Log.log日志显示
2022-12-13 14:11:22,772 - ERROR - 闭包函数.py - warp - 36 - unsupported operand type(s) for +: 'int' and 'str'
# -*- coding: utf-8 -*- import logging import os ''' * %(asctime)s 即日志记录时间,精确到毫秒@breif: * %(levelname)s 即此条日志级别@param[in]: * %(filename)s 即触发日志记录的python文件名@retval: * %(funcName)s 即触发日志记录的函数名 * %(lineno)s 即触发日志记录代码的行号 * %(message)s 即这项调用中的参数 ''' if not os.path.exists('Log.log'): file = open('Log.log', 'w') logging.basicConfig( filename='Log.log', format="%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s" ) ''' * @breif: 日志修饰器,为函数添加日志记录服务 * @param[in]: err -> 发生异常时返回的错误信息 * @retval: 加载日志服务的功能函数 ''' def logger(err): def log(func): def warp(*args, **kwargs): try: result = func(*args, **kwargs) return result except Exception as e: logging.error(e) return err return warp return log @logger('出错了') def add(a, b): return a + b print(add(1, 2)) #控制台输出 出错了 # Log.log日志显示 2022-12-13 14:11:22,772 - ERROR - 闭包函数.py - warp - 36 - unsupported operand type(s) for +: 'int' and 'str'

自动化测试脚本中处理异常

举个例子,你正在跑一个自动化测试脚本,突然间设备的闹钟响了,而刚好闹钟的界面遮挡住了你要操作的那个按钮,最终导致脚本运行失败了。没办法,你只能关掉闹钟再重新运行一次脚本。

# -*- coding: utf-8 -*-
def test_retry(func):
def run_case_again(*args, **kwargs):
try:
func(*args, **kwargs)
except:
# 如闹铃、断网重试按钮弹出、短信通知等导致失败
if exists(xxxx):
touch(xxx)
try:
func(*args, **kwargs)
print('用例重新执行成功')
except:
print('用例执行失败')
# 其他你想做的操作,比如停止剩余用例的执行
return run_case_again
@test_retry
def test():
wait(xxxx, timeout=15)
# -*- coding: utf-8 -*-

def test_retry(func):
    def run_case_again(*args, **kwargs):
        try:
            func(*args, **kwargs)
        except:
            # 如闹铃、断网重试按钮弹出、短信通知等导致失败
            if exists(xxxx):
                touch(xxx)
            try:
                func(*args, **kwargs)
                print('用例重新执行成功')
            except:
                print('用例执行失败')
                # 其他你想做的操作,比如停止剩余用例的执行

    return run_case_again


@test_retry
def test():
    wait(xxxx, timeout=15)
# -*- coding: utf-8 -*- def test_retry(func): def run_case_again(*args, **kwargs): try: func(*args, **kwargs) except: # 如闹铃、断网重试按钮弹出、短信通知等导致失败 if exists(xxxx): touch(xxx) try: func(*args, **kwargs) print('用例重新执行成功') except: print('用例执行失败') # 其他你想做的操作,比如停止剩余用例的执行 return run_case_again @test_retry def test(): wait(xxxx, timeout=15)
© 版权声明
THE END