This is a golf cheatsheet that lists techniques to reduce the number of chars in Python code.
n&~-n # zero for powers of 2, non-zero for others
# or
n&~-n<1
# or
n&-n-n # zero for powers of 2, non-zero for others
# or
n&-n==n
instead of
(n & (n-1) == 0) and n != 0
# or
import math;math.log(n, 2).is_integer()
# or
bin(num).count("1") == 1
q**n%n # zero for powers of q, non-zero for others
# or
q**n%n<1
instead of
import math;math.log(n, q).is_integer()
map(chr,range(65,91))
# ABCDEFGHIJKLMNOPQRSTUVWXYZ
map(chr,range(97,123))
# abcdefghijklmnopqrstuvwxyz
instead of:
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
[chr(i+97)for i in range(26)]
for i in 0,1,2:
print("fbboaaorz"[i::3])
# foo
# bar
# baz
instead of:
for i in 0,1,2:
if i == 0:
print("foo")
elif i == 1:
print("bar")
else:
print("baz")
It works with strings that are the same size (+- 1 char).
For True
and False
, see:
print("FTarlusee"[condition::2])
# False (if condition is False)
# True (if condition is True)
p<=s<p+"" # last utf-8 char
# or
p<=s<p+"~" # last printable ascii char
instead of:
s.startswith(p)
NB: See the utf-8 list to see the last char.
"ATTCGAAGCCTTC".translate({65:84,84:"U"}) # "TUUCGTTGCCUUC"
"ATTCGAAGCCTTC".translate({65:84,84:"55"}) # "T5555CGTTGCC5555C"
"ATTCGAAGCCTTC".translate({65:84,84:65}) # "TAACGTTGCCAAC"
instead of:
"ATTCGAAGCCTTC".replace("T","U").replace("A","T") # "TUUCGTTGCCUUC"
"ATTCGAAGCCTTC".replace("T","55").replace("A","T") # "T5555CGTTGCC5555C"
"ATTCGAAGCCTTC".replace("A","~").replace("T","A").replace("~","T") # "TAACGTTGCCAAC"
Explanation: replace
is costly because you have to use it once for every replacement you want to make. Moreover, when you need to exchange 2 chars ("A" -> "T" and "T" to "A"), you are forced to make one more .replace
call for the exchange to give the correct result.
L=[1,3,4,8]
*_,a=L
# a = 8
instead of:
L=[1,3,4,8]
a=L[-1]
# a = 8
L=[1,2,3,4,5]
i=3
a=L[~i] # 2
instead of
L=[1,2,3,4,5]
i=3
a=L[-i-1] # 2
Explanation: ~
is the bitwise inversion, leading to ~i
being equal to -i-1
.
L=[1,2,3,4,5]
a=6
L+=a,
instead of
L=[1,2,3,4,5]
a=6
L+=[a]
# or
L.append(a)
L=[1,2,3]
M=[4,5,6]
L+=M
instead of
L=[1,2,3]
M=[4,5,6]
L.extend(M)
for i in 0,1,2:
instead of
for i in range(3):
CAVEAT: it works only for loops of up until range(3)
included.
exec("do_something;"*n)
instead of
for _ in range(n):do_something
i=n;exec("do_something;i-=1;"*n)
instead of
for i in range(n,0,-1):do_something
for i in range(m*n):
print(i//n, i%n)
instead of
for i in range(m):
for j in range(n):
print(i, j)
for i in range(m*n*o):
print(i//n//o, i%(n*o)//o, i%o)
instead of
for i in range(m):
for j in range(n):
for k in range(o):
print(i, j, k)
s=[x,y][b]
instead of:
s = y if b else x
CAVEAT:
b
must be True
, False
, 0
or 1
. Being "truthy"/"untruthy" is not sufficient.
For x
and y
numbers and b
a boolean:
do | instead of |
---|---|
y*b |
[0,y][b] |
y**b |
[1,y][b] |
b or x |
[x,1][b] |
x+b |
[x,x+1][b] |
x-b |
[x,x-1][b] |
x+z*b |
[x,y][b] * |
* only works if z=y-x
already exists.
For x
and y
integers and b
a boolean:
do | instead of |
---|---|
1|-b |
[1,-1][b] |
x^-b |
[x,~x][b] |
-x-b |
[-x,~x][b] |
L=[1,3,4,8]
M=[]
L[:1]==[1] # True
L[:1]==[2] # False
M[:1]==[1] # False
instead of
L=[1,3,4,8]
M=[]
next(iter(L),None)==1 # True
next(iter(L),None)==2 # False
next(iter(M),None)==1 # False
Slicing the list is always possible, therefore [][:1]
does not fail and just returns []
. [][0]
would fail. The interesting part is that it works when the list is empty and when the list contains at least an element with the same expression.
a=b=c=d=0
e,f=1,2
instead of:
a = 0
b = 0
c = 0
d = 0
e = 1
f = 2
CAVEAT: a=b=c=d=[]
does not work with lists. Indeed:
a=b=c=d=[]
a.append(1)
print(a, b, c, d) # [1] [1] [1] [1]