Python使用闭包自动生成函数

Posted 编程大观园

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python使用闭包自动生成函数相关的知识,希望对你有一定的参考价值。

背景

在构建测试用例集时,常常需要编写一些函数,这些函数接受基本相同的参数,仅有一个参数有所差异,并且处理模式也非常相同。可以使用Python闭包来定义模板函数,然后通过参数调节来自动化生产不同的函数。

示例

看如下代码:

def commonGenerate(startTime, endTime, field, values):
    reqs = []
    for val in values:
        requestId = str(startTime) + "_" + str(endTime) + "_" + val
        baseReq = json.loads(baseExportReqStr)
        baseReq['order_search_param']['start_time'] = startTime
        baseReq['order_search_param']['end_time'] = endTime
        baseReq['order_search_param'][field] = [val]
        baseReq['request_id'] = requestId
        reqs.append(json.dumps(baseReq))
    return reqs

def generateReqByState(startTime, endTime):
    states = ["TOPAY", "CONFIRM", "PAID", "SENT", "SUCCESS", "CLOSE"]
    return commonGenerate(startTime, endTime, 'order_state', states)

def generateReqByOrderType(startTime, endTime):
    orderTypes = ["NORMAL", "GROUP", "HOTEL"]
    return commonGenerate(startTime, endTime, 'order_type', orderTypes)

def generateReqByExpressType(startTime, endTime):
    expressTypes = ["EXPRESS", "SELF_FETCH", "LOCAL_DELIVERY"]
    return commonGenerate(startTime, endTime, 'express_type', expressTypes)

def generateReqByFeedback(startTime, endTime):
    feedbacks = ["SAFE_NEW", "SAFE_FINISHED"]
    return commonGenerate(startTime, endTime, 'feedback', feedbacks)

def getGenerateFuncs():
    gvars = globals()
    return [ gvars[var] for var in gvars if var.startswith('generateReq')  ]

caseGenerateFuncs = getGenerateFuncs()
print caseGenerateFuncs

这里已经抽离出通用函数 commonGenerate ,在此基础上定义了多个 generateReqByXXX ,这些函数的模式基本相同,无非是传一个字段名及值列表,然后生成一个不一样的函数。 那么,是否可以做成可配置化呢: 只要给定一个 map[字段名,值列表], 就能自动生成这些函数 ?

使用闭包可以达到这个目标。见如下代码所示:

def commonGenerator(startTime, endTime, field, values):
    def generateReqInner(startTime, endTime):
        reqs = []
        for val in values:
            requestId = str(startTime) + "_" + str(endTime) + "_" + val
            baseReq = json.loads(baseExportReqStr)
            baseReq['order_search_param']['start_time'] = startTime
            baseReq['order_search_param']['end_time'] = endTime
            baseReq['order_search_param'][field] = [val]
            baseReq['request_id'] = requestId
            reqs.append(json.dumps(baseReq))
        return reqs
    return generateReqInner

def generateGenerators(startTime, endTime, configs):
    gvars = globals()
    for (field, values) in configs.iteritems():
        gvars['generateReqBy' + field] = commonGenerator(startTime, endTime, field, values)

configs = {"order_state": ["TOPAY", "CONFIRM", "PAID", "SENT", "SUCCESS", "CLOSE"], \
           "order_type": ["NORMAL", "GROUP", "HOTEL"], \
           "express_type": ["EXPRESS", "SELF_FETCH", "LOCAL_DELIVERY"], \
           "feedback": ["SAFE_NEW", "SAFE_FINISHED"]
           }

def getGenerateFuncs():
    gvars = globals()
    return [ gvars[var] for var in gvars if var.startswith('generateReq')  ]

generateGenerators(startTime, endTime, configs)
caseGenerateFuncs = getGenerateFuncs()
print caseGenerateFuncs

这里函数 commonGenerator 对 commonGenerate 做了一点改动,不再直接返回值列表,而是根据不同的参数返回一个处理不同的函数,这个函数会返回值列表; 然后 generateGenerators 根据指定配置 configs, 调用commonGenerator 来批量生产generateReqByXXX函数。妙不妙,生产函数的函数 !

原理

按维基的解释: 闭包是引用了自由变量的函数。在例子中,闭包就是 generateReqInner , 引用了传入的自由变量 field, values, 从而在 commonGenerator 调用结束之后,generateReqInner 依然存在能够被访问,且功能效果等同于 generateReqInner(startTime, endTime, field, values) 。

小结

通过Python闭包自动化生成函数,使得代码表达能力更强大了。只要做一点配置,就能自动生成相应的函数。

以上是关于Python使用闭包自动生成函数的主要内容,如果未能解决你的问题,请参考以下文章

Python概念之装饰器迭代器生成器

Python核心编程的四大神兽:迭代器生成器闭包以及装饰器

python装饰器迭代器生成器闭包等等

Python函数进阶:闭包装饰器生成器协程

Spark闭包与序列化

Python 应用闭包思路动态生成unittest执行脚本---分析问题,解决问题,记录填坑。