为什么它有效?
Why does it work?
所以我正在学习 Python 并研究一系列程序创意。当然,我写了强制性的 FizzBuzz,它起作用了,但基本上是 if elif else blablabla。我在谷歌上搜索了一下,看看是否还有其他方法,然后发现了这个阴暗的单线:
for i in range(1,101):
print("Fizz" * (i % 3 == 0) + "Buzz" * (i % 5 == 0) or i)
没有ifs,没有elifs,什么都没有。我用谷歌搜索 "string concatenation" 并找到了有关 * 符号的信息,但不明白它在这种情况下是如何工作的。有人可以解释吗?
一旦 if (i % 5 == 0)
为真或 return i
:
,您将打印字符串 "Buzz"
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
次,在这种情况下,它最多只会重复一次,因为任一字符串仅根据布尔测试。
您可以在 ipython 中看到 True
和 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'
拆开你就明白了
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)
returns 0
。 "any string" * 0 == ""
。如果数字既不是 Fizz 也不是 Buzz,您将得到 print("" or num)
。空字符串是 Falsey,但是 num
总是 Truthy,所以它打印 num
当 i == 3
时,(i % 3 == 0)
将为真。
任何字符串 * True 都会 return 字符串。在这种情况下,将 True
视为整数 1
会有所帮助(因为乘以 1
的任何东西都是原始乘积)。
当例如。 i == 1
,(i % 3 == 0)
将为 False (as 1 % 3 == 1)
。
所以string * False
==空字符串
获取上面 return 编辑的 fizz 和 buzz 字符串,并使用 +
运算符将它们连接起来。
现在在 print 语句中,如果连接的结果是空字符串,or
运算符将使用 i
的值。
下面是对正在发生的事情的细分:
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
There are no ifs, no elifs, nothing.
当然有!只是伪装。寻找字符串连接(即 +
)对您没有帮助,因为 *
是 重复 。具体来说,string *
n 给你一个字符串,它是连续 n 个字符串的副本。此外,布尔值可以隐式转换为整数:True
变为 1
,False
变为 0
。所以
"Fizz" * (i % 3 == 0)
表示"One Fizz
if i % 3 == 0
, none if not."与Buzz
相同。
最后,最后的 or i
意味着如果你得到的是空字符串,因为两部分都是空的,那么你会得到 i
。 or
真正的意思是 "the value of the left hand side unless the left hand side is a false value, in which case return the value of the right hand side."
这个技巧也被用在其他地方。 Python 没有直接等同于 C 的 ?:
运算符,但是由于我上面提到的 bool-to-integer 转换,您可以使用一个二元素元组和一个索引操作接近一个.所以C的
a? b: c
意思是“b
如果a
为真,否则c
”在Python中变成这样:
(c, b)[a]
如果你只考虑条件:
(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")
....
这就是 "dank" 一个衬垫的工作原理。
所以我正在学习 Python 并研究一系列程序创意。当然,我写了强制性的 FizzBuzz,它起作用了,但基本上是 if elif else blablabla。我在谷歌上搜索了一下,看看是否还有其他方法,然后发现了这个阴暗的单线:
for i in range(1,101):
print("Fizz" * (i % 3 == 0) + "Buzz" * (i % 5 == 0) or i)
没有ifs,没有elifs,什么都没有。我用谷歌搜索 "string concatenation" 并找到了有关 * 符号的信息,但不明白它在这种情况下是如何工作的。有人可以解释吗?
一旦 if (i % 5 == 0)
为真或 return i
:
"Buzz"
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
次,在这种情况下,它最多只会重复一次,因为任一字符串仅根据布尔测试。
您可以在 ipython 中看到 True
和 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'
拆开你就明白了
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)
returns 0
。 "any string" * 0 == ""
。如果数字既不是 Fizz 也不是 Buzz,您将得到 print("" or num)
。空字符串是 Falsey,但是 num
总是 Truthy,所以它打印 num
当 i == 3
时,(i % 3 == 0)
将为真。
任何字符串 * True 都会 return 字符串。在这种情况下,将 True
视为整数 1
会有所帮助(因为乘以 1
的任何东西都是原始乘积)。
当例如。 i == 1
,(i % 3 == 0)
将为 False (as 1 % 3 == 1)
。
所以string * False
==空字符串
获取上面 return 编辑的 fizz 和 buzz 字符串,并使用 +
运算符将它们连接起来。
现在在 print 语句中,如果连接的结果是空字符串,or
运算符将使用 i
的值。
下面是对正在发生的事情的细分:
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
There are no ifs, no elifs, nothing.
当然有!只是伪装。寻找字符串连接(即 +
)对您没有帮助,因为 *
是 重复 。具体来说,string *
n 给你一个字符串,它是连续 n 个字符串的副本。此外,布尔值可以隐式转换为整数:True
变为 1
,False
变为 0
。所以
"Fizz" * (i % 3 == 0)
表示"One Fizz
if i % 3 == 0
, none if not."与Buzz
相同。
最后,最后的 or i
意味着如果你得到的是空字符串,因为两部分都是空的,那么你会得到 i
。 or
真正的意思是 "the value of the left hand side unless the left hand side is a false value, in which case return the value of the right hand side."
这个技巧也被用在其他地方。 Python 没有直接等同于 C 的 ?:
运算符,但是由于我上面提到的 bool-to-integer 转换,您可以使用一个二元素元组和一个索引操作接近一个.所以C的
a? b: c
意思是“b
如果a
为真,否则c
”在Python中变成这样:
(c, b)[a]
如果你只考虑条件:
(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")
....
这就是 "dank" 一个衬垫的工作原理。