Рассечение строки (запутанного?) Python

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

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

И поэтому, конечно, я был вынужден провести все утро, пытаясь понять вышеприведенный список ... Понимание ... вещь. Я не решаюсь категорически объявить его запутанным, но только потому, что я программирую всего полтора месяца, и поэтому не уверен, что такие конструкции являются обычным явлением в 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'}

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

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

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

Редактировать: Хотя мне стыдно говорить это сейчас, пока три секунды назад я не предположил, что Гвидо ван Россум был итальянцем. Прочитав его статью в Википедии, я, по крайней мере, понимаю, если не до конца понимаю, почему эта строка там.

8
задан Community 23 May 2017 в 12:19
поделиться

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)

Удаление логического значения и/или обман, который используется для эмуляции оператора 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)
11
ответ дан 5 December 2019 в 08:50
поделиться

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

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

Основная форма понимания списка -

[expression for var in enumerable if condition]

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

  1. вычисляется перечислимое
  2. Каждое значение, в свою очередь, присваивается переменной
  3. проверяется условие
  4. вычисляется выражение

Результатом является список значений выражений для каждого элемента перечисляемого, для которого условие было истинным.

В этом примере не используется условие, поэтому после добавления скобок остается:

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

this.s - это перечислимый. c - повторяющаяся переменная. c в this.d и this.d [c] или c - это выражение.

c в this.d и this.d [c] или c использует короткозамкнутую природу логических операторов Python для достижения того же, что и this.d [c] if c в this. d иначе c .

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

2
ответ дан 5 December 2019 в 08:50
поделиться

Моя версия с современным 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, его основная программа расшифровывает и распечатывает сообщение this.s Чтобы расшифровать сообщение, замените те буквы, которые находятся в dict this.d, их декодированными частями (верхний / нижний регистр разные). Остальные буквы менять не нужно, их нужно печатать как есть.

0
ответ дан 5 December 2019 в 08:50
поделиться

"". Join ([c в this.d и this.d [c] или c вместо c в this.s]) , безусловно, запутано. Вот версия Zen:

this.s.decode ('rot13')

2
ответ дан 5 December 2019 в 08:50
поделиться

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

Цикл имеет вид [dosomething(c) для c в this.s] Это понимание списка, и его следует читать как выполнение для всех c в this.s.

Голландская часть рассказывает о Гвидо Ван Россуме, создателе питона, голландце.

2
ответ дан 5 December 2019 в 08:50
поделиться

Как правило, списковые включения имеют следующую форму:

[ 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 берет на себя каждый из символов в этом.с в порядке.

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

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 в this.d заключается в том, чтобы просто проверить, что dict this.d имеет ключ со значением с. Если это так, верните this.d[c], а если нет, верните сам c.

Другой способ написать это будет

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

(второй аргумент метода get — это значение по умолчанию, возвращаемое, когда первый аргумент отсутствует в словаре).

ПС. Троичная форма

condition and value1 or value2

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

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

value1 if condition else value2

Он не восприимчив к упомянутая выше ловушка. Если условие равно True, выражение всегда оценивается как значение1.

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

2
ответ дан 5 December 2019 в 08:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: