Python中的星号符号

4 投票
2 回答
2974 浏览
提问于 2025-04-18 02:31

我在研究解决经典的FizzBuzz问题的不同方法时,偶然发现了这个:

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

这些星号是if语句的简写吗?如果是的话,这种写法是特定于print的吗?

提前谢谢你。

2 个回答

1

在Python中,星号(asterisk)用来表示乘法。如果它用在字符串上,它会把这个字符串重复指定的次数。例如:

print "test"*0
print "test"*1
print "test"*2

输出结果:

<blank line>
test
testtest

在你的例子中,有一个or条件,它是从左到右进行判断的:

print "Fizz"*(i%3 == 0) + "Buzz"*(i%5 == 0) or i 

如果FizzBuzz的值不为零或为真,Python就不会去判断i的值。

i是3的倍数时,Fizz的值为真(所以,对于所有能被3整除的i值,它会输出3)。

同样,Buzz在所有5的倍数时为真。

i能被15整除时,FizzBuzz都会输出。

只有当上述两个条件都为假时,i才会被计算并打印出来。

9

在Python中,星号(*)其实就是标准的乘法符号。它对应的是一个叫做 __mul__ 的方法,这个方法是作用在它后面的对象上的。因此,我们可以自定义这个符号的含义。这和 ifprint 没有任何关系。

对于字符串(strunicode),这个星号被重新定义为表示字符串的重复,比如 "foo" * 5 会变成 "foofoofoofoofoo"

>>> 'foo' * 5  # and the other way around 5 * "foo" also works
'foofoofoofoofoo'

"Fizz" * (i % 3 == 0) 其实是一个“聪明”的简写,等同于:

"Fizz" if i % 3 == 0 else ""

这是因为表达式 i % 3 == 0 的结果是一个布尔值,而布尔值在Python中是整数的一个子类型,所以 True == 1False == 0。因此,如果你用布尔值去“乘”一个字符串,你要么得到原来的字符串,要么得到一个空字符串。

注意:我想补充一下,根据我的经验,这种编程风格在Python中并不被推荐——这样会让代码变得不易阅读(对于新手和老手都是如此),而且也不会让代码运行得更快(实际上可能会更慢;可以参考这个快速基准测试:http://pastebin.com/Q92j8qga,有趣的是在PyPy中却不是这样:http://pastebin.com/sJtZ6uDm)。


星号(*)同样适用于 listtuple 的实例:

>>> [1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]

>>> (1, 2, 3) * 3
(1, 2, 3, 1, 2, 3, 1, 2, 3)

你还可以为自己的类型定义星号(*)操作符,这实际上就是在Python中进行的 运算符重载

class Foo(object):
    def __mul__(self, other):
        return "called %r with %r" % (self, other)

print Foo() * "hello"  # same as Foo().__mul__("hello")

输出:

called <__main__.Foo object at 0x10426f090> with 'hello'

对于像 intfloat 这样的“基本”类型,星号(*)的映射到 __mul__ 的情况也是一样的,所以 3 * 4 等同于 (3).__mul__(4)(其他运算符也是如此)。实际上,你甚至可以继承 int 并为星号(*)提供自定义的行为:

class MyTrickyInt(int):
    def __mul__(self, other):
        return int.__mul__(self, other) - 1
    def __add__(self, other):
        return int.__add__(self, other) * -1

print MyTrickInt(3) * 4  # prints 11
print MyTrickyInt(3) + 2  # prints -5

...但请不要这样做 :) (实际上,尽量避免继承具体类型是个好主意!)

撰写回答