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.
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\$
May 16, 2021 at 19:24
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}"
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.It's common to want to iterate over adjacent pairs of items in a list or string, i.e.
"golf" -> [('g','o'), ('o','l'), ('l','f')]
There's a few methods, and which is shortest depends on specifics.
Shift and zip
## 47 bytes
l=input()
for x,y in zip(l,l[1:]):do_stuff(x,y)
Create a list of adjacent pairs, by removing the first element and zipping the original with the result. This is most useful in a list comprehension like
sum(abs(x-y)for x,y in zip(l,l[1:]))
You can also use map
with a two-input function, though note that the original list is no longer truncated.
## Python 2
map(cmp,l[:-1],l[1:])
Keep the previous
## 41 bytes, Python 3
x,*l=input()
for y in l:do_stuff(x,y);x=y
Iterate over the elements of the list, remembering the element from a previous loop. This works best with Python 3's ability to unpack to input into the initial and remaining elements.
If there's an initial value of x
that serves as a null operation in do_stuff(x,y)
, you can iterate over the whole list.
## 39 bytes
x=''
for y in input():do_stuff(x,y);x=y
Truncate from the front
## 46 bytes
l=input()
while l[1:]:do_stuff(*l[:2]);l=l[1:]
Keep shortening the list and act on the first two elements. This works best when your operation is better-expressed on a length-two list or string than on two values.
I've written these all as loops, but they also lend to a recursive functions. You can also adjust to get cyclic pairs by putting the first element at the end of the list, or as the initial previous-value.
The Python 3.8 "walrus" assignment expressions allow a short expression to give pairs, though with an extra initial element.
>>> p=''
>>> [(p,p:=c)for c in"golf"]
[('', 'g'), ('g', 'o'), ('o', 'l'), ('l', 'f')]
x
that serves as a null operation" at the end of your list as well so the final item is processed with it you can do x=''(\n)for y in*input(),x:do_stuff(x,y);x=y
\$\endgroup\$
Jul 4, 2021 at 22:30
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+"'|'"
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.
0in
instead of not all
(or, under DeMorgan's Law, any(not ...)
)
not all(...)
~-all(...) # shorter than `not`, and with more forgiving precedence
0in(...)
not all map(f,a)
0in map(f,a) # the reduction is more significant here because you can omit the parentheses
This only works if the falsey values in the ...
sequence are actually False
(or 0
/0.0
/etc.) (not []
/""
/{}
etc.).
1in
instead of any
This one isn't shorter with a comprehension:
any(f(x)for x in a)
1in(f(x)for x in a)
But it sometimes saves bytes with other kinds of expression by letting you omit the parentheses:
any(map(f,a))
1in map(f,a)
This has a similar truthiness-related caveat to the above, though.
These might sometimes have less favourable precedence, because they use the in
operator. However, if you're combining this with a comparison you may be able to make additional use of this tip about comparison condition chaining.
You can also use these if you want the entire for
-comprehension in any
/all
to always be fully evaluated:
any([... for x in a])
1in[... for x in a]
This one's rare, but if you need to evaluate and discard an extra expression for every item in a comprehension, you could use a dictionary here at no extra cost:
1in[(condition,side_effect)[0]for x in a]
1in{condition:side_effect for x in a}
because dict
's in
checks only the keys.
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\$
Jul 12, 2017 at 14:44
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.
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.
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.
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\$
Jun 29, 2018 at 22:37
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])
(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 -> +
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
You can compute cos
and sin
without needing to import math
by using complex arithmetic. For an angle of d
degrees, its cosine is
(1j**(d/90)).real
and its sine is
(1j**(d/90)).imag
Here, 1j
is how Python writes the imaginary unit \$i\$. If your angle is r
radians, you'll need to use 1j**(r/(pi/2))
, using a decimal approximation of pi/2
if the challenge allows it.
If you're curious, this all works because of Euler's formula:
$$i^x = (e^{i \pi /2})^x = e^{i \pi /2 \cdot x} = \cos(\pi/2 \cdot x) + i \sin(\pi /2 \cdot x)$$
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.
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.
!=
can be replaced with -
here is a example
n=int(input())
if n!=69:
print("thanks for being mature")
instead of using !=
you can use -
after that it should look like this
n=int(input())
if n-69:
print("thanks for being mature")
Sometimes you can use Python's exec
-statement combined with string repetition, to shorten loops. Unfortunately, you can't often use this, but when you can you can get rid of a lot of long loop constructs. Additionally, because exec
is a statement you can't use it in lambdas, but eval()
might work (but eval()
is quite restricted in what you can do with it) although it's 2 characters longer.
Here is an example of this technique in use: GCJ 2010 1B-A Codegolf Python Solution
eval()
I was most likely thinking of. You can't do eval("print 1")
because print 1
is a statement. I'll update the post.
\$\endgroup\$
Jan 28, 2011 at 10:23
eval("print(1)")
since print()
is now a function.
\$\endgroup\$
Apr 20, 2014 at 23:02
exec("print(1)")
since exec()
is now a function.
\$\endgroup\$
May 28, 2017 at 5:37
Was somewhat mentioned but I want to expand:
[a,b],[c,d]=[[1,2],[3,4]]
works as well as simple a,b=[1,2]. Another great thing is to use ternary operator (similiar to C-like ?:)
x if x<3 else y
and no one mentioned map. Map will call first function given as first argument on each item from second argument. For example assume that a is a list of strings of integers (from user input for example):
sum(map(int,a))
will make sum of all integers.
If you rely on data (mostly for kolmogorov-complexity problems), use the built-in zip encoding/decoding and store the data in a file (add +1 for the filename):
open('f','rb').read().decode('zip')
If you have to store the data in the source code, then you need to encode the zip with base64 and do:
"base64literal".decode('base64').decode('zip')
These don't necessarily save characters in all instances, though.
When your program needs to return a value, you might be able to use a yield
, saving one character:
def a(b):yield b
However, to print it you'd need to do something like
for i in a(b):print i
print next(i())
will work too.
\$\endgroup\$
Jun 23, 2014 at 13:35
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\$
Jun 23, 2020 at 15:20
Instead of
isinstance(x,C) # 15 bytes
there are several alternatives:
x.__class__==C # 14 bytes
'a'in dir(x) # 12 bytes, if the class has a distinguishing attribute 'a'
type(x)==C # 10 bytes, doesn't work with old-style classes
'K'in`x` # 8 bytes, only in python 2, if no other classes contain 'K'
# watch out for false positives from the hex address
Some of them may save extra bytes depending on the context, because you can eliminate a space before or after the expression.
Thanks Sp3000 for contributing a couple of tips.
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
.
map
, for which that wouldn't work, but I'll add it as a note thanks :)
\$\endgroup\$
:=
operator in 3.8 \$\endgroup\$