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.
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()[?])()
:=
in list comprehension to store the previous value of the iterableInstead of the convoluted
f=[s[i]for i in range(len(s))if s[i-1]!=s[i]]
You can use
e=""
f=[c for c in s if e!=(e:=c)]
Which saves 11 bytes in this example. Care needs to be taken that e
is reassigned after being evaluted. It also needs to be initialised before the list, which is quite easy to do with default function arguments
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\$
Abusing try
/except
blocks can sometimes save characters, especially for exiting out of nested loops or list comprehensions. This:
for c in s:
for i in l:
q=ord(c)==i
if q:print i,c;break
if q:break
... can become this, saving 3 characters:
try:
for c in s:
for i in l:
if ord(c)==i:print i,c;1/0
except:0
... which in this particular instance can be compressed even further using list comprehensions:
try:[1/(ord(c)-i)for c in s for i in l]
except:print i,c
For an example, see e.g. https://codegolf.stackexchange.com/a/36492/16766.
When using Python 3, for your final print statement, use exit
to save one char (note: this prints to STDERR, so you might not be able to use this):
print('x')
exit('x')
exit
even adds a trailing newline. There is one caveat, however: exit(some_integer)
will not print.
exit(some_integer)
is valid because exit code is a default output form.
\$\endgroup\$
Commented
Jun 23, 2020 at 15:20
Use list(iter(input,eof))
to take multi-line input. eof
can be any string that you want to stop taking input on if you see it. An example would be eof = ''
. The python 2 version is list(iter(raw_input,eof))
, however you may want to use sys.stdin.readlines()
instead if you have already imported sys
.
list(iter(input,eof))
is shorter by one, you don't need that space. Also worth noting that this is only for Python 3 - Python 2 is 4 bytes longer because raw_input
.
\$\endgroup\$
read(0)
returns an iterable of all lines of input on many systems (in Python 3.9, not sure when it was added).
\$\endgroup\$
Commented
May 16, 2021 at 19:24
l.insert(x,y) # before
l[x:x]=y, # after
l.reverse() # before
l[::-1]=l # after
l.append(x) # before
l[L:]=x, # after (where L is any integer >= len(l))
l[:]=x # set the contents of l to the contents of x
EDIT: thanks to @quintopia for pointing this out, these are statements, not expressions. The mutator methods are void functions, so they are expressions which evaluate to None
. This means that things like [l.reverse() for x in L]
and condition or l.reverse()
are valid, whereas [l[::-1]=l for x in L]
and condition or l[::-1]=l
are not.
or
or and
as conditionals, assignment is not allowed, but append
and the like are.
\$\endgroup\$
Commented
Jan 13, 2016 at 5:34
l[:]=x
is a bit unpythonic - same number of bytes, but I reckon l=x[:]
is better practice. Also, [::-1]
is listed as a tip here, L[:x]+=y,
is better for the general case where x
might be an expression (but same byte count if it's just x
), and l+=x,
is listed here for append.
\$\endgroup\$
l[:]=x
and l=x[:]
do different things. The former mutates the list itself, i.e. all references to that list, whereas the latter sets the variable l to a copy of x
\$\endgroup\$
Many sequence challenges ask you to find the n'th number in a sequence of increasing positive integers. When you have a expression p(i)
that checks membership, you can do this with the recursive function:
f=lambda n,i=1:n and-~f(n-p(i),i+1)
Note that expression p(i)
must give 0 or 1, not just Falsey or Truthy. The outputs are one-indexed, so say for the sequence of primes, it would give
f(1) = 2
f(2) = 3
...
For 0-indexed outputs, shift the base case
f=lambda n,i=1:n+1and-~f(n-p(i),i+1)
The recursive function f=lambda n,i=1:n and-~f(n-p(i),i+1)
works by decrementing the required count n
each time it gets a hit, and incrementing the output value each time for each value it checks. It might seem weird to redundantly track i
, but it's longer to do:
f=lambda n,i=1:n and f(n-p(i),i+1)or~-i
Also compare the natural list strategy (zero-indexed here)
lambda n:[i for i in range(n*n)if p(i)][n]
(You might need a larger bound than n*n
.)
Format() works on dates:
"We are in year: %s" % (date.strftime('%y'))
Becomes:
"We are in year: {:%y}".format(date)
Or even better with f-strings:
f"We are in year: {date:%y}"
Say you have a challenge to find the difference of some characteristic on two inputs. Your solution has the form lambda a,b:e(b)-e(a)
, where e
is some long expression you've written. Repeating e
twice is wasteful, so what do you do?
Here are templates sorted by length. Assume that e
stands for a long expression, not one that's already defined as a function. Also assume inputs can be taken in either order.
lambda*l:eval('e(%s)-'*2%l+'0')
*Requires that e
only mentions its variable once. Assumes -e(x)
negates the whole expression, otherwise requires parens like -(e(x))
for two more bytes.
f=lambda a,*b:e(a)-(b>()and f(*b))
lambda a,b:d(b)-d(a)
d=lambda x:e(x)
a,b=[e(x)for x in input()]
print b-a
r=0
for x in input():r=e(x)-r
print r
lambda*l:int.__sub__(*[e(x)for x in l])
I've seen this code to get a character matrix (2D array) as a string.
'\n'.join(''.join(i)for i in M)
It's shorter to use a map
instead:
'\n'.join(map(''.join,M))
If you're printing the result, it's shortest to use a for
loop:
print('\n'.join(map(''.join,M)))
for i in M:print(*i,sep='') # -5 bytes
If you're using Python 2, you can't use the print
trick, but you can still use the for
loop:
for i in M:print(''.join(i)) # -3 bytes
In Python,
True == 1 # true
False == 0 # true
So,
(a<b)*2-1
returns 1 if b is larger than a. If not, returns -1.
More golfing,
-(a>b)|1
returns exactly same value as mentioned above.
Useful when modify iterator index by comparable values.
In addition to the famous walrus operator, Python 3.8 introduces useful new math features.
Modular inverse
The modular-power built-in pow(base, exp, mod)
can now compute the modular inverse using exp=-1
. This requires that base
and mod
are relatively prime integers.
>>> pow(38, -1, 97)
23
>>> 23 * 38 % 97 == 1
True
exp
may be any negative integer, which lets you compute modular powers of the modular inverse.
The math library has useful new functions for combinatorics and distances. Access them with import math
. Or, write from math import*
to import them without the math.
, which is worth it if you write more than one call.
Combinatorics
math.comb(n,k)
: The binomial coefficient n choose k
, which equals n! / (k! * (n - k)!)
.math.perm(n,k)
: The number of ordered choices of k
elements from n
, which is n! / (n - k)!
. Calling just math.perm(n)
gives n!
, useful as a synonym for math.factorial(n)
.math.prod(l)
: The product of the elements of a list or iterable l
, analogous to sum
.Distances and square roots
math.dist(p,q)
: The Euclidean distance between two points p
and q
. The inputs p
and q
must be lists or iterables that are the same length.math.hypot(*p)
: The Euclidean distance from a point p
to zero. Now takes any number of arguments; before it took only two. For some reason, arguments still must be splatted like math.hypot(1,2,3)
rather than math.hypot([1,2,3])
.math.isqrt(n)
: The integer square root, that is the floor of the square root of n
. Requires than n
is a non-negative integer. Usually n**.5//1
suffices instead, but this gives exact integer output rather than a float.exec
to remove repeated print
This is not quite often applicable, but can save some bytes, especially in ASCII art. Take the following code, which prints the flag where n=4
.
# 43 bytes | ***
n=input() | **
while~-n:n-=1;print'*'*n | *
print'|' | |
Notice that we repeat print
twice. We can remove this using exec
in the following code, saving 3 bytes.
# 40 bytes
n=input()
exec"'*'*n;n-=1;print"*n+"'|'"
Suppose we have to print a list as a string with spaces, like square of numbers upto 10
. Then,
print(' '.join(str(i**2)for i in range(11))) # 44 chars
print(*(i**2for i in range(11))) # 32 chars
print(*[_*_ for _ in range(11)])
is same 32 bytes but less cluttered by not having 2f
clumped up
\$\endgroup\$
Commented
May 28 at 7:34
while 1
It is possible to shorten a while 1:
by replacing the 1
with an existing expression inside of the loop body. Common ways to make use of this in Python 3 include embedding
print()
statement:while 1:print(x);...
# vs
while[print(x)]:...
while 1:x>1==print(x);...
# vs
while[x>1==print(x)]:...
while 1:x=1;...
while x:=1:...
In general, any expression (one that returns a value), can be used as the while
condition to save a byte or two. Often it's necessary to wrap the expression in []
to ensure it maintains a truthy value.
When you write a quoted literal string in your code, perhaps to compress a big blob of data, certain characters must be replaced by a two-character escape sequence.
Null byte \0
(ASCII 0)
The null byte can't be present verbatim in Python code. Write it as \0
.
Newline \n
(ASCII 10)
An actual newline \n
can't appear in a string literal because the Python lexer will read it and think the line has ended without closing the initial quote. But, a triple-quoted string like '''stuff'''
or """stuff"""
may contain newlines. This saves bytes with 5+ newlines, which can be useful in ASCII art.
Carriage return \r
(ASCII 13)
A carriage return always needs escaping as \r
. Though allowed in a triple-quoted string, a literal \r
is misread as a newline \n
.
Quotes "
(ASCII 34) and '
(ASCII 39)
A single-quoted string can contain double quotes like '"'
, but must escape single-quotes like '\''
, and vice-versa for double-quoted strings. Choose whichever option leads to less escaping.
A triple-quoted string is OK with unescaped quotes of the same type like '''it's'''
. But, having quotes at the start and end or three-in-a-row can confuse the lexer into giving a SyntaxError.
Backslash \
(ASCII 92)
A backslash can be escaped as \\
. But, Python allows just writing \
if it's followed by a character that can't make it an escape sequence. This is any character not in abfnrtvx0123456789"'\
or literal newline \n
.
You can use a r
-prefixed raw string like r'\n'
to ignore most escape sequences, so r'\n'
is just a backslash followed by a letter n
and r'\\'
is two backslashes. Quote characters still get escaped but don't consume the backslash, so r'\''
is backslash then single-quote. This can cause complications: r'\'
, r'\\\'
, and r'\\''
all give SyntaxError.
For reference, the special characters are ASCII values [0, 10, 13, 39, 34, 92]
. When doing compression, you might tweak your method to avoid hitting these values.
Some weird characters can be written verbatim without escaping, such as:
\a
(ASCII 7)\b
(ASCII 8)\t
(ASCII 9)\f
(ASCII 12)StackExchange posts won't render these, but Python clients and TIO should handle them fine. Here they are for copy-pasting.
Characters with ASCII codes 128 and up can't be included in Python 2 code without a extra line declaring an encoding like this. Python 3, though, handles them fine, including multibyte Unicode characters.
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)
[x**2for x in range(10)]
\$\endgroup\$
[x*2for x in range(10)]
\$\endgroup\$
shortList = list(range(0, 20, 2))
\$\endgroup\$
Commented
Dec 7, 2022 at 8:50
*shortList,=range(0,20,2)
or as an expression, [*range(0,20,2)]
will make it a list
with fewer characters than calling list()
(constructor call adds six, [*...]
adds three over just range(0,20,2)
, and *shortList,=range(0,20,2)
only adds two).
\$\endgroup\$
Commented
Feb 10, 2023 at 20:55
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\$
Commented
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\$
Commented
Apr 21, 2015 at 13:36
If you need to import a lot of modules you can reassign __import__
to something shorter, this also has the advantage of being able to name imports anything you want.
i=__import__;s=i('string');x=i('itertools');
import string,itertools
, import string,itertools as M
, from itertools import*
and other variants tend to be shorter...
\$\endgroup\$
s,i=map(__import__,['string','itertools'])
is shorter than your example, but still longer than import string as s,itertools as i
\$\endgroup\$
Commented
Jul 12, 2017 at 14:44
map
approach does scale better if you are using a single space-separated string and splitting it. But to pull ahead of the alternatives, you'd need a lot of imports. As in s,i,c,p,f,b,d=map(__import__,'string itertools collections subprocess fractions bisect datetime'.split())
. So probably not useful in most golfing scenarios. :-)
\$\endgroup\$
Commented
Feb 24, 2023 at 2:19
Use str.title
instead for single words. The difference between the two functions is that capitalize
only capitalises the first word, while title
capitalises all words:
>>> "the quick brown fox".capitalize()
'The quick brown fox'
>>> "the quick brown fox".title()
'The Quick Brown Fox'
str.find
is almost always better, and even returns -1 if the substring is not present rather than throwing an exception.
See this tip by @xnor.
str.split
is shorter:
s.splitlines()
s.split('\n')
However, str.splitlines
may be useful if you need to preserve trailing newlines, which can be done by passing 1
as the keepends
argument.
splitlines
also avoids a trailing blank line when the string ends in a newline. 'foo\nbar\n'.split('\n')
produces ['foo', 'bar', '']
(len 3, with trailing empty string), while 'foo\nbar\n'.splitlines()
produces ['foo', 'bar']
(len 2, no trailing empty string), which can save trouble in some cases.
\$\endgroup\$
Commented
Feb 24, 2023 at 2:23
repeat
argument of itertools.product
As @T.Verron points out, in most cases (e.g. ranges and lists), you can instead do
product(*[x]*n)
However, even if you have a generator which you can only use once, like a Python 3 map
, the repeat
argument is still unnecessary. In such a case you can use itertools.tee
:
product(x,repeat=n)
product(*tee(x,n))
For n = 2
you don't even need to include n
, since 2 is the default argument to tee
.
product(*[L]*n)
is even shorter.
\$\endgroup\$
Commented
Oct 8, 2015 at 11:59
map
, for which that wouldn't work, but I'll add it as a note thanks :)
\$\endgroup\$
Say you have an dictionary literal, which I'll denote {...}
, and you want to get the value for a key k
, with a default of d
if k
is missing.
You can save two bytes by prepending an entry rather than using get
{k:d,...}[k]
{...}.get(k,d)
Because later entries override earlier ones of the same key, the entry k:d
gets overwritten if it appears in the dict, but remains if key k
isn't present.
Note that this required writing k
twice, which is fine for a variable, but poor when k
is an expression.
Access list, while building it inside comprehension
In python version 2.4 (and <2.3 with some tweaks) it is possible to access list, from list comprehension. Source #1, Source #2 (Safari, Python Cookbook, 2nd edition)
Python creates secret name _[1]
for list, while it is created and store it in locals
. Also names _[2]
, _[3]
... are used for nested lists.
So to access list, you may use locals()['_[1]']
.
In earlier versions this is not enough. You'll need to use locals()['_[1]'].__self__
I couldn't find evidence, that somethins like that is possible in versions >2.4
Don't think, that it might be usefull often, but who knows! At least it helps with building one-liners.
Example:
# Remove duplicates from a list:
>>> L = [1,2,2,3,3,3]
>>> [x for x in L if x not in locals()['_[1]']]
[1,2,3]
'.0'
, and it's a generator.
\$\endgroup\$
If transforming from list to a tuple or set to a set, list or tuple is needed, as of Python 3.5 you can use the splat operator:
tuple(iterable) -> (*iterable,) (-3 bytes)
set(iterable) -> {*iterable} (-2 bytes)
list(iterable) -> [*iterable] (-3 bytes)
If you're doing this as well as appending/prepending, you can do the following for an extra bonus:
iterable+[1] -> *iterable,1 (-2 bytes, 3 for tuples)
iterable+iter2 -> *iterable,*iterable2 (+1 byte, 0 for tuples, though can combine types)
[1]+iterable+[1] -> 1,*iterable,1 (-3 bytes, -4 for tuples)
iterable+[1]+iter2 -> *iterable,1,*iter2 (0 bytes, -1 for tuples)
Basically, ,*
instead of ,
gives a +1 byte penalty and ,
instead of ,[]
gives -2 bytes.
This shows [1,*iterable,1]
is a golfier way of doing [1]+iterable+[1]
by one byte, even when we're not doing any type conversion.
And just for fun, {*{}}
is the same length as set()
for challenges without letters.
set()
(e.g. ...and set()
can become ...and{*{}}
). Oh, and it can be replaced with {*()}
or {*[]}
if an empty dict
feels unsettling. ;-)
\$\endgroup\$
Commented
Jun 29, 2018 at 22:37
(not deep clone. For deep clone see this answer)
(credit to this answer)
a=x[:]
b=[*x]
c=x*1
*d,=x
\$\endgroup\$
not
with 1-
In python, the negation operator not
wastes bytes, so we have to find a shorter way. Negation can be implemented as subtraction from 1 (obtained from my Keg experiece), which saves 1 byte. (Also, True
and False
can be alternatively represented as 1
and 0
internally, so this will not matter much.)
Compare this program:
lambda s:not(s[0]+s[-1]).isdigit()
With this program:
lambda s:1-(s[0]+s[-1]).isdigit()
Some straightforward tricks that might help:
and -> *
or -> +
dict.get
as a first-class function# all keys in the dict G with a truthy value
[k for k in G if G[k]]
filter(G.get,G)
# all keys in the dict G with a falsy value
[k for k in G if not G[k]]
G.keys()-filter(G.get,G)
{…,**d}
or a|b
to merge dict
s in Python# merge two dicts
a={…}
b={…}
# Python <3.9
merged={**a,**b} # the order lets you decide which overrides which
# Python ≥3.9
merged=a|b
# set a defaut value
G.setdefault(a,1)
G[a]=G.get(a,1)
# Python <3.9
G={a:1,**G}
# Python ≥3.9
G={a:1}|G
::
# This is a very specific tip when you want to get both an element at
# the near beginning of a list and one somewhere near the end.
# For example, let's assume you want to take the elements at indices i=6 and j=37
# from a list L of length l=40 (it works only if i+j*2<l)
# ok
a=L[5];b=L[36]
# equivalent
a,b=L[5],L[36]
# 36 = 5 + 31
a,b=L[5::31]
set()
is 5 chars just to create an empty set. If you can have an initial element e
, you can save 2 chars with {e}
.
# assuming the function iterates on its argument
f([x**2 for x in range(4)])
f(x**2 for x in range(4))
If you're accessing a static method or class method, for example int.from_bytes
or dict.fromkeys
, you can also still access them on instances of that class - it doesn't have to be on the class itself. It's very often shorter to do this:
int.from_bytes(...
0 .from_bytes(...
dict.fromkeys(...
{}.fromkeys(...
Often you already have an instance of that class stored in a one-letter variable, so it can be even shorter:
x.from_bytes
It doesn't matter what value x
is, and it isn't changed.
You can use list checking instead of using or
s in a clause statement.
e.g. instead of using
if i % 3 == 0 or i % 5 == 0 or i % 7 == 0 ...:
# Golfed:
if i%3==0or i%5==0or i%7==0 ...:
use
if 0 in [i % 3, i % 5, i % 7, ...]:
# Golfed:
if 0in[i%3,i%5,i%7,...]:
This saves around 2-3
characters per condition, but can only be used in certain circumstances.
:=
operator in 3.8 \$\endgroup\$