百分号在Python中是一个操作符,其含义根据上下文不同而不同。很多内容在其他答案中已经提到(或者暗示了),但我认为提供更详细的总结有助于理解。
%
用于数字:取模运算/余数/剩余部分
百分号是Python中的一个操作符。它的描述如下:
x % y remainder of x / y
它会给出你用 x 除以 y 的 余数,即使你使用 "floor divide"(向下取整除法)。通常来说(至少在 Python 中),对于一个数 x 和一个除数 y:
x == y * (x // y) + (x % y)
例如,如果你将5除以2:
>>> 5 // 2
2
>>> 5 % 2
1
>>> 2 * (5 // 2) + (5 % 2)
5
通常使用模运算来测试一个数字是否可以被另一个数字整除,这是因为一个数的倍数对该数进行模运算得到的结果为0:
>>> 15 % 5 # 15 is 3 * 5
0
>>> 81 % 9 # 81 is 9 * 9
0
在您的示例中,如果一个数是另一个数(除了它自己和1)的倍数,那么它就不能是质数,这就是此代码的作用:
if n % x == 0:
break
如果您发现 n % x == 0
不够描述清晰,您可以将它放入另一个函数,使用更易理解的名称:
如果你觉得 n % x == 0
不是很形象化,你可以把它放到另一个函数中,用一个更具描述性的名称:
def is_multiple(number, divisor):
return number % divisor == 0
...
if is_multiple(n, x):
break
除了is_multiple
,也可以命名为evenly_divides
或其他类似的名称。这就是被测试的内容。
类似于它常常被用来确定一个数字是"奇数"还是"偶数":
def is_odd(number):
return number % 2 == 1
def is_even(number):
return number % 2 == 0
在某些情况下,当需要循环(往返)行为时,还可将其用于数组/列表索引,然后只需通过“索引”对“数组长度”取模即可实现:
>>> l = [0, 1, 2]
>>> length = len(l)
>>> for index in range(10):
... print(l[index % length])
0
1
2
0
1
2
0
1
2
0
注意,标准库中也有一个与此运算符相关的函数operator.mod
(别名为operator.__mod__
):
>>> import operator
>>> operator.mod(5, 2)
1
除了常规的赋值操作,还有增强赋值操作%=
,它将结果分配回变量:
>>> a = 5
>>> a %= 2
>>> a
1
对于字符串,其含义完全不同,在这里它是做字符串格式化的一种方式(我认为是最有限和丑陋的方法):
>>> "%s is %s." % ("this", "good")
'this is good'
在这个字符串中,%
代表一个占位符,后面跟着一个格式化规范。在这种情况下,我使用了%s
,意思是它期望一个字符串。然后字符串后面跟着一个%
,表示左侧的字符串将由右侧格式化。在这种情况下,第一个%s
被第一个参数this
替换,第二个%s
被第二个参数 (good
)替换。
请注意,有更好的(可能是基于个人观点的)格式化字符串的方法:
>>> "{} is {}.".format("this", "good")
'this is good.'
%
在Jupyter/IPython中的魔法命令
引用文档:
对于Jupyter用户来说,魔法命令是特定于IPython内核并由其提供的。是否在内核上可用是内核开发人员基于每个内核做出的决策。为了正常工作,魔法必须使用不在底层语言中有效的语法元素。例如,IPython内核使用%
语法元素作为魔法,因为%
在Python中不是有效的一元运算符。而这种语法元素在其他语言中具有意义。
这在Jupyter笔记本和类似环境中经常使用:
In [1]: a = 10
b = 20
%timeit a + b # one % -> line-magic
54.6 ns ± 2.7 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [2]: %%timeit # two %% -> cell magic
a ** b
362 ns ± 8.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
在NumPy / Pandas生态系统中,数组上的%
运算符
当应用于这些数组时,%
运算符仍然是模数运算符,但它返回一个包含数组中每个元素余数的数组:
>>> import numpy as np
>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a % 2
array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
为您自己的类定制%
运算符
当应用于您自己的类时,您当然可以定制%
运算符的工作方式。通常,您只应该使用它来实现模数操作!但这只是一条指南,不是硬性规定。
这里提供一个简单的示例,展示它如何工作:
class MyNumber(object):
def __init__(self, value):
self.value = value
def __mod__(self, other):
print("__mod__ called on '{!r}'".format(self))
return self.value % other
def __repr__(self):
return "{self.__class__.__name__}({self.value!r})".format(self=self)
这个例子并不是很有用,它只是打印然后将操作委托给存储的值,但它展示了当将 %
应用于一个实例时会调用 __mod__
:
>>> a = MyNumber(10)
>>> a % 2
__mod__ called on 'MyNumber(10)'
0
请注意,即使没有明确实现__imod__
,它也适用于%=
:
>>> a = MyNumber(10)
>>> a %= 2
__mod__ called on 'MyNumber(10)'
>>> a
0
然而,你也可以显式地实现__imod__
来覆盖增强赋值:
class MyNumber(object):
def __init__(self, value):
self.value = value
def __mod__(self, other):
print("__mod__ called on '{!r}'".format(self))
return self.value % other
def __imod__(self, other):
print("__imod__ called on '{!r}'".format(self))
self.value %= other
return self
def __repr__(self):
return "{self.__class__.__name__}({self.value!r})".format(self=self)
现在,
%=
被显式地重写为原地操作:
>>> a = MyNumber(10)
>>> a %= 2
__imod__ called on 'MyNumber(10)'
>>> a
MyNumber(0)
%
的原样。format()
功能强大,但对于基本用途,%
更加方便。 - TM.