8

Stack Overflow ( Zen of Python ) に関する別の質問を読んでいたところ、Jaime Soriano の回答で次の行に出くわしました。

import this
"".join([c in this.d and this.d[c] or c for c in this.s])

上記を Python シェルに入力すると、次のように出力されます。

"The Zen of Python, by Tim Peters\n\nBeautiful is better than ugly.\nExplicit is
better than implicit.\nSimple is better than complex.\nComplex is better than 
complicated.\nFlat is better than nested.\nSparse is better than dense.
\nReadability counts.\nSpecial cases aren't special enough to break the rules.
\nAlthough practicality beats purity.\nErrors should never pass silently.
\nUnless explicitly silenced.\nIn the face of ambiguity, refuse the temptation to
guess.\nThere should be one-- and preferably only one --obvious way to do it.
\nAlthough that way may not be obvious at first unless you're Dutch.\nNow is 
better than never.\nAlthough never is often better than *right* now.\nIf the 
implementation is hard to explain, it's a bad idea.\nIf the implementation is
easy to explain, it may be a good idea.\nNamespaces are one honking great idea 
-- let's do more of those!"

そしてもちろん、私は上記のリストを理解するために午前中を費やすことを余儀なくされました... 理解... こと。難読化されていることをきっぱりと宣言することをためらっていますが、それは、プログラミングを始めてわずか 1 か月半であり、そのような構造が Python で一般的であるかどうかについて確信が持てないためです。

this.s上記の印刷物のエンコードされたバージョンが含まれています。

"Gur Mra bs Clguba, ol Gvz Crgref\n\nOrnhgvshy vf orggre guna htyl.\nRkcyvpvg vf orggre guna vzcyvpvg.\nFvzcyr vf orggre guna pbzcyrk.\nPbzcyrk vf orggre guna pbzcyvpngrq.\nSyng vf orggre guna arfgrq.\nFcnefr vf orggre guna qrafr.\nErnqnovyvgl pbhagf.\nFcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.\nNygubhtu cenpgvpnyvgl orngf chevgl.\nReebef fubhyq arire cnff fvyragyl.\nHayrff rkcyvpvgyl fvyraprq.\nVa gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.\nGurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.\nNygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.\nAbj vf orggre guna arire.\nNygubhtu arire vf bsgra orggre guna *evtug* abj.\nVs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.\nVs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.\nAnzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"

そしてthis.d、デコードする暗号を含む辞書が含まれていますthis.s:

{'A': 'N', 'C': 'P', 'B': 'O', 'E': 'R', 'D': 'Q', 'G': 'T', 'F': 'S', 'I': 'V', 'H': 'U', 'K': 'X', 'J': 'W', 'M': 'Z', 'L': 'Y', 'O': 'B', 'N': 'A', 'Q': 'D', 'P': 'C', 'S': 'F', 'R': 'E', 'U': 'H', 'T': 'G', 'W': 'J', 'V': 'I', 'Y': 'L', 'X': 'K', 'Z': 'M', 'a': 'n', 'c': 'p', 'b': 'o', 'e': 'r', 'd': 'q', 'g': 't', 'f': 's', 'i': 'v', 'h': 'u', 'k': 'x', 'j': 'w', 'm': 'z', 'l': 'y', 'o': 'b', 'n': 'a', 'q': 'd', 'p': 'c', 's': 'f', 'r': 'e', 'u': 'h', 't': 'g', 'w': 'j', 'v': 'i', 'y': 'l', 'x': 'k', 'z': 'm'}

私が知る限り、Jaime のコードの実行の流れは次のように
なります。 1. ループc for c in this.sは c に値を代入します
2. ステートメントc in this.dが True と評価された場合、"and" ステートメントはすぐ右にあるものを実行します、この場合はthis.d[c].
3. ステートメントc in this.dが False と評価された場合 (Jaime のコードでは発生しません)、「or」ステートメントは、たまたまそのすぐ右にあるものを実行します。この場合は loopc for c in this.sです。

その流れで正しいでしょうか?

実行の順序が正しいとしても、これにはまだ多くの疑問が残ります。<1> のコードが複数の条件ステートメントの後の行の最後にあるのに、なぜ <1> が最初に実行されるのでしょうか? 言い換えれば、なぜforループは実行を開始して値を代入するのに、実際にはコード実行の後の時点でしか値を返さないのでしょうか?

また、おまけとして、オランダ語に関する Zen ファイルの奇妙な行は何ですか?

追記:今さら言うのも恥ずかしいが、3秒前までグイド・ヴァン・ロッサムはイタリア人だと思っていた。彼のウィキペディアの記事を読んだ後、完全に理解していなくても、その行がそこにある理由を少なくとも理解しました.

4

6 に答える 6

11

リスト内包表記の演算子は、次のように関連付けられます。

"".join([(((c in this.d) and this.d[c]) or c) for c in this.s])

リスト内包表記の削除:

