【问题标题】:Python lambda & listPython lambda 和列表
【发布时间】:2021-06-05 20:29:53
【问题描述】:

我有这个简单的 python 代码:

TOPICS = ['dacha/1', 'dacha/2']

def publish(topic, payload):
  print(f"Publish -> Topic: {topic}, Payload: {payload}")  

publishers = []
for topic in TOPICS:
  print(topic)
  pub = lambda payload: publish(topic, payload)
  publishers.append(pub)

pub1, pub2 = publishers

pub1("HI!")
pub2("HI!")

和我的输出:

dacha/1
dacha/2

Publish -> Topic: dacha/2, Payload: HI!
Publish -> Topic: dacha/2, Payload: HI!

当我在创建时传递不同的主题时,为什么主题相同? 也许我使用的 lambda 不正确,或者只是它们不受这种方式的支持? 或者它只是一个python bug,我的python是:3.9.3

同样的结果:

pub1, pub2 = [
  (lambda payload: publish(topic, payload))
  for topic in TOPICS
]

【问题讨论】:

  • 是的,这不是错误,不用担心。无法帮助找到更多信息,尝试搜索更多,围绕这个主题有很多问题。
  • 问题是当调用 pub() 时,它使用最后一个值 'topic' 调用它,而不是它在创建 pub 时的值。 lambda 函数不在内存中存储变量
  • 是的,非常感谢,也许您知道另一种方法吗?

标签: python list lambda


【解决方案1】:

好的,让我们试着弄清楚到底是什么问题,尝试在循环后删除局部变量topic

def publish(topic, payload):
  print(f"Publish -> Topic: {topic}, Payload: {payload}")  

publishers = []
for topic in TOPICS:
  print(topic)
  pub = lambda payload: publish(topic, payload)
  publishers.append(pub)
del topic     ########## <--------------------------------- This one
pub1, pub2 = publishers
pub1("HI!")
pub2("HI!")

如果这样做,Python 稍后会在尝试评估 pub1 时抛出错误:

Traceback (most recent call last):
  File "<input>", line 14, in <module>
  File "<input>", line 9, in <lambda>
NameError: name 'topic' is not defined

所以,这意味着 Python 正在寻找 topic 的局部变量引用,这就是为什么你的输出总是只有第二个主题,因为到时间循环退出时,主题总是会有最后一个项目在列表中。

进一步调试:

尝试更改您的publish 函数,并以格式化字符串返回变量主题的id

def publish(topic, payload):
  print(f"Publish -> Topic: {id(topic)}, Payload: {payload}") 

输出如下:

dacha/1
dacha/2
Publish -> Topic: 2574286013360, Payload: HI!
Publish -> Topic: 2574286013360, Payload: HI!

如您所见,两个主题都有相同的id,毫无疑问两者都引用相同的值。

那么,如何解决?

您可以使用lambda 函数范围内的变量,而不是使用局部变量。 您可以将 lambda 函数更改为:

lambda payload, topic=topic: publish(topic, payload)

它将做的是,它将另一个名为topic的变量保留在lambda本身的范围内,也就是说,它将存储它自己的topic值的副本,结果仍然存在尽管稍后更改了局部变量 topic 的值的操作,但完好无损。

输出

dacha/1
dacha/2
Publish -> Topic: dacha/1, Payload: HI!
Publish -> Topic: dacha/2, Payload: HI!

【讨论】:

    【解决方案2】:

    万岁,我找到了一个可行的解决方案,只需更改此行: pub = lambda payload: publish(topic, payload) 这个pub = (lambda payload, topic=topic: publish(topic, payload)) 结果:

    TOPICS = ['dacha/1', 'dacha/2']
    
    def publish(topic, payload):
      print(f"Publish -> Topic: {topic}, Payload: {payload}")  
    
    publishers = []
    for topic in TOPICS:
      print(topic)
      pub = (lambda payload, topic=topic: publish(topic, payload))
      publishers.append(pub)
    
    pub1, pub2 = publishers
    
    pub1("HI!")
    pub2("HI!")
    

    输出:

    dacha/1
    dacha/2
    Publish -> Topic: dacha/1, Payload: HI!
    Publish -> Topic: dacha/2, Payload: HI!
    

    这对我有帮助:Python lambda's binding to local values

    【讨论】:

      猜你喜欢
      • 2016-04-10
      • 1970-01-01
      • 1970-01-01
      • 2018-02-06
      • 2020-04-27
      • 1970-01-01
      • 2023-01-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多