【问题标题】:How to reuse an expression in a comprehension expression?如何在理解表达式中重用表达式?
【发布时间】:2020-05-07 13:07:13
【问题描述】:

想象一个理论上的 sn-p:

# just for this example: `bad_structure` contains a list of dicts with different keys
# for the same semantic
bad_structure = [{'path': '/dir/one'}, {'subdir': '/dir/two'}]

# i want to turn this into
# { '/dir/one': some_func('/dir/one'),
#   '/dir/two': some_func('/dir/two')}

result = {}
for e in bad_structure:
  # calculate a value which we will need more than once (here the key)
  p = next(k for k in ('path', 'subdir') if k in e)
  result[p] = some_func(p)

我现在想把它变成一个dict理解,我的第一个方法是这样的:

bad_structure = [{'path': '/dir/one'}, {'path': '/dir/two'}]
result = {next(k for k in ('path', 'subdir') if k in e): 
          some_func(next(k for k in ('path', 'subdir') if k in e))
          for e in bad_structure}

其中包含两次丑陋、容易出错且速度慢的“计算”。我想将其重写为 s.th。喜欢

result = {p: some_func(p) 
          for p = next(k for k in ('path', 'subdir') if k in e)
          for e in bad_structure}

这当然不是有效的 Python 代码..

在 Python 中这样的事情可能吗?

澄清一下:我不关心理解语法,而是重用没有单独变量声明的计算(这在封闭表达式中是不可能的)

【问题讨论】:

  • 请注意,您的p 表达式可以重写为next(iter(e))

标签: python python-3.x dictionary-comprehension


【解决方案1】:

是的! Python 3.8 引入了“赋值运算符”:=,它允许您在单个表达式的局部范围内定义一个变量(例如,推导式)。在您的示例中,您可以这样做:

result = {(p := next(k for k in ('path', 'subdir') if k in e)): some_func(p) 
          for e in bad_structure}

免责声明:这不适用于 3.8 之前的任何 python 版本。

【讨论】:

  • 这很可悲 - 我坚持使用 3.7 .. :)
  • := 不在表达式范围内定义名称,而是在包含范围内。
  • 有没有办法定义一个变量(input:=open('bla')) 只对整个表达式求值一次?(这里没有 Python3.8..)
【解决方案2】:

您可以使用中间推导来绑定名称:

result = {
    p: some_func(p)
    # bind intermediate result to p
    for p in (  # nested comprehension to produce intermediate result
        next(k for k in ('path', 'subdir') if k in e)
        for e in bad_structure
    )
 }

它不是直接映射到两个单独的表达式,而是首先映射到一个公共表达式,然后被映射到两个单独的表达式。

您可以传递和重命名任意数量的值。在内部理解中创建一个元组,并在外部理解中将其解包为多个名称。

result = {
    p: some_func(e, p)
    for e, p in (
        (e, next(iter(e)))
        for e in bad_structure
    )
 }

【讨论】:

  • 嗯,但我不能再在我的表达中使用e,可以吗?
  • @frans 我添加了一个传递ep 的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-09
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
  • 1970-01-01
相关资源
最近更新 更多