result = []
for c in this.s:
   result.append(((c in this.d) and this.d[c]) or c)
print "".join(result)

-ステートメントをエミュレートするために使用されるand/orブールのトリッキーを削除します。ifelse

result = []
for c in this.s:
   if c in this.d:
      result.append(this.d[c])
   else:
      result.append(c)
print "".join(result)
于 2010-08-24T17:29:50.220 に答える
2

一般に、リスト内包表記は次の形式です。

[ expression for var in iterator ]

リスト内包表記を書き留めるとき、私はしばしば書くことから始めます

[ for var in iterator ]

何年にもわたる手続き型プログラミングが、最初に来る部分としてforループの側面を私の心に教え込んできたからです。

そして、あなたが正しく指摘しているように、forループは最初に「実行」されているように見える部分です。

ループを通過するたびに、式が評価されます。(マイナーポイント:式が評価され、ステートメントが実行されます。)

したがって、この場合、

[ expression for c in this.s ]

this.sは文字列です。Pythonでは、文字列はイテレータです。あなたが書くとき

for c in some_string:

ループは文字列内の文字を繰り返し処理します。したがってc、this.sの各文字を順番に引き受けます。

今、式は

c in this.d and this.d[c] or c

これは、三項演算として知られているものです。そのリンクは論理を説明していますが、基本的な考え方は

if c in this.d:
    the expression evaluates to this.d[c]
else:
    the expression evaluates c

したがって、条件は、dictに値を持つキーがあるc in this.dことを確認することです。含まれている場合はを返し、そうでない場合は自分自身を返します。this.dcthis.d[c]c

それを書く別の方法は

[this.d.get(c,c) for c in this.s]

getメソッドの2番目の引数は、最初の引数がdictにない場合に返されるデフォルト値です)。

PS。三部形式

condition and value1 or value2

エラーが発生しやすいです。condition(がTrueの場合に何が起こるかを考えてみてください。ただし、value1がTrueであるため、三部形式はに評価されると期待できます。つまり、。しかし、ブール値があるため、三部形式は代わりに評価されます。したがって、注意しないとこの落とし穴を認識していると、三部形式はエラーを引き起こす可能性があります。)Noneconditionvalue1NoneNoneFalsevalue2

Pythonの最新バージョンの場合、これを作成するためのより良い方法は次のようになります。

value1 if condition else value2

上記の落とし穴の影響を受けません。がTrueの場合condition、式は常にに評価されvalue1ます。

しかし、上記の特定のケースでは、私は好むでしょうthis.d.get(c,c)

于 2010-08-24T17:37:54.667 に答える
2

あなたの分析は近いです。リスト内包表記です。(ところで、外側の角括弧が削除された場合、同じ出力が得られます。これはジェネレータ内包表記と呼ばれます)

hereにいくつかのドキュメントがあります。

リスト内包表記の基本形は

[expression for var in enumerable if condition]

それらは次の順序で評価されます。

  1. 列挙可能が評価される
  2. 各値は順番に var に割り当てられます
  3. 状態はチェック済み
  4. 式が評価される

結果は、条件が真であった列挙可能な各要素の式の値のリストです。

この例では条件を使用していないため、いくつかの括弧を追加した後に残るのは次のとおりです。

[(c in this.d and this.d[c] or c) for c in (this.s)]

this.s列挙可能です。c反復変数です。c in this.d and this.d[c] or cが表現です。

c in this.d and this.d[c] or cは、python の論理演算子の短絡的な性質を使用して、 と同じことを実現しthis.d[c] if c in this.d else cます。

全体として、これを難読化とはまったく呼びません。リスト内包表記の威力を理解すれば、非常に自然に見えます。

于 2010-08-24T17:31:16.577 に答える
2

"".join([c in this.d and this.d[c] or c for c in this.s])確かに難読化されています。これが Zen バージョンです。

this.s.decode('rot13')

于 2010-08-24T23:42:14.377 に答える
2

あなたは流れについて正しいです。

ループは一種[dosomething(c) for c in this.s]のリスト内包表記であり、this.s 内のすべての c に対して dosomething として読み取る必要があります。

オランダ語の部分は、python の作成者である Guido Van Rossum についてです。オランダ人です。

于 2010-08-24T17:29:02.220 に答える
0

if else とジェネレーターを備えた私のバージョン:

import this ## prints zenofpython
print '-'*70
whatiszenofpython = "".join(this.d[c] if c in this.d else c for c in this.s)
zen = ''
for c in this.s:
    zen += this.d[c] if c in this.d else c
print zen

言語バージョン: これをインポートすると、そのメイン プログラムがメッセージ this.s をデスクランブルして出力します。メッセージをデスクランブルするには、dict this.d にある文字をデコードされた対応する部分 (大文字/小文字が異なる) に置き換えます。他の文字は変更する必要はありませんが、そのまま印刷します。

于 2010-08-24T19:12:00.570 に答える