【问题标题】:Dict comprehension, tuples and lazy evaluation字典理解、元组和惰性求值
【发布时间】:2014-01-03 17:58:19
【问题描述】:

我正在尝试看看我是否可以在 Python 中实现一些非常惰性的东西。

我有一个 dict 理解,其中的值是一个元组。我希望能够通过使用元组的第一个条目来创建元组的第二个条目。

一个例子应该会有所帮助。

dictA = {'a': 1, 'b': 3, 'c': 42}
{key: (a = someComplexFunction(value), moreComplexFunction(a)) for key, value in dictA.items()}

moreComplexFunction 是否可能使用元组第一个条目中的计算?

【问题讨论】:

  • 您可以让someComplexFunction 实现lru_cache,然后您只需调用moreComplexFunction(someComplexFunction(value)) 而不会受到性能影响。 缓存有一些开销,如果您只使用一次缓存,这可能有点过头了,所以我将此作为评论而不是答案。

标签: python python-3.x dictionary functional-programming


【解决方案1】:

您可以在单元素元组上添加第二个循环:

{key: (a, moreComplexFuntion(a)) for key, value in dictA.items() 
                                 for a in (someComplexFunction(value),)}

这使您可以在值表达式中访问someComplexFunction(value) 的输出,但这相当难看。

就个人而言,在这种情况下,我会转向常规循环:

dictB = {}
for key, value in dictA.items():
    a = someComplexFunction(value)
    dictB[key] = (a, moreComplexFunction(a))

并完成它。

【讨论】:

  • 马丁,谢谢。这似乎是一件合理的事情(至少对我而言)。显然,为了清楚起见,循环更好。不过,如果有一个我可以利用的聪明的语言功能,那就太好了。 :)
  • 我的 +1 用于常规循环。代码更简单高效。
  • 聪明的语言特性是“lambda 函数”,它是函数式编程工具包的一部分,可以让您嵌入该函数,即 {key: (lambda x: (x, moreComplexFunction(x))) (someComplexFunction(value)) 用于键,dictA.items()} 中的值。但它更丑陋,难以阅读,而且速度较慢。该循环易于阅读并且可能是最快的。
【解决方案2】:

或者,您可以编写一个函数来返回元组:

def kv_tuple(a):
    tmp = someComplexFunction(a)
    return (a, moreComplexFunction(tmp))

{key:kv_tuple(value) for key, value in dictA.items()}

这还使您可以选择使用诸如 namedtuple 之类的东西来获取元组项的名称等。我不知道这会快多少/慢多少...常规循环可能会更快(更少的函数调用)...

【讨论】:

  • 你知道,这就是我最终要做的事情,但我想要一些可以使用 Python 函数式编程模型的简洁特性的东西。
  • @fgnu:创建一个函数just 来使用理解会降低效率并且会造成混淆。只需将循环放在函数中即可。
  • @eryksun - 它可能是混淆的,或者它可能更简单。对我来说,保持语句更短让我更容易阅读(就像我说的,我更喜欢在这里命名元组)。 kv_tuple 不是一个描述性很强的名称,但我不知道它的用途......可以很容易地给它一个名称,这样上面的语句就可以更清楚地从 dictA 中的 Y 数据生成 X 数据(以及更容易阅读的函数包装)。除非有充分的理由在代码的其他地方使用kv_tuple,否则我同意,我可能也会使用循环。
  • 不,我绝对同意它的速度较慢......只是不是说它一定更难理解。
  • 我第一条评论中的斜体暗示这将是一次性使用功能。这就是为什么我建议将循环移到一个显式函数中——如果重点是让代码更容易理解的话。然后可以在表达式中调用该函数,就像使用推导一样。
【解决方案3】:

除了Martijn's answer,使用生成器表达式和字典推导也是非常语义化和懒惰的:

dictA = { ... } # Your original dict

partially_computed = ((key, someComplexFunction(value))
                      for key, value in dictA.items())

dictB = {key: (a, moreComplexFunction(a)) for key, a in partially_computed}

【讨论】:

  • 这只是引入额外循环的另一种形式:-)
  • @MartijnPieters 这正是我的想法!
  • 为什么是的,是的,它是>.
猜你喜欢
  • 2017-05-12
  • 1970-01-01
  • 1970-01-01
  • 2021-03-21
  • 2015-09-25
  • 1970-01-01
  • 1970-01-01
  • 2021-03-26
  • 2021-12-23
相关资源
最近更新 更多