What does the percentage sign mean?
It's an operator in Python that can mean several things depending on the context. A lot of what follows was already mentioned (or hinted at) in the other answers but I thought it could be helpful to provide a more extensive summary.
%
for Numbers: Modulo operation / Remainder / RestThe percentage sign is an operator in Python. It's described as:
x % y remainder of x / y
So it gives you the remainder/rest that remains if you "floor divide" x by y. Generally (at least in Python) given a number x
and a divisor y
:
x == y * (x // y) + (x % y)
For example if you divide 5 by 2:
>>> 5 // 2
2
>>> 5 % 2
1
>>> 2 * (5 // 2) + (5 % 2)
5
In general you use the modulo operation to test if a number divides evenly by another number, that's because multiples of a number modulo that number returns 0:
>>> 15 % 5 # 15 is 3 * 5
0
>>> 81 % 9 # 81 is 9 * 9
0
That's how it's used in your example, it cannot be a prime if it's a multiple of another number (except for itself and one), that's what this does:
if n % x == 0:
break
If you feel that n % x == 0
isn't very descriptive you could put it in another function with a more descriptive name:
def is_multiple(number, divisor):
return number % divisor == 0
...
if is_multiple(n, x):
break
Instead of is_multiple
it could also be named evenly_divides
or something similar. That's what is tested here.
Similar to that it's often used to determine if a number is "odd" or "even":
def is_odd(number):
return number % 2 == 1
def is_even(number):
return number % 2 == 0
And in some cases it's also used for array/list indexing when wrap-around (cycling) behavior is wanted, then you just modulo the "index" by the "length of the array" to achieve that:
>>> 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
Note that there is also a function for this operator in the standard library operator.mod
(and the alias operator.__mod__
):
>>> import operator
>>> operator.mod(5, 2) # equivalent to 5 % 2
1
But there is also the augmented assignment %=
which assigns the result back to the variable:
>>> a = 5
>>> a %= 2 # identical to: a = a % 2
>>> a
1
%
for strings: printf
-style String FormattingFor strings the meaning is completely different, there it's one way (in my opinion the most limited and ugly) for doing string formatting:
>>> "%s is %s." % ("this", "good")
'this is good'
Here the %
in the string represents a placeholder followed by a formatting specification. In this case I used %s
which means that it expects a string. Then the string is followed by a %
which indicates that the string on the left hand side will be formatted by the right hand side. In this case the first %s
is replaced by the first argument this
and the second %s
is replaced by the second argument (good
).
Note that there are much better (probably opinion-based) ways to format strings:
>>> "{} is {}.".format("this", "good")
'this is good.'
%
in Jupyter/IPython: magic commandsTo quote the docs:
To Jupyter users: Magics are specific to and provided by the IPython kernel. Whether magics are available on a kernel is a decision that is made by the kernel developer on a per-kernel basis. To work properly, Magics must use a syntax element which is not valid in the underlying language. For example, the IPython kernel uses the
%
syntax element for magics as%
is not a valid unary operator in Python. While, the syntax element has meaning in other languages.
This is regularly used in Jupyter notebooks and similar:
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)
%
operator on arrays (in the NumPy / Pandas ecosystem)The %
operator is still the modulo operator when applied to these arrays, but it returns an array containing the remainder of each element in the array:
>>> 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])
%
operator for your own classesOf course you can customize how your own classes work when the %
operator is applied to them. Generally you should only use it to implement modulo operations! But that's a guideline, not a hard rule.
Just to provide a simple example that shows how it works:
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)
This example isn't really useful, it just prints and then delegates the operator to the stored value, but it shows that __mod__
is called when %
is applied to an instance:
>>> a = MyNumber(10)
>>> a % 2
__mod__ called on 'MyNumber(10)'
0
Note that it also works for %=
without explicitly needing to implement __imod__
:
>>> a = MyNumber(10)
>>> a %= 2
__mod__ called on 'MyNumber(10)'
>>> a
0
However you could also implement __imod__
explicitly to overwrite the augmented assignment:
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)
Now %=
is explicitly overwritten to work in-place:
>>> a = MyNumber(10)
>>> a %= 2
__imod__ called on 'MyNumber(10)'
>>> a
MyNumber(0)