今日、コードベースを調べていたところ、これが見つかりました。
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')
)
)
)
パラメータの辞書を取り、それらをシェルコマンドのパラメータのリストに変換するようです。ジェネレータ内包内で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):
... return "Hi"
>>> x = [1, 2, 3]
>>> list(f((yield a)) for a in x)
[1, 'Hi', 2, 'Hi', 3, 'Hi']
_
基本的に、ジェネレータ式でyield
を使用すると、ソース反復可能のすべての値に対して2つの値が生成されます。ジェネレータ式は文字列のリストを反復処理するため、各反復で_yield x
_が最初にリストから文字列を生成します。 genexpのターゲット式はf((yield x))
であるため、リスト内のすべての値について、ジェネレーター式の「結果」はf((yield x))
の値です。ただし、f
は引数を無視し、常にオプション文字列_"-o"
_を返します。そのため、ジェネレーターを通過するすべてのステップで、最初にキーと値の文字列(例、_"x=1"
_)、次に_"-o"
_が生成されます。外側のlist(reversed(list(...)))
はこのジェネレーターからリストを作成し、それを逆にして、_"-o"
_ sが各オプションの後ではなく前に来るようにします。
ただし、この方法で行う理由はありません。より多くの読みやすい代替があります。おそらく最も明示的なのは単純です:
_kvs = [...] # same list comprehension can be used for this part
result = []
for keyval in kvs:
result.append("-o")
result.append(keyval)
return result
_
簡潔で「賢い」コードが好きな場合でも、あなたはまだやることができます
_return sum([["-o", keyval] for keyval in kvs], [])
_
kvs
リスト内包表記自体は、読みやすさと読み難さの奇妙な組み合わせです。より簡単に書かれています:
_kvs = [str(optName) + separator + str(optValue) for optName, optValue in options.items()]
_
これをコードベースに入れた人には「介入」を手配することを検討する必要があります。
うん基本的に、これは次のように要約されます。
def f(_): # I'm the lambda _: t
return '-o'
def thegenerator(): # I'm (f((yield x)) for x in l)
for x in kvs:
yield f((yield x))
そのため、反復処理を行うと、ジェネレーターはx
(kvs
のメンバー)を生成し、次にf
の戻り値(常に-o
、すべてkvs
に対する1回の反復で。なんでも yield x
が戻り、f
に渡されるものは無視されます。
同等のもの:
def thegenerator(): # I'm (f((yield x)) for x in l)
for x in kvs:
whatever = (yield x)
yield f(whatever)
def thegenerator(): # I'm (f((yield x)) for x in l)
for x in kvs:
yield x
yield f(None)
def thegenerator(): # I'm (f((yield x)) for x in l)
for x in kvs:
yield x
yield '-o'
もちろん、これをもっと簡単にする方法はたくさんあります。元のダブルイールドトリックを使用しても、全体が
return list(((lambda _: '-o')((yield x)) for x in kvs))[::-1]