关于PYTHON Enclosing 的一个小问题

文章讨论了一个Python脚本在并发执行测试用例时遇到的问题,即由于闭包作用域导致的变量i值变化,从而影响了打印输出。解决方案是通过将变量i作为参数传递给内部函数,创建一个新的局部作用域,防止外部作用域的i值改变影响结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题分析

以下是一段每隔半小时重复执行测试用例的脚本,func是传入的测试函数,在执行func前后,会打印操作次数

def repeat(func, action):
    try:
        log.info(u'******开始并发%s******' % action)
        thread_list = []
        for i in range(repeat_count):
            def run():
                log.info(u'***第%s次并发%s%svnf开始***' % (i + 1, action, concurrent_count))
                func(concurrent_count)
                log.info(u'***第%s次并发%s%svnf结束***\n' % (i + 1, action, concurrent_count))

            t = Thread(target=run)
            t.start()
            thread_list.append(t)
            time.sleep(60 * 30)
        log.info('\n')
    except Exception as e:
        log.error('!!!!!![%s] failed, message is[%s]!!!!!!' % (action, e.message))

这个脚本之前都能够正常执行,准备的打印操作次数,就是***第%s次并发%s%svnf开始***,以及***第%s次并发%s%svnf结束***\n

但是今天突然发现***第5次并发实例化200vnf开始***被打印了2次,这是什么情况呢?

原来是掉到闭包的坑里了!

上诉for循环中的run函数,里面的变量i位于Enclosing(嵌套函数的外层函数内部)嵌套作用域

在真正执行时,变量i的值可能已经变了,与定义闭包时的值不同

关于作用域,可以参考https://dev.zte.com.cn/topic/#/48178

上诉for循环里有个半小时的延时,如果任务能否在半小时内执行完,那么打印就会正常,因为i的值还未发生变化。但是,如果某个任务A超过半小时,for循环就会进入下一次任务,这时i就会发生变化,当任务A执行完成时,打印的次数就会是已经发生变化的i。这就是今天突然发现***第5次并发实例化200vnf开始***被打印了2次的原因

解决方案

将变量i作为参数传给run函数,run函数内部再定义一个闭包,由run函数来生成闭包。而不是直接在闭包中使用i。即将i作为参数传递给run的count,并在run内部定义inner函数,inner函数内部使用count变量。

这样count就属于run函数的Local作用域,只受run函数内部影响,不会受for循环中i的影响

def repeat(func, action):
    try:
        log.info(u'******开始并发%s******' % action)
        for i in range(repeat_count):
            def run(count):
                def inner():
                    log.info(u'***第%s次并发%s%svnf开始***' % (count + 1, action, concurrent_count))
                    func(concurrent_count)
                    log.info(u'***第%s次并发%s%svnf结束***\n' % (count + 1, action, concurrent_count))

                return inner

            t = Thread(target=run(i))
            t.start()
            time.sleep(60 * 30)
        log.info('\n')
    except Exception as e:
        log.error('!!!!!![%s] failed, message is[%s]!!!!!!' % (action, e.message))

总结

使用Python闭包时,如果是在for循环内部生成闭包,并且闭包中使用了Enclosing嵌套作用域中的变量(比如上面的i),最好不要直接使用,而是将变量作为参数传给一个函数,该函数内部再定义一个闭包,由该函数来生成闭包

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值