是否有一个Python相当于哈斯克尔“让”的(Is there a Python equivalen

2019-06-27 15:57发布

是否有一个Python相当于哈斯克尔的“让”的表达,让我写的东西,如:

list2 = [let (name,size)=lookup(productId) in (barcode(productId),metric(size)) 
            for productId in list]

如果不是这样,这将是最可读的选择吗?

增加了澄清让利语法:

x = let (name,size)=lookup(productId) in (barcode(productId),metric(size))

相当于

(name,size) = lookup(productId)
x = (barcode(productId),metric(size))

第二个版本不与list解析的工作那么好,虽然。

Answer 1:

你可以使用一个临时表理解

[(barcode(productId), metric(size)) for name, size in [lookup(productId)]][0]

或者,等同地,发电机表达

next((barcode(productId), metric(size)) for name, size in [lookup(productId)])

但是这两个都是非常可怕的。

另一个(可怕的)的方法是通过一个临时的拉姆达,您立即拨打

(lambda (name, size): (barcode(productId), metric(size)))(lookup(productId))

我想推荐的“Python化”的方式也只是定义功能,如

def barcode_metric(productId):
   name, size = lookup(productId)
   return barcode(productId), metric(size)
list2 = [barcode_metric(productId) for productId in list]


Answer 2:

哪有这回事。 你可以模仿它以同样的方式let被脱到演算( let x = foo in bar <=> (\x -> bar) (foo) )。

最可读的替代视情况而定。 为了您的具体的例子,我会选择像[barcode(productId), metric(size) for productId, (_, size) in zip(productIds, map(lookup, productIds))] (再一想真难看,这是如果你越不需要productId过,那么你可以使用map )或明确for环(在发电机中):

def barcodes_and_metrics(productIds):
    for productId in productIds:
        _, size = lookup(productId)
        yield barcode(productId), metric(size)


Answer 3:

最近的Python版本允许多个在发电机表达的条款,所以现在你可以这样做:

list2 = [ barcode(productID), metric(size)
          for productID in list
          for (name,size) in (lookup(productID),) ]

这是类似于哈斯克尔提供过:

list2 = [ (barcode productID, metric size)
        | productID <- list
        , let (name,size) = lookup productID ]

和denotationally相当于

list2 = [ (barcode productID, metric size) 
        | productID <- list
        , (name,size) <- [lookup productID] ]


Answer 4:

在b0fh的回答条款的多是我个人一直使用现在的,而风格,因为我相信它提供了更清晰,不杂乱临时函数的命名空间。 然而,如果速度是一个问题,但要记住,临时构建一个元素列表的时间超过构建一个元组明显更长是很重要的。

比较在这个线程的各种解决方案的速度,我发现,丑陋的拉姆达黑客是最慢的,其次是嵌套的发电机,然后通过b0fh的解决方案。 然而,这些都是由一个元组冠军超越:

list2 = [ barcode(productID), metric(size)
          for productID in list
          for (_, size) in (lookup(productID),) ]

这可能不是到OP的问题那么重要,但也有其他情况下,清晰度可大大提高,并在其中一个可能希望使用列表理解,通过使用而不是为虚拟迭代器列表一个元组的情况下,速度上涨。



Answer 5:

要得到的东西隐约可比性,你要么需要做两个内涵或地图,或定义一个新的功能。 尚未提出但一种方法是将其拆分成两行,像这样。 我相信这是有点可读; 虽然可能定义自己的功能是正确的路要走:

pids_names_sizes = (pid, lookup(pid) for pid in list1)
list2 = [(barcode(pid), metric(size)) for pid, (name, size) in pids_names_sizes]


Answer 6:

只是猜测什么呢哈斯克尔,这里的替代品。 它使用什么Python中被称为“列表理解”。

[barcode(productId), metric(size)
    for (productId, (name, size)) in [
        (productId, lookup(productId)) for productId in list_]
]

你可以包括使用lambda:正如其他人建议。



Answer 7:

既然你问了最好的可读性,你可以考虑的λ-选项,但有一小搓:初始化参数。 下面是我用自己的各种选项,从我第一次尝试,并与一个我最现在用的结束。

假设我们有一个功能(未示出)获得data_structure作为参数,你需要得到x从它反复。

第一次尝试(按从休恩2012的答案):

(lambda x:
    x * x + 42 * x)
  (data_structure['a']['b'])

随着多个符号这成为可读性变差,所以接下来我想:

(lambda x, y:
    x * x + 42 * x + y)
  (x = data_structure['a']['b'],
   y = 16)

这仍然不是很可读,因为它重复的符号名。 于是我尝试:

(lambda x = data_structure['a']['b'],
        y = 16:
  x * x + 42 * x + y)()

这几乎读为“让”表达。 该任务的定位和格式当然是你的。

这个成语是很容易的开始“(”和结尾“()”的认可。

在函数表达式(也在Python),许多括号倾向于堆积在末端。 奇一出“(”是容易被发现。



Answer 8:

虽然你可以简单地写为:

list2 = [(barcode(pid), metric(lookup(pid)[1]))
         for pid in list]

你可以定义LET自己获得:

list2 = [LET(('size', lookup(pid)[1]),
             lambda o: (barcode(pid), metric(o.size)))
         for pid in list]

甚至:

list2 = map(lambda pid: LET(('name_size', lookup(pid),
                             'size', lambda o: o.name_size[1]),
                            lambda o: (barcode(pid), metric(o.size))),
            list)

如下:

import types

def _obj():
  return lambda: None

def LET(bindings, body, env=None):
  '''Introduce local bindings.
  ex: LET(('a', 1,
           'b', 2),
          lambda o: [o.a, o.b])
  gives: [1, 2]

  Bindings down the chain can depend on
  the ones above them through a lambda.
  ex: LET(('a', 1,
           'b', lambda o: o.a + 1),
          lambda o: o.b)
  gives: 2
  '''
  if len(bindings) == 0:
    return body(env)

  env = env or _obj()
  k, v = bindings[:2]
  if isinstance(v, types.FunctionType):
    v = v(env)

  setattr(env, k, v)
  return LET(bindings[2:], body, env)


Answer 9:

class let:
    def __init__(self, var):
        self.x = var

    def __enter__(self):
        return self.x

    def __exit__(self, type, value, traceback):
        pass

with let(os.path) as p:
    print(p)

但是,这是有效的一样p = os.pathp的范围并不局限在与块。 要做到这一点,你需要

class let:
    def __init__(self, var):
        self.value = var
    def __enter__(self):
        return self
    def __exit__(self, type, value, traceback):
        del var.value
        var.value = None

with let(os.path) as var:
    print(var.value)  # same as print(os.path)
print(var.value)  # same as print(None)

这里var.value将是None外有块,但os.path内它。



文章来源: Is there a Python equivalent of the Haskell 'let'