2016-12-10 3 views
1

Я возился с несколькими скриптами для скрипки Fizz, когда я изучал python. Я столкнулся с этим, который отлично работает, но я не могу расшифровать, как это работает. Я знаю, как обычный шум fizz работает с циклом for и «if i% 3 == 0 и i% 5 == 0». Что меня в тупик, как "Fizz" (не я% 3) + "Buzz" (не я% 5)» работы.FizzBuzz list comprehension

x = ["Fizz"*(not i%3) + "Buzz"*(not i%5) or i for i in range(1, 100)] 
+0

Вы можете попытаться оценить детали самостоятельно для небольшого 'i' в интерактивной сессии Python:' 'Fizz" * (не 10% 3) 'или' "Buzz" * (не 5% 5) '. –

+0

В Python оператор * на строке позволяет «размножать» строку положительным целым числом ..., чтобы указать несколько раз, чтобы повторить строку. Поэтому «somestring» * 0 означает, что не повторяйте его вообще; замените его пустой строкой. Таким образом, это умное понимание списка генерирует список строк «Fizz», «Buzz», «FizzBuzz» или целых чисел на основе логического принуждения по числовым результатам различных операций по модулю (математический остаток) для каждого из чисел в диапазоне 1 до 100). –

ответ

2

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

print('aaa' * 3) # aaaaaaaaa 

Кроме того, логические значения неявно отлиты в целые числа по умножению. Таким образом, если вы делаете

"Fizz"*(not i%3) 

Во-первых, i% 3 вернет результат по модулю. Затем оператор not преобразует его в True, если результат равен 0 или False в противном случае (путем литья его в значение boolean, а затем с отрицанием значения). К тому времени применяя оператор умножения, False обращается в 0 и True превращается в 1.

Таким образом, если число делится на 3, получаем 0 в качестве результата по модулю, True при применении not, 1 при умножении, и строка Fizz тиражируется 1 раз в результате умножения. Если он не делится, мы получаем 0 как операнд для умножения, эффективно получая строку Fizz, реплицированную 0 раз, таким образом пустую строку.

То же самое можно сказать о Buzz, а результат для каждого i в диапазоне - это просто конкатенация двух.

+0

Спасибо, martinarroyo. Полагаю, я знал, что False - 0, а True - 1, просто не помещал их вместе с неявным литьем в целые числа при умножении. Спасибо за хорошо написанный ответ. – Neal

+0

Спасибо. Это очень изобретательный способ работы со значением литья: D – martinarroyo

0
>>> 3%3 
0 
>>> not 3%3 
True 
>>> 
>>> 3%2 
1 
>>> not 3%2 
False 
>>> 
>>> if 0: 
... print 'true' 
... 
>>> if 1: 
... print 'true' 
... 
true 
>>> False * 'Fizz' 
'' 
>>> True * 'Fizz' 
'Fizz' 

Вы можете видеть, что 3%3 вычисляет 0 и 0 имеет значение false. 1 оценивается как истина.

в понимании, что петли для каждого числа от 1 до 99, а если i%3 оценивается до True или i=3; 3%3, затем "Fizz" напечатан и аналогичен для "Buzz", если i%5 == 0.

Если ни "Fizz", ни "Buzz" получить печатные, часть перед or здесь: "Fizz"*(not i%3) + "Buzz"*(not i%5) or i вычисляет ''+'' так or часть состояния распечатывается, который только i.

0

Как вы знаете, оператор % возвращает остальную часть данного дивиденда и делителя. Эта операция возвращает только 0, когда операция не возвращает никакого остатка.

Например, если i % 3 == 0, то 3 - коэффициент i. Поэтому i % 3 and i % 5 вернется только 0, когда 3 или 5 может разделить i.

Таким образом, not i % 3 возвращает только 1, если i - это 3. Оператор not инвертирует выход, где ненулевой остаток (true) становится значением 0 (false). Аналогичным образом, нулевым остатком станет значение 1 (true).

Когда строка типа "Fizz" умножается на 0, она станет пустой строкой. При умножении на 1 он останется прежним. Я считаю, что это связано с численным представлением строк, но кто-то может исправить меня, если это не так.

Поэтому "Fizz" и/или "Buzz" будет существовать только на выходе из этого выражения, если i % 3 и/или i % 5 возвращения 0 остатков при. Это означает, что i делится на 3 и/или 5.

1

Список понимание выражается как

L = [mapping-expression for element in source-list if filter-expression] 

теперь, заменить «для элемента-источника списка» части с

for i in range(1, 100) 

который итерация по списку, содержащих целые числа от 1 до 99 возвращения одно целое вовремя.

"отображение-выражение" здесь

"Fizz"*(not i%3) + "Buzz"*(not i%5) or i 

который использует целое число я вернулся из "для г в диапазоне (1, 100)"

, когда я делится на 3 или 5, я % 3 и i% 5 возвращает 0, любое другое целочисленное перенастроенное, когда i не делится.

(not i % 3) # return True when i is divisible by 3 
    (not i % 5) # returns False when i is not divisible by 5 

когда булевы вернулся из (не я% 3) или (не я% 5) умножается со строками "Fizz" и "Buzz":

"Fizz" * True # returns "Fizz" 
    "Buzz" * False # returns "" 

затем Строки возвращенного выше конкатенированной

"Fizz" + "" 

в результате «Fizz» помещается в результирующий список, и этот процесс продолжается для каждой итерации, возвращая либо «Fizz» или «шум» или иногда раз целое число я сам, когда оба строка булево много plication возвращает пустую строку "". так

 "" + "" or i # returns i 

Результирующий список что-то вроде [1, 2, 'Fizz', 4 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz', 11, 'Fizz' , 13, 14, «FizzBuzz» ......]

примечание: в примере не используется опциональное выражение «if filter-expression».

0

Мой личный фаворит:

#!python 
from __future__ import print_function 
def fizz_buzz(lower=1, upper=101): 
    return ["Fizz"*(x % 3 == 0) + "Buzz"*(x % 5 == 0) or str(x) \ 
     for x in range(lower, upper)] 

print('\n'.join(fizz_buzz())) 

Все действия в выражении список понимания и большинство, что в условном выражении, которое либо оценивающего в строку («Fizz», или «Buzz» или «Fizz "+" Buzz ") или в строковое представление оцениваемого целого.

Это зависит от относительно необычного (возможно, даже неясного) оператора Python для строк ... для «умножения» строки путем дублирования и конкатенации ... а также на семантику Python относительно оценки «истины». (В пустых последовательностях Python: строках, списках и кортежах, а также в других пустых контейнерах, словарях и наборах и числовых нулях все «ложные» --- вместе со специальными Нет и Объекты False).

Назад к вопросу. Python рассматривает «умножение строки на ноль» как пустую строку. Он также обрабатывает логический объект как 1 или 0 в любом арифметическом контексте (например, умножение). Таким образом, Boolean из не i% 3 - это True, если объект делится на 3 ... то есть операция по модулю 3 возвращает ненулевое значение. Поэтому каждая из этих строк «умножается» на один или на нуль (эквивалент вызова int (not (bool (i% X))) ... где X равно 3 в одном подвыражении и 5 в другом. (Примечание : не - это унарный оператор, а не функция, но он может быть записан как вызов функции, потому что нет (x) так же, как и , а не ... посторонние круглые скобки в большинстве случаев безвредны).

Я предпочитаю возвращать (или уступать) преобразование строк целого числа именно потому, что вы можете использовать результаты из этого выражения в других функциях естественным образом (например, при вызове строки . join() способ).