4

所以我正在学习 Python 并研究一系列程序想法。当然,我写了强制性的 FizzBu​​zz,它有效,但基本上是 if elif else blablabla。我用谷歌搜索看看是否有其他方法,发现这个潮湿的单线:

for i in range(1,101): 
    print("Fizz" * (i % 3 == 0) + "Buzz" * (i % 5 == 0) or i)

没有ifs,没有elifs,什么都没有。我用谷歌搜索“字符串连接”并找到有关 * 符号的信息,但不明白在这种情况下它是如何工作的。有人可以解释一下吗?

4

6 回答 6

2

您将打印字符串"Buzz" 一次if (i % 5 == 0)为 True 或返回i

In [5]: "foo" * 2
Out[5]: 'foofoo'

In [6]: "foo" * 3
Out[6]: 'foofoofoo'

In [7]: i = 5
In [8]: "foo" *  (i % 5 == 0) or i
Out[9]: 'foo'  
In [9]: "foo" *  (i % 5 == 1) or i
Out[22]: 5

同样的逻辑适用于“Fizz”有时(i % 3 == 0)会是 True,所以我们只看到一次,当它是 False 时,我们看不到它。

当您*在字符串上使用运算符时,它将重复字符串n次数,在这种情况下,它最多会重复一次,因为任一字符串仅根据布尔测试的结果打印。

True你可以在 ipython 中看到和发生了什么False

In [26]: "foo" * True
Out[26]: 'foo'

In [27]: "foo" * False
Out[27]: ''

基本上True * "foo"相当于1 * "foo" "foo" * False相当于0 * "foo"

Bool 是 int 的子类,因此代码利用了这一事实,您有时会看到类似的逻辑用于基于测试索引列表,但不推荐:

In [31]: d = ["bar","foo"]   
In [32]: d[3<2] # False so we get 0 the first element
Out[32]: 'bar'   
In [33]: d[3>2] # True so we get 1 the second element
Out[33]: 'foo'
于 2015-02-24T00:33:53.163 回答
2

打破它,你会明白的。

def does_it_fizz(num):
    return num % 3 == 0

def does_it_buzz(num):
    return num % 5 == 0

for num in range(1, 101):
    print("Fizz" * does_it_fizz(num) + "Buzz" * does_it_buzz(num) or num)

字符串乘法重复字符串,所以'a' * n也是aaaaa...n times...a。如果i % 3 != 0,则does_it_fizz(i)返回0"any string" * 0 == "". 如果数字既不应该是 Fizz 也不应该是 Buzz,你会得到print("" or num). 空字符串是 Falsey,但num始终是 Truthy,所以它打印num

于 2015-02-24T00:36:20.953 回答
2

没有ifs,没有elifs,什么都没有。

当然有!只是伪装。寻找字符串连接(即+)不会帮助你,因为*重复。具体来说,字符串*n 为您提供一个字符串,该字符串是连续 n 个字符串的副本。此外,布尔值可以隐式转换为整数:Truebecome1Falsebecome 0。所以

"Fizz" * (i % 3 == 0)

意思是“一个Fizz如果i % 3 == 0,没有如果不是”。与 相同Buzz

最后,这or i意味着如果你得到空字符串,因为这两个部分都是空的,那么你会得到ior真正的意思是“左侧的值,除非左侧是假值,在这种情况下返回右侧的值。”

这个技巧也可以在其他地方使用。Python 没有直接等效于 C 的?:运算符,但是由于我上面提到的布尔到整数的转换,您可以通过两个元素的元组和索引操作接近一个。所以C

a? b: c

这意味着“b如果a为真,否则c”在 Python 中变为:

(c, b)[a]
于 2015-02-24T00:41:15.077 回答
1

如果您只考虑条件:

(i % 3 == 0)

这会生成一个布尔值,说明 i 模 3 的特定值是否等于 0。这是 3 的倍数或 0(0、3、6 等)的情况。所以这就是你如何知道打印“Fizz”(或“Buzz”,给定另一个条件)。

Python 中字符串的一个很酷的地方是你可以有条件地打印一个字符串。例如,启动一个解释器并输入:

'foo' * True
'foo' * False

这应该会产生以下输出:

'foo'
''

所以基本上,对于给定的 i 值,你正在这样做:

print("Fizz" * (0 % 3 == 0) + "Buzz" * (0 % 5 == 0) or i) -> print("Fizz" * True + "Buzz" * True or i) -> printf('Fizz'+'Buzz')
print("Fizz" * (1 % 3 == 0) + "Buzz" * (1 % 5 == 0) or i) -> print("Fizz" * False + "Buzz" * False or i) -> printf(1)
print("Fizz" * (2 % 3 == 0) + "Buzz" * (2 % 5 == 0) or i) -> print("Fizz" * False + "Buzz" * False or i) -> printf(2)
print("Fizz" * (3 % 3 == 0) + "Buzz" * (3 % 5 == 0) or i) -> print("Fizz" * True + "Buzz" * False or i) -> printf("Fizz")
....

这就是“潮湿”一班轮的工作原理。

于 2015-02-24T00:53:09.030 回答
1

当 时i == 3(i % 3 == 0)将为真。

任何字符串 * True 都将返回该字符串。在这种情况下,True将其视为整数会有所帮助(因为乘以的任何东西都是被相乘的原始东西)。11

当例如。i == 1,(i % 3 == 0)将是 False (as 1 % 3 == 1)

所以string * False== 空字符串

获取上面返回的嘶嘶声和嗡嗡声字符串,并使用+运算符将​​它们连接起来。

现在在 print 语句中,如果该连接的结果是空字符串,则or运算符将使用值 ofi代替。

于 2015-02-24T00:39:46.803 回答
1

以下是正在发生的事情的细分:

for i in range(1,101):
    if (i % 3 == 0):
        print "Fizz"
    if (i % 5 == 0):
        print "Buzz"
    if (i % 5 != 0 and (i % 3 != 0)):
        print i

我的 ide 设置为 Python 2.7 btw

于 2015-02-24T00:40:54.867 回答