这个lambda / yield / generator理解如何工作? [英] How does this lambda/yield/generator comprehension work?

查看:107
本文介绍了这个lambda / yield / generator理解如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  def optionsToArgs(options,separator ='='): 
kvs = [

%(option)s%(separator)s%(value)s%
{'option':str(k),'separator ':separator,'value':str(v)}
)for k,v in options.items()
]
return list(
reverse(
) list(
(lambda l,t:
(lambda f:
(f((yield x))for x in l)
)(lambda _:t)
)(kvs,'-o')



它似乎需要一个参数的字典,并将它们变成一个shell命令的参数列表。它看起来像是在生成器理解中使用yield,我认为这是不可能的...?

 >>> ; optionsToArgs({x:1,y:2,z:3})
['-o','z = 3','-o','x = 1' -o','y = 2']

它是如何工作的?

解决方案

由于Python 2.5, yield< value> 是一个表达式,而不是语句。请参阅 PEP 342



代码是丑陋而不必要的丑陋,但它是合法的。它的核心技巧是在生成器表达式中使用 f((yield x))。这是一个更简单的例子:

 >>> def f(val):
... returnHi
>>> x = [1,2,3]
>>>列表(f((yield a))for a x)
[1,'Hi',2,'Hi',3,'Hi']
pre>

基本上,在生成器表达式中使用 yield 会导致它为源可迭代器中的每个值生成两个值。当生成器表达式遍历字符串列表时,在每次迭代中,产生x 首先从列表中产生一个字符串。 genexp的目标表达式是 f((yield x)),因此对于列表中的每个值,生成器表达式的结果都是 f((yield x))。但是 f 只是忽略了它的参数,并且总是返回选项字符串 - o。因此,在通过生成器的每一步中,首先产生键值字符串(例如,x = 1),然后 - o 。外部列表(反转(list(...)))只是从这个生成器中列出一个列表,然后反转它,使得 - o s会出现在每个选项之前,而不是之后。



然而,没有理由这样做。有许多更可读的选择。也许最明显的是:

  kvs = [...]#同样的列表理解可以用于这部分
result = []
for keyvs in kvs:
result.append( - o)
result.append(keyval)
返回结果

即使你喜欢简洁,聪明的代码,你仍然可以做

  return sum([[ -  o,keyval]为kvs中的keyval],[])

kvs 列表理解本身是尝试可读性和不可读性的奇怪组合。它的写法更简单:

$ opt
$ b

  kvs = [str(optName)+ separator + str(optValue)for optName,optValue in options .items()] 

您应该考虑为代码放置这个代码的人。

I was looking through my codebase today and found this:

def optionsToArgs(options, separator='='):
    kvs = [
        (
            "%(option)s%(separator)s%(value)s" %  
            {'option' : str(k), 'separator' : separator, 'value' : str(v)}
        ) for k, v in options.items()
    ]
    return list(
        reversed(
            list(
                    (lambda l, t: 
                        (lambda f: 
                            (f((yield x)) for x in l)
                        )(lambda _: t)
                    )(kvs, '-o')
                )
            )
        )

It seems to take a dict of parameters and turn them into a list of parameters for a shell command. It looks like it's using yield inside a generator comprehension, which I thought would be impossible...?

>>> optionsToArgs({"x":1,"y":2,"z":3})
['-o', 'z=3', '-o', 'x=1', '-o', 'y=2']

How does it work?

解决方案

Since Python 2.5, yield <value> is an expression, not a statement. See PEP 342.

The code is hideously and unnecessarily ugly, but it's legal. Its central trick is using f((yield x)) inside the generator expression. Here's a simpler example of how this works:

>>> def f(val):
...     return "Hi"
>>> x = [1, 2, 3]
>>> list(f((yield a)) for a in x)
[1, 'Hi', 2, 'Hi', 3, 'Hi']

Basically, using yield in the generator expression causes it to produce two values for every value in the source iterable. As the generator expression iterates over the list of strings, on each iteration, the yield x first yields a string from the list. The target expression of the genexp is f((yield x)), so for every value in the list, the "result" of the generator expression is the value of f((yield x)). But f just ignores its argument and always returns the option string "-o". So on every step through the generator, it yields first the key-value string (e.g., "x=1"), then "-o". The outer list(reversed(list(...))) just makes a list out of this generator and then reverses it so that the "-o"s will come before each option instead of after.

However, there is no reason to do it this way. There are a number of much more readable alternatives. Perhaps the most explicit is simply:

kvs = [...] # same list comprehension can be used for this part
result = []
for keyval in kvs:
   result.append("-o")
   result.append(keyval)
return result

Even if you like terse, "clever" code, you could still just do

return sum([["-o", keyval] for keyval in kvs], [])

The kvs list comprehension itself is a bizarre mix of attempted readability and unreadability. It is more simply written:

kvs = [str(optName) + separator + str(optValue) for optName, optValue in options.items()]

You should consider arranging an "intervention" for whoever put this in your codebase.

这篇关于这个lambda / yield / generator理解如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