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.
Use a=b=c=0
instead of a,b,c=0,0,0
. (Note that this uses the same instance for each variable, so don't do this with objects like lists if you intend to mutate them independently)
Use a,b,c='123'
instead of a,b,c='1','2','3'
.
Conditionals can be lengthy. In some cases, you can replace a simple conditional with (a,b)[condition]
. If condition
is true, then b
is returned.
Compare
if a<b:return a
else:return b
To this
return(b,a)[a<b]
a if a<b else b
and a<b and a or b
\$\endgroup\$
(lambda(): b, lambda(): a)[a < b]()
make your own short-circuit with lambdas
\$\endgroup\$
Commented
May 7, 2011 at 23:33
P and A or B
for any A that gives bool(A)=False
. But (P and [A] or [B])[0]
will do the job. See diveintopython.net/power_of_introspection/and_or.html for reference.
\$\endgroup\$
A great thing I did once is:
if 3 > a > 1 < b < 5: foo()
instead of:
if a > 1 and b > 1 and 3 > a and 5 > b: foo()
Python’s comparison operators rock.
Using that everything is comparable in Python 2, you can also avoid the and
operator this way. For example, if a
, b
, c
and d
are integers,
if a<b and c>d:foo()
can be shortened by one character to:
if a<b<[]>c>d:foo()
This uses that every list is larger than any integer.
If c
and d
are lists, this gets even better:
if a<b<c>d:foo()
3>a>1<b<5
\$\endgroup\$
Commented
Jan 28, 2011 at 0:35
[$a => $b]->[$b <= $a]
:)
\$\endgroup\$
Commented
Feb 3, 2011 at 21:42
*
. An or
would be +
\$\endgroup\$
Commented
May 22, 2014 at 10:53
foo()if 3>a>1<b<5
doesn't work for me.
\$\endgroup\$
Commented
Dec 24, 2019 at 8:52
If you're using a built-in function repeatedly, it might be more space-efficient to give it a new name, if using different arguments:
r=range
for x in r(10):
for y in r(100):print x,y
Use string substitution and exec
to deal with long keywords like lambda
that are repeated often in your code.
a=lambda b:lambda c:lambda d:lambda e:lambda f:0 # 48 bytes (plain)
exec"a=`b:`c:`d:`e:`f:0".replace('`','lambda ') # 47 bytes (replace)
exec"a=%sb:%sc:%sd:%se:%sf:0"%(('lambda ',)*5) # 46 bytes (%)
The target string is very often 'lambda '
, which is 7 bytes long. Suppose your code snippet contains n
occurences of 'lambda '
, and is s
bytes long. Then:
plain
option is s
bytes long.replace
option is s - 6n + 29
bytes long.%
option is s - 5n + 22 + len(str(n))
bytes long.From a plot of bytes saved over plain
for these three options, we can see that:
exec"..."%(('lambda ',)*5)
saves 2 bytes, and is your best option.exec"...".replace('`','lambda ')
is your best option.For other cases, you can index the table below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 (occurences)
+---------------------------------------------------------
3 | - - - - - - - - - - - - - - r r r r r
4 | - - - - - - - - - r r r r r r r r r r
5 | - - - - - - - r r r r r r r r r r r r
6 | - - - - - r r r r r r r r r r r r r r
7 | - - - - % r r r r r r r r r r r r r r
8 | - - - % % r r r r r r r r r r r r r r
9 | - - - % % r r r r r r r r r r r r r r
10 | - - % % % r r r r r r r r r r r r r r
11 | - - % % % r r r r r r r r r r r r r r
12 | - - % % % r r r r r r r r r r r r r r r = replace
13 | - - % % % r r r r r r r r r r r r r r % = string %
14 | - % % % % r r r r r r r r r r r r r r - = do nothing
15 | - % % % % r r r r r r r r r r r r r r
(length)
For example, if the string lambda x,y:
(length 11) occurs 3 times in your code, you're better off writing exec"..."%(('lambda x,y:',)*3)
.
replace
is huge.
\$\endgroup\$
import
- you can do for s in ('module1','module2','etc'):exec"from %s import*"%s
\$\endgroup\$
.replace("R",'.replace("')
to save bytes, many other replacements become cheaper. (It also makes your code entirely unreadable.)
\$\endgroup\$
Sometimes your Python code requires you to have 2 levels of indentation. The obvious thing to do is use one and two spaces for each indentation level.
However, Python 2 considers the tab and space characters to be different indenting levels.
This means the first indentation level can be one space and the second can be one tab character.
For example:
if 1:
if 1:
pass
TabError: inconsistent use of tabs and spaces in indentation.
\$\endgroup\$
Commented
Oct 3, 2016 at 5:16
"editor.renderWhitespace": "all"
and 2) stop the editor from replacing it with whitespace - "editor.insertSpaces": false, "editor.detectIndentation": false
. (VSCode version 1.46.1). If you want these to work only for the current golfing project, you can add a local settings.json file to the current workspace.
\$\endgroup\$
Commented
Jun 22, 2020 at 10:11
Say you want to hardcode a Boolean lookup table, like which of the first twelve English numbers contain an n
.
0: False
1: True
2: False
3: False
4: False
5: False
6: False
7: True
8: False
9: True
10:True
11:True
12:False
Then, you can implement this lookup table concisely as:
3714>>i&1
with the resulting 0
or 1
being equal to False
to True
.
The idea is that the magic number stores the table as a bitstring bin(3714)
= 0b111010000010
, with the n
-th digit (from the end) corresponding the the n
th table entry. We access the n
th entry by bitshifting the number n
spaces to the right and taking the last digit by &1
.
This storage method is very efficient. Compare to the alternatives
n in[1,7,9,10,11]
'0111010000010'[n]>'0'
You can have your lookup table store multibit entries that can be extracted like
340954054>>4*n&15
to extract the relevant four-bit block.
n in [...]
might be smaller for sparse sets.
\$\endgroup\$
Commented
Jun 9, 2020 at 0:53
Use extended slicing to select one string from many
>>> for x in 0,1,2:print"fbboaaorz"[x::3]
...
foo
bar
baz
vs
>>> for x in 0,1,2:print["foo","bar","baz"][x]
...
foo
bar
baz
In this Boolean two-string case, one can also write
b*"string"or"other_string"
for
["other_string","string"][b]
Unlike interleaving, this works for strings of any length, but can have operator precedence issues if b
is instead an expression.
for x in ("foo","bar","baz"): print x
\$\endgroup\$
Commented
Jun 2, 2017 at 7:21
x
are rendered. The golfed part is the "fbboaaorz"[x::3]
vs ["foo","bar","baz"][x]
How the x
value is derived would be another part of your golf solution.
\$\endgroup\$
Say you're iterating over the cells of an m*n
grid. Instead of two nested for
loops, one for the rows and one for the columns, it's usually shorter to write a single loop to iterate over the m*n
cells of the grid. You can extract the row and column of the cell inside the loop.
Original code:
for i in range(m):
for j in range(n):
do_stuff(i,j)
Golfed code:
for k in range(m*n):
do_stuff(k/n,k%n)
In effect, you're iterating over the Cartesian product of the two ranges, encoding the pair (i,j)
as x=i*n+j
. You've save a costly range
call and a level of indentation inside the loop. The order of iteration is unchanged.
Use //
instead of /
in Python 3. If you refer to i
and j
many times, it may be shorter to assign their values i=k/n
, j=k%n
inside the loop.
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
\$\endgroup\$
itertools.product
can be much more concise than nested loops, especially when generating cartesian products. a1, a2, b1, b2
are examples of the cartesian product of 'ab'
and '12'
\$\endgroup\$
Commented
Mar 16, 2018 at 3:24
Use `n`
to convert an integer to a string instead of using str(n)
:
>>> n=123
>>> `n`
'123'
Note: Only works in Python 2.
For integer n
, you can write
n+1
as -~n
n-1
as ~-n
because the bit flip ~x
equals -1-x
. This uses the same number of characters, but can indirectly cut spaces or parens for operator precedence.
Compare:
while n-1: #Same as while n!=1
while~-n:
c/(n-1)
c/~-n
or f(n)+1
or-~f(n)
(n-1)/10+(n-1)%10
~-n/10+~-n%10
The operators ~
and unary -
are higher precedence than *
, /
, %
, unlike binary +
.
-~-x
saves one byte vs. (1-x)
.
\$\endgroup\$
a+b+1
can be more concisely written as a-~b
.
\$\endgroup\$
Commented
Jan 22, 2017 at 11:51
Unless the following token starts with e
or E
. You can remove the space following a number.
For instance:
if i==4 and j==4:
pass
Becomes:
if i==4and j==4:
pass
Using this in complicated one line statements can save quite a few characters.
EDIT: as @marcog pointed out, 4or a
will work, but not a or4
as this gets confused with a variable name.
if(i,j)==(4,4):
is even shorter and in this special case if i==j==4:
\$\endgroup\$
4or a
works, but not a or4
\$\endgroup\$
0or
also doesn't work (0o
is a prefix for octal numbers).
\$\endgroup\$
0 or x
is always gonna return x
. Might as well cut out the 0 or
.
\$\endgroup\$
Commented
Apr 6, 2014 at 12:57
0or
is fine as part of a longer number though. 10 or x
is equivalent to 10or x
.
\$\endgroup\$
Commented
Apr 20, 2014 at 22:39
A nice way to convert an iterable to list on Python 3:
imagine you have some iterable, like
i = (1,2,3,4)
i = range(4)
i = (x**2 for x in range(5))
But you need a list:
x=list(i) #the default way
*x,=i #using starred assignment -> 4 char fewer
It's very useful to make a list of chars out of a string
s=['a','b','c','d','e']
s=list('abcde')
*s,='abcde'
*s,='abcde'
and then s
crashes my interactive python3 with a segfault :(
\$\endgroup\$
[*'abcde']
.
\$\endgroup\$
Commented
Jun 5, 2017 at 0:58
The best way to explain this is via an example:
>>> a,*b,c=range(5)
>>> a
0
>>> b
[1, 2, 3]
>>> c
4
We've already seen a use for this — turning an iterable into a list in Python 3:
a=list(range(10))
*a,=range(10)
Here are a few more uses.
a=L[-1]
*_,a=L
In some situations, this can also be used for getting the first element to save on parens:
a=(L+[1])[0]
a,*_=L+[1]
a=1;b=2;c=[]
a,b,*c=1,2
_,*L=L
*L,_=L
These are shorter than the alternatives L=L[1:]
and L.pop()
. The result can also be saved to a different list.
Tips courtesy of @grc
a=1;L=[]
so many times. It's amazing that you can save chars on something so straightforward as this.
\$\endgroup\$
a,*L=1,
), but it still saves one char :)
\$\endgroup\$
a,*_,b=L
\$\endgroup\$
Instead of range(x)
, you can use the *
operator on a list of anything, if you don't actually need to use the value of i
:
for i in[1]*8:pass
as opposed to
for i in range(8):pass
If you need to do this more than twice, you could assign any iterable to a variable, and multiply that variable by the range you want:
r=1,
for i in r*8:pass
for i in r*1000:pass
Note: this is often longer than exec"pass;"*8
, so this trick should only be used when that isn't an option.
[1]*8
is shorter than range(8)
, you also get to save a space because for i in[...
is legal while for i in range...
is not".
\$\endgroup\$
Commented
Aug 18, 2014 at 17:13
exec"pass;"*8
is significantly shorter.
\$\endgroup\$
Commented
May 19, 2016 at 19:23
r=1
, r*8
is 8, and you can't iterate through a number. I guess you meant r=[1]
\$\endgroup\$
You can use the good old alien smiley face to reverse sequences:
[1, 2, 3, 4][::-1] # => [4, 3, 2, 1]
If L
is a list, use L[~i]
to get the i
'th element from the back.
This is the i
'th element of the reverse of L
. The bit complement ~i
equals -i-1
, and so fixes the off-by-one error from L[-i]
.
For ages it bothered me that I couldn't think of a short way to get the entire alphabet. If you use range
enough that R=range
is worth having in your program, then
[chr(i+97)for i in R(26)]
is shorter than the naive
'abcdefghijklmnopqrstuvwxyz'
, but otherwise it's longer by a single character. It haunted me that the clever one that required some knowledge of ascii values ended up being more verbose than just typing all the letters.
Until I saw this answer for My Daughter's Alphabet. I can't follow the edit history well enough to figure out if this genius was the work of the OP or if it was a suggestion by a commenter, but this is (I believe) the shortest way to create an iterable of the 26 letters in the Roman alphabet.
map(chr,range(97,123))
If case doesn't matter, you can strip off another character by using uppercase:
map(chr,range(65,91))
I use map
way too much, I don't know how this never occurred to me.
string.lowercase
-- that's what it's there for.
\$\endgroup\$
ord('z')
)? Aside from it being the same length... Also, if you need alphanumerics, replace str.isalpha
in @quintopia's version with str.isalnum
. (But if you only need one case, the whole 36-character string is no longer than filter(str.isalnum,map(chr,range(90)))
.)
\$\endgroup\$
Commented
Dec 21, 2015 at 5:36
R
, my version is shorter than your original one: '%c'*26%tuple(R(97,123))
(only 24 chars) if you spell range
it is just as long as the alphabet -- uppercase version is shorter
\$\endgroup\$
Commented
Dec 21, 2017 at 20:26
You can write sets like this S={1,2,3}
This also means you can check for membership using {e}&S
instead of e in S
which saves one character.
Choosing one of two numbers based on a condition
You already know to use the list selection [x,y][b]
with a Boolean b
for the ternary expression y if b else x
. The variables x
, y
, and b
can also be expressions, though note that both x
and y
are evaluated even when not selected.
Here's some potential optimizations when x
and y
are numbers.
[0,y][b] -> y*b
[1,y][b] -> y**b
[x,1][b] -> b or x
[x,x+1][b] -> x+b
[x,x-1][b] -> x-b
[1,-1][b] -> 1|-b
[x,~x][b] -> x^-b
[x,y][b] -> x+z*b
(or y-z*b
), where z=y-x.You can also switch x
and y
if you can rewrite b
to be its negation instead.
[-x,~x][b] -> -x-b
\$\endgroup\$
Commented
Jul 20, 2022 at 12:41
When you have two boolean values, a
and b
, if you want to find out if both a
and b
are true, use *
instead of and
:
if a and b: #7 chars
vs
if a*b: #3 chars
if either value is false, it will evaluate as 0
in that statement, and an integer value is only true if it is nonzero.
&
: a=b=False
, a&b
\$\endgroup\$
Commented
Apr 9, 2014 at 7:56
+
for or
if you can guarantee a != -b
\$\endgroup\$
Commented
Apr 23, 2015 at 1:18
|
works in all situations.
\$\endgroup\$
Commented
May 31, 2017 at 1:30
*
instead of and
/&&
saves some bytes in many languages.
\$\endgroup\$
*
unfortunately only works if what youre comparing are bool variables, otherwise you need parentheses, which cuts out any savings over using and
, but I have found that >0<
actually works as an and
, and at least cuts out a byte or two of whitespace
\$\endgroup\$
Although python doesn't have very golfable switch statements (the match
/case
syntax since Python 3.10), you can emulate them with dictionaries. For example, if you wanted to golf this:
match a:
case 1: runCodeOne()
case 2: runCodeTwo()
case 3: runCodeThree()
case _: runDefault()
You could use if
statements, or you could use one of these:
# Code as strings
exec{1:"runCodeOne()",2:"runCodeTwo()",3:"runCodeThree()"}[a]
# Functions with non-consecutive indices
{1:runCodeOne,4:runCodeFour,30:runCodeThirty)[a]()
# Functions with consecutive indices
# (you can't add a default value)
(0,runCodeOne,runCodeTwo,runCodeThree)[a]()
# Code as strings (and default code)
exec{ <same as before> }.get(a,"runDefault()")
# Run functions (and default function)
{ <same as before> }.get(a,runDefault)()
This can be used to condense return statements:
# Before
def getValue(k):
if k=='blah':return 1
if k=='foo':return 2
if k=='bar':return 3
return 4
# After
# getValue = ...
lambda k:{'blah':1,'foo':2,'bar':3}.get(k,4)
dict(s1=v1,s2=v2,...,sn=vn)
instead of {'s1':v1,'s2':v2,...,'sn':vn}
saves 2*n-4 bytes and is better if n>=3
\$\endgroup\$
match
statement was added in 3.10. python.org/dev/peps/pep-0636
\$\endgroup\$
Commented
Nov 3, 2021 at 15:43
exec{...}[k];func()
instead of (previously) exec{...}[k]+";func()"
, being 3 bytes shorter
\$\endgroup\$
With the release of Python 3.5, manipulation of lists, tuples, sets and dicts just got golfier.
Compare the pairs:
set(T)
{*T}
list(T)
[*T]
tuple(T)
(*T,)
Much shorter! Note, however, that if you just want to convert something to a list and assign it to a variable, normal extended iterable unpacking is shorter:
L=[*T]
*L,=T
A similar syntax works for tuples:
T=*L,
which is like extended iterable unpacking, but with the asterisk and comma on the other side.
Unpacking is slightly shorter than concatenation if you need to append a list/tuple to both sides:
[1]+T+[2]
[1,*T,2]
(1,)+T+(2,)
(1,*T,2)
This isn't limited to print
, but it's definitely where most of the mileage will come from. PEP448 now allows for multiple unpacking, like so:
>>> T = (1, 2, 3)
>>> L = [4, 5, 6]
>>> print(*T,*L)
1 2 3 4 5 6
This probably won't happen very often, but the syntax can be used to save on updating dictionaries if you're updating at least three items:
d[0]=1;d[1]=3;d[2]=5
d={**d,0:1,1:3,2:5}
This basically negates any need for dict.update
.
If you ever want to get the rounded-up result for a division, much like you'd do with //
for floor, you could use math.ceil(3/2)
for 15 or the much shorter -(-3//2)
for 8 bytes.
math.floor(n) : 13 bytes+12 for import
n//1 : 4 bytes
math.ceil(n) : 12 bytes+12 for import
-(-n//1) : 8 bytes
n//1+1
instead of ceil but it does mean ceil(n)=n+1 but it should work for all non integer values
\$\endgroup\$
round(x)
is (x+.5)//1
, +1 byte but the latter starts with a (
, and if x
is a sum consisting of a constant it can be useful.
\$\endgroup\$
Commented
Apr 28, 2018 at 5:27
loops up to 4 items may be better to supply a tuple instead of using range
for x in 0,1,2:
vs
for x in range(3):
+=
instead of append
and extend
A.append(B)
can be shortened to:
A+=B,
B,
here creates a one-element tuple which can be used to extend A
just like [B]
in A+=[B]
.
A.extend(B)
can be shortened to:
A+=B
return 0
or return 1
is equivalent to return False
or return True
.
\$\endgroup\$
Commented
Apr 16, 2014 at 8:30
-x
rather than x*-1
. --8.32
rather than -8.32*-1
. Or just 8.32
...
\$\endgroup\$
Commented
Apr 20, 2014 at 22:56
A+=B
B
is a tuple
.
\$\endgroup\$
Commented
Jun 10, 2016 at 7:52
|=
in place of +=
\$\endgroup\$
Change import *
to import*
If you haven't heard, import*
saves chars!
from math import*
is only 1 character longer than import math as m
and you get to remove all instances of m.
Even one time use is a saver!
A one line function can be done with lambda:
def c(a):
if a < 3: return a+10
else: return a-5
can be converted to (note missing space 3and
and 10or
)
c=lambda a:a<3and a+10or a-5
c=lambda a:a+[-5,10][a<3]
. the and/or trick is more useful when you are depending on the shortcircuit behaviour
\$\endgroup\$
else:
can be dropped as return
stops the execution of the function, so everything that follows is only executed if the if
condition failed, aka if the else
condition is true. Thus else
can safely be ommited. (Explained in details for the neophytes out there)
\$\endgroup\$
Python 2 lets you convert an object x
to its string representation `x`
at a cost of only 2 chars. Use this for tasks that are easier done on the object's string than the object itself.
Join characters
Given a list of characters l=['a','b','c']
, one can produce ''.join(l)
as `l`[2::5]
, which saves a byte.
The reason is that `l`
is "['a', 'b', 'c']"
(with spaces), so one can extract the letters with a list slice, starting that the second zero-indexed character a
, and taking every fifth character from there. This doesn't work to join multi-character strings or escape characters represented like '\n'
.
Concatenate digits
Similarly, given a non-empty list of digits like l=[0,3,5]
, one can concatenate them into a string '035'
as `l`[1::3]
.
This saves doing something like map(str,l)
. Note that they must be single digits, and can't have floats like 1.0
mixed in. Also, this fails on the empty list, producing ]
.
Check for negatives
Now, for a non-string task. Suppose you have a list l
of real numbers and want to test if it contains any negative numbers, producing a Boolean.
You can do
'-'in`l`
which checks for a negative sign in the string rep. This shorter than either of
any(x<0for x in l)
min(l+[0])<0
For the second, min(l)<0
would fail on the empty list, so you have to hedge.
str(l)[2::5]
is 12 bytes, versus 19 for ''.join(map(str,l))
. An actual situation where this came up (where l
was a generator statement, not a list) saved me just one byte... which is still worth it!
\$\endgroup\$
Commented
Dec 21, 2015 at 2:08
sum
doesn't work for lists of strings.
\$\endgroup\$
Commented
Aug 18 at 0:26
I've think it would be useful to have a reference for the character count differences for some common alternative ways of doing things, so that I can know when to use which. I'll use _
to indicate an expression or piece of code.
Assign to a variable: +4
x=_;x
_
So, this breaks even if you
_
a second time: _
has length 5_
a third time: _
has length 3Assign variables separately: 0
x,y=a,b
x=a;y=b
a
equals b
for x=y=a
Expand lambda
to function def
: +7
lambda x:_
def f(x):return _
_
can touch on the leftprint
rather than return*x
Generically, if you're def
to save an expression to a variable used twice, this breaks even when the expression is length 12.
lambda x:g(123456789012,123456789012)
def f(x):s=123456789012;return g(s,s)
STDIN rather than function: +1
def f(x):_;print s
x=input();_;print s
_
if not single-lineraw_input
needed in Python 2return
rather than print
in Python 2Use exec
rather than looping over range(n)
: +0
for i in range(n):_
i=0;exec"_;i+=1;"*n
exec()
range(c,c+n)
for single-char c
n
to 1
via range(n,0,-1)
Apply map
manually in a loop: +0
for x in l:y=f(x);_
for y in map(f,l):_
Apply map
manually in a list comprehension: +8
map(f,l)
[f(x)for x in l]
f
must be written in the map
as the lambda
expression lambda x:f(x)
, causing overall 4 char loss.Apply filter
manually in a list comprehension: +11
filter(f,l)
[x for x in l if f(x)]
f(x)
expression can touch on the leftf
must be written in the filter
as the lambda
expression lambda x:f(x)
, causing overall 1 char loss.Import versus import single-use: +4*
import _;_.f
from _ import*;f
_
has length 5import _ as x;x.f
is always worse except for multiple imports__import__('_').f
is also worseThanks to @Sp3000 for lots of suggestions and fixes.
lambda x:g(123456789012,123456789012)
can be replaced with lambda x:g(a:=123456789012,a)
\$\endgroup\$
Commented
Aug 19 at 0:10
:=
operator in 3.8 \$\endgroup\$