What general tips do you have for golfing in Python? I'm looking for ideas which can be applied to code-golf problems and which are also at least somewhat specific to Python (e.g. "remove comments" is not an answer).
Please post one tip per answer.
Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It only takes a minute to sign up.
Sign up to join this communityWhat general tips do you have for golfing in Python? I'm looking for ideas which can be applied to code-golf problems and which are also at least somewhat specific to Python (e.g. "remove comments" is not an answer).
Please post one tip per answer.
If you want to make a 3*4 grid of zeroes, the natural expression M=[[0]*4]*3
gives an unpleasant surprise if you modify an entry:
>>> M=[[0]*4]*3
>>> M
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> M[0][0]=1
>>> M
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
Since each row is a copy of the same list by reference, modifying one row modifies all of them, which is usually not the behavior you want.
In Python 2, avoid this with the hack (19 chars):
M=eval(`[[0]*4]*3`)
Doing eval(`_`)
converts to the string representation, then re-evaluates it, converting the object to the code of how it's displayed. In effect, it's doing copy.deepcopy
.
If you're OK getting a tuple of lists, you can do (18 chars):
M=eval('[0]*4,'*3)
to get ([0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0])
. This lets you do M[0][0]=1
but not M[0]=[1,2,3,4]
. It also works in Python 3.
str
for backticks as M=eval(str([[0]*3]*4))
. Or, M=[3*[0]for _ in[0]*4]
which is the same length. Maybe there's better.
\$\endgroup\$
Say you have two 2-element tuples which represent points in the Euclidean plane, e.g. x=(0, 0)
and y=(3, 4)
, and you want to find the distance between them. The naïve way to do this is
d=((x[0]-y[0])**2+(x[1]-y[1])**2)**.5
Using complex numbers, this becomes:
c=complex;d=abs(c(*x)-c(*y))
If you have access to each coordinate individually, say a=0, b=0, c=3, d=4
, then
abs(a-c+(b-d)*1j)
can be used instead.
d=abs(x[0]-y[0]+(x[1]-y[1])*1j)
. Can this be made shorter than what you have? I'm just wondering if 1j
could be useful in converting a tuple to a complex number.
\$\endgroup\$
*1j
is usually shorter.
\$\endgroup\$
x=(0,0);y=(3,4);c=complex;d=abs(c(*x)-c(*y))
, different assignments: a,b=0,0;c,d=3,4;d=((a-c)**2+(b-d)**2)**.5
. Yes, writing x=0,0;y=3,4
does indeed make the complex option shorter, but using different assignments makes it even shorter: x=0,0;y=3,4;c=complex;d=abs(c(*x)-c(*y)
. Finally, consider @mbomb007's approach with different assignments: a,b=0,0;x,y=3,4;d=abs(a-x+(b-y)*1j)
: with or without the assignment, it's shorter than all of the alternatives I've found.
\$\endgroup\$
1j
part, so I've added that in. The general point was basically that ((a-b)**2+(c-d)**2)**.5
is rarely ever needed.
\$\endgroup\$
In Python 3, a bytes object is written as a string literal preceded by a b
, like b"golf"
. It acts much like a tuple of the ord
values of its characters.
>>> l=b"golf"
>>> list(l)
[103, 111, 108, 102]
>>> l[2]
108
>>> 108 in l
True
>>> max(l)
111
>>> for x in l:print(x)
103
111
108
102
Python 2 also has bytes objects but they act as strings, so this only works in Python 3.
This gives a shorter way to express an explicit list of numbers between 0 to 255. Use this to hardcode data. It uses one byte per number, plus three bytes overhead for b""
. For example, the list of the first 9 primes [2,3,5,7,11,13,17,19,23]
compresses to 14 bytes rather than 24. (An extra byte is used for a workaround explained below for character 13.)
In many cases, your bytes object will contain non-printable characters such as b"\x01x02\x03"
for [1, 2, 3]
. These are written with hex escape characters, but you may use them a single characters in your code (unless the challenge says otherwise) even though SE will not display them. But, characters like the carriage return b"\x0D"
will break your code, so you need to use the two-char escape sequence "\r"
.
Use powers of the imaginary unit to calculate sines and cosines.
For example, given an angle d
in degrees, you can calculate the sine and cosine as follows:
p=1j**(d/90.)
s=p.real
c=p.imag
This can also be used for related functions such as the side length of a unit n
-gon:
l=abs(1-1j**(4./n))
list.insert
Instead of list.insert
, appending to a slice is shorter:
L.insert(i,x)
L[:i]+=x,
For example:
>>> L = [1, 2, 3, 4]
>>> L[:-2]+=5,
>>> L
[1, 2, 5, 3, 4]
>>> L[:0]+=6,
>>> L
[6, 1, 2, 5, 3, 4]
Python 3.6 introduces a new string literal that is vastly more byte-efficient at variable interpolation than using %
or .format()
in non-trivial cases. For example, you can write:
l='Python';b=40;print(f'{l}, {b} bytes')
instead of
l='Python';b=43;print('%s, %d bytes'%(l,b))
' '+str(n)
(10 bytes) and f' {n}'
(7 bytes).
\$\endgroup\$
' %d'%n
I think, where this example doesn't save any bytes. You do need more args for this to help
\$\endgroup\$
Your submission can be a method of an object
range(123,790,111).count
This defines an anonymous function much shorter than
lambda n:range(123,790,111).count(n)
The object method is a valid function that meets our definition. For example, it could be bound and called
f=range(123,790,111).count
print f(99)
Because it avoids a costly lambda
, this saves characters even rewriting from
lambda n:n in range(123,790,111)
Consider using an object method when your solution is a simple two-input function of your input and some concrete object. You can use dir()
to get a list of methods of an object. Note in particular methods like .__add__
that are called for an operator like +
. Most infix operators correspond to a method.
Other examples:
"prefix{}suffix".format
lambda s:"prefix"+s+"suffix"
2 .__rpow__ #Space for lexer
lambda n:n*n
[0,0].__le__
lambda l:[0,0]<=l
You can even sometimes save bytes with two input by currying. For example, compare
lambda l:expression_in_l.count
lambda n,l:n in expression_in_l
where expression_in_l
produces a list with no duplicates and has favorable spacing and precedence.
["North","East","South","West"].pop
a function submission must work multiple times, no? using .__getitem__
would do the trick, but the length would be the same
\$\endgroup\$
Jul 12, 2017 at 13:51
If you need to loop a number of times but you don't care about the iteration variable, you can co-opt the loop to assign a variable.
r=reused;for _ in"_"*n:stuff
r=reused;exec("r;"*n) # [note 1]
r=reused;exec"r;"*n # [note 1]; Python 2 only
for r in[reused]*n:r
lambda args:((r:=reused)for _ in"_"*n) # generally needs parentheses
lambda args,r=reused:(r for _ in"_"*n) # only works with constants
lambda args:(r for r in[reused]*n)
This is generally a more versatile approach for assignment than the :=
operator or using default arguments of functions, because it supports assigning to attributes .x
, subscripts [x]
, and unpacking with *
or ,
.
(stuff+(a[0]:=value)for _ in"_"*n) # syntax error
(stuff+a[0]for a[0]in[value]*n) # works, and shorter!
(stuff+a+b for*a,b in[value]*n) # works!
The only pitfall is that scope inside comprehensions is sometimes quite confusing, because the body of the comprehension is compiled as a separate implicit function.
Taken from @xnor's use of it here.
[note 1]: and longer if backslashes/quotes/newlines/... need to be escaped inside the string
This is a bot account operated by pxeger. I'm posting this to get enough reputation to use chat.
Abuse the fact that in case of an expression yielding True
boolean operators return the first value that decides about the outcome of the expression instead of a boolean:
>>> False or 5
5
is pretty straightforward. For a more complex example:
>>> i = i or j and "a" or ""
i's value remains unchanged if it already had a value set, becomes "a" if j has a value or in any other case becomes an empty string (which can usually be omitted, as i most likely already was an empty string).
Lets play with some list tricks
a=[5,5,5,5,5,5,5]
can be written as:
a=[5]*7
It can be expanded in this way. Lets, say we need to do something like
for i in range(0,100,3):a[i]=5
Now using the slicing trick we can simply do:
a[0:100:3]=[5]*(1+99//3)
a[:100:3]=[5]*34
\$\endgroup\$
==
short circuitingIf you have:
print
);Then you might be able to use ==
over or
to save a byte.
Here's printing all numbers n
under 100 that have f(n)
less than 2:
# Naive
for n in range(100):f(n)<2and print(n)
# Invert condition
for n in range(100):f(n)>1or print(n)
# Use ==
for n in range(100):f(n)<2==print(n)
Usually you use map
to transform a collection
>> map(ord,"abc")
[97, 98, 99]
But you can also use it to repeatedly act on object by a built-in method that modifies it.
>> L=[1,2,3,4,5]
>> map(L.remove,[4,2])
[None, None]
>> L
[1, 3, 5]
Be aware that the calls are done in order, so earlier ones might mess up later ones.
>> L=[1,2,3,4,5]
>> map(L.pop,[0,1])
[1, 3]
>> L
[2, 4, 5]
Here, we intended to extract the first two elements of L
, but after extracting the first, the next second element is the original third one. We could sort the indices in descending order to avoid this.
An advantage of the evaluation-as-action is that it can be done inside of a lambda
. Be careful in Python 3 though, where map
objects are not evaluated immediately. You might need an expression like [*map(...)]
or *map(...),
to force evaluation.
A detailed guide
I had worked with short-circuiting and/or
's for a while without really grasping how they work, just using b and x or y
just as a template. I hope this detailed explanation will help you understand them and use them more flexibly.
Recursive named lambda
functions are often shorter than programs that loop. For evaluation to terminate, there must be control flow to prevent a recursive call for the base case. Python has a ternary condition operator that fits the bill.
f=lambda x:base_value if is_base_case else recursive_value
Note that list selection won't work because Python evaluates both options. Also, regular if _:
isn't an option because we're in a lambda
.
Python has another option to short-circuit, the logical operator keywords and
and or
. The idea is that
True or b == True
False and b == False
so Python can skip evaluate b
in these cases because the result is known. Think of the evaluation of a or b
as "Evaluate a
. If it's True, output a
. Otherwise, evaluate and output b
." So, it's equivalent to write
a or b
a if a else b
It's the same for a or b
except we stop if a
is False.
a and b
a if (not a) else b
You might wonder why we didn't just write False if (not a) else b
. The reason is that this works for non-Boolean a
. Such values are first converted to a Boolean. The number 0
, None
, and the empty list/tuple/set become False
, and are so called "Falsey". The rest are "Truthy".
So, a or b
and a and b
always manages to produce either a
or b
, while forming a correct Boolean equation.
(0 or 0) == 0
(0 or 3) == 3
(2 or 0) == 2
(2 or 3) == 2
(0 and 0) == 0
(0 and 3) == 0
(2 and 0) == 0
(2 and 3) == 3
('' or 3) == 3
([] and [1]) == []
([0] or [1]) == [0]
Now that we understand Boolean short-circuiting, let's use it in recursive functions.
f=lambda x:base_value if is_base_case else recursive_value
The simplest and most common situation is when the base is something like f("") = ""
, sending a Falsey value to itself. Here, it suffices to do x and
with the argument.
For example, this function doubles each character in a string, f("abc") == "aabbcc"
.
f=lambda s:s and s[0]*2+f(s[1:])
Or, this recursively sums the cubes of numbers 1 through n
, so f(3)==36
.
f=lambda n:n and n**3+f(n-1)
Another common situation is for your function to take non-negative numbers to lists, with a base case of 0
giving the empty list. We need to transform the number to a list while preserving Truthiness. One way is n*[5]
, where the list can be anything nonempty. This seems silly, but it works.
So, the following returns the list [1..n]
.
f=lambda n:n*[5]and f(n-1)+[n]
Note that negative n
will also give the empty list, which works here, but not always. For strings, it's similar with any non-empty string. If you've previously defined such a value, you can save chars by using it.
More generally, when your base value is an empty list, you can use the arithmetic values True == 1
and False == 0
to do:
[5]*(is_not_base_case)and ...
TODO: Truthy base value
TODO: and/or
and
and or
work might be: x or y=if x:return x;return y
x and y:if x:return y;return x
\$\endgroup\$
Cut out newlines wherever you can.
At the top-level, it doesn't matter.
a=1
b=9
Takes the same amount of characters as:
a=1;b=9
In the first case you have a newline instead of a ;
. But in function bodies, you save however deep the nesting level is:
def f():
a=1;b=9
Actually in this case, you can have them all on one line:
def f():a=1;b=9
If you have an if
or a for
, you can likewise have everything on one line:
if h:a=1;b=9
for g in(1,2):a=1;b=9
But if you have a nesting of control structures (e.g. if
in a for
, or if
in a def
), then you need the newline:
if h:for g in(1,2):a=1;b=9 #ERROR
if h:
for g in(1,2):a=1;b=9 # SAUL GOODMAN
a,b=1,9
does not save any bytes
\$\endgroup\$
Jul 12, 2017 at 14:40
If you are doing something small in a for loop whose only purpose is to invoke a side effect (pop
, print
in Python 3, append
), it might be possible to translate it to a list-comprehension. For example, from Keith Randall's answer here, in the middle of a function, hence the indent:
if d>list('XXXXXXXXX'):
for z in D:d.pop()
c=['X']
Can be converted to:
if d>list('XXXXXXXXX'):
[d.pop()for z in D]
c=['X']
Which then allows this golf:
if d>list('XXXXXXXXX'):[d.pop()for z in D];c=['X']
An if
within a for
works just as well:
for i in range(10):
if is_prime(i):d.pop()
can be written as
[d.pop()for i in range(10)if is_prime(i)]
[d.pop()for i in range(10)if is_prime(i)]
is shorter as for i in range(10):notprime(i)or d.pop()
, so it's shorter with a False condition instead of a True one if the condition can be squished into the or
. Obviously, if you need the popped values the comprehension is shorter, but this post is about side effects.
\$\endgroup\$
Jul 4, 2021 at 22:11
Say you want to apply f
composed k
times to the number 1
, then print the result.
This can be done via an exec
loop,
n=1
exec("n=f(n);"*k)
print(n)
which runs code like n=1;n=f(n);n=f(n);n=f(n);n=f(n);n=f(n);print(n)
.
But, it's one character shorter to use eval
print(eval("f("*k+'1'+")"*k))
which evaluates code like f(f(f(f(f(1)))))
and prints the result.
This does not save chars in Python 2 though, where exec
doesn't need parens but eval
still does. It does still help though when f(n)
is an expression in which n
appears only once as the first or last character, letting you use only one string multiplication.
One trick I have encountered concerns returning or printing Yes/No answers:
print 'YNeos'[x::2]
x is the condition and can take value 0 or 1.
I found this rather brilliant.
A condition like
s = ''
if c:
s = 'a'
can be written as
s = c*'a'
and there is possibly a need for parenthesis for condition.
This can also be combined with other conditions as (multiple ifs)
s = c1*'a' + c2*'b'
or (multiple elifs)
s = c1*'a' or c2*'b'
For example FizzBuzz problem's solution will be
for i in range(n):
print((i%3<1)*"Fizz"+(i%5<1)*"Buzz" or i)
Check whether a positive integer n
is a perfect power of 2, that is one of 1, 2, 4, 8, 16, ...
, with any of these expression:
n&~-n<1
n&-n==n
2**n%n<1
This is shorter than converting to binary or using a loop. The last one also works for checking, say, powers of 3.
List comprehension.
shortList = []
for x in range(10):
shortList += [x * 2]
can be shortened into
shortList = [x*2 for x in range(10)]
Or even shorter:
shortList = range(0,20,2)
To concatenate strings or characters, it can be shorter to repeatedly append to the empty string than to join
.
23 chars
s=""
for x in l:s+=f(x)
25 chars
s="".join(f(x)for x in l)
Assume here that f(x)
stands for some expression in x
, so you can't just map
.
But, the join
may be shorter if the result doesn't need saving to a variable or if the for
takes newlines or indentation.
For a dictionary with string keys which also happen to be valid Python variable names, you can get a saving if there's at least three items by using dict
's keyword arguments:
{'a':1,'e':4,'i':9}
dict(a=1,e=4,i=9)
The more string keys you have, the more quote characters you'll save, so this is particularly beneficial for large dictionaries (e.g. for a kolmogorov challenge).
When squaring single letter variables, it is shorter to times it by itself
>>> x=30
>>> x*x
900
Is one byte shorter than
>>> x=30
>>> x**2
900
When mapping a function on a list in Python 3, instead of doing [f(x)for x in l]
or list(map(f,l))
, do [*map(f,l)]
.
It works for all other functions returning generators too (like filter
).
The best solution is still switching to Python 2 though
*
) to pass a bunch of single character strings into a functionFor example:
a.replace("a","b")
a.replace(*"ab") -2 bytes
some_function("a","b","c")
some_function(*"abc") -5 bytes
In fact, if you have n
single-character strings, you will save 3(n - 1) - 1
or 3n - 4
bytes by doing this (because each time, you remove the ","
for each one and add a constant *
).
If you need to keep multiple conditions inside comprehension, you can replace and with if to save a byte each time.
Works in Python 2 and 3.
[a for a in 'abc'if cond1()and cond2()or cond3()and cond4()and cond5()]
[a for a in 'abc'if cond1()if cond2()or cond3()if cond4()if cond5()]
Usually you do it this way (6 bytes):
n%2==0
But you can reduce it to 5 bytes:
n%2<1
And even 4 bytes:
~n&1
Bonus tip: when you use if
you can ignore spacebetween if
and ~n&1
this way:
if~n&1:
Here's a trick to shorten long function names. The basic idea is to fetch the name by using dir()
. This would return the name as a string, so we must follow it with an eval
to make it usable. Below is an exaggerated example from the itertools
module:
from itertools import*
combinations_with_replacement('ABC',2)
eval(dir()[7])('ABC',2)
In the minimal case, if the function name is 15 bytes or longer, there's a chance that it can still save bytes. This is assuming, that the name can be accessed by dir
with a single-digit index:
???????????????()
eval(dir()[?])()
if isdigit(a) and isdigit(b) and isdigit(c)
if all(map(isdigit,[a,b,c]))
filter(function, iterable) returns a list of all the elements of
iterable` for which function
is a True
-y value and a non-empty list is True
-y, so this can be shortened further to if filter(isdigit,[a,b,c])
\$\endgroup\$
Apr 16, 2014 at 8:33
if filter(isdigit,[a,b,c])
is not equivalent to the code in the answer; but it would be if @moose used isdigit(a) or...
and if any(...
.
\$\endgroup\$
Apr 21, 2015 at 13:36
Sometimes you need convert boolean expression into integer (0/1)
Simple use this Boolean (in examples below c > 0
) in ariphmetic
a=b+(c>0)
a+=c>0
a=sum(c>0 for c in b) # space in "0 for" may be omitted
And sometimes you need simple convert boolean to int (for example for printing or convert to binary string). In programm you may use some variants
1 if c>0 else 0
c>0and 1or 0
(0,1)[c>0]
int(c>0)
but shortest way is
+(c>0)
+c
being shorter. E.g. let c
be a boolean, then 4+c
is 5 if c
is True else 4.
\$\endgroup\$
:=
operator in 3.8 \$\endgroup\$