Рассечение линии (запутано?) Питон

Я читал еще один вопрос о переполнении стека (Дзен питона), и я наткнулся на эту строку в ответ Хайме Сориано:

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 PetersnnBeautiful 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!"

this.s содержит закодированную версию вышеуказанной распечатки:

"Gur Mra bs Clguba, ol Gvz CrgrefnnOrnhgvshy 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'}

насколько я могу судить, поток выполнения в коде Хайме выглядит так:
1. петля c for c in this.s присваивает значение c
2. если утверждение c in this.d вычисляет значение True, оператор " and " выполняет что бы ни случилось с его непосредственным правом, в этом случае this.d[c].
3. если утверждение c in this.d оценивает значение False (что никогда не происходит в коде Хайме), оператор "или" выполняет все, что происходит справа от него, в этом случае цикл c for c in this.s.

Я прав насчет этого потока?

даже если я прав насчет порядка исполнения, это все равно оставляет мне массу вопросов. Почему Первое, что нужно выполнить, даже если код для него приходит последним в строке после нескольких условных операторов? Другими словами, почему for цикл начинает выполняться и присваивать значение, но затем фактически возвращает значение на более позднем этапе выполнения кода, если вообще?

кроме того, для бонусных очков, что со странной строкой в файле Zen о голландцах?

Edit:

6 ответов


операторы в строке понимания списка ассоциируются следующим образом:

"".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 логический обман, который используется для эмуляции if-else о себе:

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

вы правы насчет потока.

цикл имеет вид [dosomething(c) for c in this.s] Это понимание списка и должно читаться как dosomething для всех c в этом.s.

голландская часть о Guido Van Rossum создатель python голландский.


ваш анализ близок. Это понимание списка. (кстати, тот же результат получился бы, если бы были исключены внешние квадратные скобки, что можно было бы назвать пониманием генератора)

есть некоторая документация здесь.

основной формой понимания списка является

[expression for var in enumerable if condition]

они оцениваются в следующем порядке:

  1. enumerable оценивается
  2. каждому значению в свою очередь присваивается ВАР
  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.

в целом, я бы не назвал это запутанным вообще. Как только вы поймете силу понимания списка, это будет выглядеть вполне естественно.


как правило, список постижений имеет следующую форму:

[ expression for var in iterator ]

когда я записываю понимание списка, я часто начинаю писать

[ for var in iterator ]

потому что многие годы процедурного программирования привили мне аспект for-loop как часть, которая приходит первой.

и, как вы правильно заметили, for-loop-это часть, которая, кажется, "выполняется" первой.

для каждого прохода через цикл выражение оцененный. (Незначительный момент: выражения вычисляются, операторы выполняются.)

Итак, в этом случае у нас есть

[ expression for c in this.s ]

этого.S-это строка. В Python строки являются итераторами! Когда вы пишете

for c in some_string:

цикл повторяет символы в строке. Так что c принимает на себя каждый из символов в этом.С в порядке.

теперь выражение

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

условие c in this.d таким образом, просто убедитесь, что дикт this.d есть ключ со значением c. Если это произойдет, вернитесь this.d[c], а если нет, вернуть .

другой способ написать это было бы

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

(второй аргумент метод GET значение по умолчанию возвращается, если первый аргумент не в словарь.)

PS. Троичная форма

condition and value1 or value2

подвержен ошибкам. (Подумайте, что произойдет, если condition - это верно, но value1 is None. С condition верно, вы можете ожидать, что троичная форма будет оцениваться до value1, то есть None. Но с None имеет логическое значение False, троичная форма оценивается в value2 вместо. Таким образом, если вы не будете осторожны и осознаете эту ловушку, троичная форма может ввести ошибки.)

для современных версии Python лучший способ написать это было бы

value1 if condition else value2

он не восприимчив к упомянутой выше ловушке. Если condition истинно, выражение всегда вычисляется как value1.

но в конкретном случае выше, я бы предпочел this.d.get(c,c).


"".join([c in this.d and this.d[c] or c for c in this.s]) - Это, конечно, запутанный. Вот Дзэн-версия:

this.s.decode('rot13')


моя версия с современным 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

устная версия: импортируйте это, основная программа его расшифровывает и печатает сообщение об этом.с Чтобы расшифровать сообщение, замените те буквы, которые находятся в dict this.d с их декодированными встречными частями (верхний/нижний регистр отличается). Другие буквы не нужно менять, а печатать так, как они есть.