You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将lambda函数传入threading.Thread时的结果异常问题排查与修复

Python多线程中Lambda捕获变量导致重复值问题及解决方法

我是Python新手,代码若未遵循最佳实践请见谅,也欢迎大家提出Pythonic的改进建议。

我编写了如下代码,期望根据名称输出对应问候语,但实际输出两次都显示名称Sal:

from time import sleep
import threading

def printGreating(get_greeting):
    sleep(5)
    greeting = get_greeting()
    print(greeting)

def createGreeting(greeting,name):
    return greeting+' '+ name

nameslist = ["Sam","Sal"]
threads = []

for n in nameslist:
    print(n)

    if n == "Sam":
        create_greeting_l = lambda : createGreeting("Hello",n)
    else:
        create_greeting_l = lambda : createGreeting("Greeting",n)

    t = threading.Thread(target=printGreating, args=(create_greeting_l,))
    t.start()
    threads.append(t)

for t in threads:
    t.join()

print('-------------------Completed--------------')

期望输出:

Sam
Sal
Hello Sam
Greeting Sal
-------------------Completed--------------

实际输出:

Sam
Sal
Greeting Sal
Hello Sal

问题原因

Lambda表达式在循环中捕获变量n时,不会立即绑定当前迭代的n值,而是在Lambda被调用时(也就是线程执行get_greeting()时)才去查找n的当前值。循环结束后,n的最终值是"Sal",所以两个Lambda调用时都使用了这个值,导致输出重复。

解决方案

方法1:将名称作为参数传入Lambda(我找到的解决方法)

通过给Lambda添加参数,并在创建线程相关对象时传入当前的n值,强制绑定迭代时的变量值:

if n == "Sam":
    create_greeting_l = lambda a : createGreeting("Hello",a)
else:
    create_greeting_l = lambda a : createGreeting("Greeting",a)
t = GreeterClass(create_greeting_l,n)

方法2:用Lambda默认参数绑定当前值

更简洁的方式是利用Lambda的默认参数特性,在定义时就绑定当前的n值:

for n in nameslist:
    print(n)
    if n == "Sam":
        create_greeting_l = lambda n=n: createGreeting("Hello", n)
    else:
        create_greeting_l = lambda n=n: createGreeting("Greeting", n)
    
    t = threading.Thread(target=printGreating, args=(create_greeting_l,))
    t.start()
    threads.append(t)

方法3:使用functools.partial(更Pythonic)

functools.partial可以直接创建带有预设参数的可调用对象,代码更清晰易读,避免Lambda闭包的陷阱:

from time import sleep
import threading
from functools import partial

def print_greeting(get_greeting):
    sleep(5)
    greeting = get_greeting()
    print(greeting)

def create_greeting(greeting,name):
    return greeting+' '+ name

nameslist = ["Sam","Sal"]
threads = []

for n in nameslist:
    print(n)
    if n == "Sam":
        get_greeting = partial(create_greeting, "Hello", n)
    else:
        get_greeting = partial(create_greeting, "Greeting", n)
    
    t = threading.Thread(target=print_greeting, args=(get_greeting,))
    t.start()
    threads.append(t)

for t in threads:
    t.join()

print('-------------------Completed--------------')

Pythonic改进建议

  • 函数名遵循PEP8规范:比如printGreating改为print_greeting,createGreeting改为create_greeting,提升代码可读性。
  • 优先使用functools.partial替代复杂的Lambda闭包,尤其是在循环中创建可调用对象时,能避免变量捕获的问题。
  • 可以考虑将线程逻辑封装成类,让代码结构更清晰(如示例中的GreeterClass思路)。

内容的提问来源于stack exchange,提问作者samsal77

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 23:55:16