297
\$\begingroup\$

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.

\$\endgroup\$
4

157 Answers 157

5
\$\begingroup\$

The best way to check whether is a number even or not

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:
\$\endgroup\$
4
\$\begingroup\$

Be aware of all, any and map:

if isdigit(a) and isdigit(b) and isdigit(c)
if all(map(isdigit,[a,b,c]))
\$\endgroup\$
2
  • 4
    \$\begingroup\$ 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 '14 at 8:33
  • 1
    \$\begingroup\$ Over a year later, I'm reading this thread again and I'm embarrassed about my previous comment. 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 '15 at 13:36
4
\$\begingroup\$

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');
\$\endgroup\$
2
  • 2
    \$\begingroup\$ I've rarely found this to be actually useful. Generally import string,itertools, import string,itertools as M, from itertools import* and other variants tend to be shorter... \$\endgroup\$
    – Sp3000
    Jul 25 '15 at 9:05
  • \$\begingroup\$ 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 '17 at 14:44
4
\$\begingroup\$

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.

\$\endgroup\$
4
\$\begingroup\$

Alternatives to builtin string functions

str.capitalize for single words

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.index

str.find is almost always better, and even returns -1 if the substring is not present rather than throwing an exception.

str.startswith

See this tip by @xnor.

str.splitlines

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.

\$\endgroup\$
4
\$\begingroup\$

Dictionary defaults as entries

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.

\$\endgroup\$
4
\$\begingroup\$

Find the n'th number meeting a condition

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.)

\$\endgroup\$
4
\$\begingroup\$

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.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ The last one can also be useful if there is a letter preceding 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 '18 at 22:37
4
\$\begingroup\$

Difference of two parallel expressions

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.

31 bytes*

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.

34 bytes

f=lambda a,*b:e(a)-(b>()and f(*b))

36 bytes

lambda a,b:d(b)-d(a)
d=lambda x:e(x)

36 bytes

a,b=[e(x)for x in input()]
print b-a

37 bytes

r=0
for x in input():r=e(x)-r
print r

39 bytes

lambda*l:int.__sub__(*[e(x)for x in l])
\$\endgroup\$
4
\$\begingroup\$

Formatting a Matrix

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
\$\endgroup\$
4
\$\begingroup\$

Replace 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 -> +
\$\endgroup\$
1
4
\$\begingroup\$

Using 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+"'|'"
\$\endgroup\$
4
\$\begingroup\$

Printing the elements of a list, with spaces

Suppose we have to print a list as a string with spaces, like square of numbers upto 10. Then,

Instead of,

print(' '.join(str(i**2)for i in range(11))) # 44 chars

We can do,

print(*(i**2for i in range(11))) # 32 chars
\$\endgroup\$
4
\$\begingroup\$

Combine assignments of reused values with unused for-loop variables

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 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.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ howdy there stranger! welcome to code gol...oh wait nevermind. \$\endgroup\$
    – lyxal
    Jul 20 at 11:44
3
\$\begingroup\$

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

\$\endgroup\$
6
  • \$\begingroup\$ What kind of restrictions are you thinking about? I don't think Python in itself has any kind of restriction on exec, so you must be referring to problem statements? \$\endgroup\$
    – hallvabo
    Jan 28 '11 at 8:43
  • \$\begingroup\$ @hallvabo, you're right it's 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\$
    – JPvdMerwe
    Jan 28 '11 at 10:23
  • \$\begingroup\$ As a general rule, this is worth trying when you need to do something n times, but don't care about the index. As soon as you need to initialise a loop variable and increment it, it ends up slightly longer than a for loop \$\endgroup\$
    – gnibbler
    Feb 3 '11 at 20:35
  • 2
    \$\begingroup\$ In Python 3 you can do eval("print(1)") since print() is now a function. \$\endgroup\$
    – trichoplax
    Apr 20 '14 at 23:02
  • 2
    \$\begingroup\$ In Python 3 you can also do exec("print(1)") since exec() is now a function. \$\endgroup\$ May 28 '17 at 5:37
3
\$\begingroup\$

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.

\$\endgroup\$
2
  • 5
    \$\begingroup\$ Quoting the OP: Please post one tip per answer. \$\endgroup\$
    – nyuszika7h
    Jun 23 '14 at 13:53
  • \$\begingroup\$ x if cond else y == cond and x or y. \$\endgroup\$
    – DELETE_ME
    Jul 5 '18 at 9:34
3
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$

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
\$\endgroup\$
2
  • 1
    \$\begingroup\$ If only a single value is yielded, print next(i()) will work too. \$\endgroup\$
    – nyuszika7h
    Jun 23 '14 at 13:35
  • \$\begingroup\$ Or just do print[*a(b)] \$\endgroup\$ Jun 5 '17 at 0:59
3
\$\begingroup\$

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.

\$\endgroup\$
4
  • \$\begingroup\$ Does this print to STDOUT or STDERR? This sounds like it would be the latter, but in most challenges only the former is allowed. \$\endgroup\$
    – Sp3000
    Apr 19 '15 at 4:24
  • \$\begingroup\$ @Sp3000 I don't know... how can I tell? \$\endgroup\$
    – Justin
    Apr 19 '15 at 5:18
  • \$\begingroup\$ Seems to be stderr \$\endgroup\$
    – Sp3000
    Apr 19 '15 at 5:32
  • \$\begingroup\$ exit(some_integer) is valid because exit code is a default output form. \$\endgroup\$ Jun 23 '20 at 15:20
3
\$\begingroup\$

Shorter isinstance

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.

\$\endgroup\$
3
\$\begingroup\$

Avoid the 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.

\$\endgroup\$
3
  • \$\begingroup\$ product(*[L]*n) is even shorter. \$\endgroup\$
    – T. Verron
    Oct 8 '15 at 11:59
  • \$\begingroup\$ @T.Verron The initial use case I had in mind was something like a Python 3 map, for which that wouldn't work, but I'll add it as a note thanks :) \$\endgroup\$
    – Sp3000
    Oct 8 '15 at 12:05
  • 1
    \$\begingroup\$ Doesn't feersum have an open 500-point bounty for using itertools at all in a sufficiently old question? \$\endgroup\$
    – lirtosiast
    Oct 8 '15 at 13:17
3
\$\begingroup\$

Optional empty sequence argument

Suppose we want to write a recursive function that prepends to a sequence (e.g. list, tuple) each time. For example, the Python 3 program

def f(n,k,L=[]):n and[f(n-1,k,[b]+L)for b in range(k)]or print(L)

works like itertools.product, taking n,k and printing all length n lists of numbers taken from range(k). (Example thanks to @xnor)

If we don't need L to be a list specifically, we can save on the optional empty list argument by making use of unpacking, like so:

def f(n,k,*T):n and[f(n-1,k,b,*T)for b in range(k)]or print(T)

where T is now a tuple instead. In the general case, this saves 3 bytes!

In Python 3.5+, this also works if we're appending to the end of a sequence, i.e. we can change f(n-1,k,L+[b]) to f(n-1,k,*T,b). The latter is a syntax error in earlier versions of Python though.

\$\endgroup\$
3
\$\begingroup\$

Use slicing + assignment instead of mutator methods

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.

\$\endgroup\$
4
  • \$\begingroup\$ Note that this cannot always be done. For instance, when using or or and as conditionals, assignment is not allowed, but append and the like are. \$\endgroup\$
    – quintopia
    Jan 13 '16 at 5:34
  • \$\begingroup\$ 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\$
    – Sp3000
    Feb 17 '16 at 7:10
  • \$\begingroup\$ @Sp3000 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\$
    – Cyoce
    Feb 17 '16 at 7:47
  • \$\begingroup\$ @Cyoce Oh, nevermind then - my eyes are going to have to get used to seeing that :P \$\endgroup\$
    – Sp3000
    Feb 17 '16 at 8:01
3
\$\begingroup\$

Use IDLE 3.3 to take multiline input

In IDLE versions 3.1 to 3.3, the command input() reads an entire multiline string like "line1\nline2", rather than a single line at a time as per the spec. This was fixed in version 3.4.

Calling input() only once is very convenient for golfing. Whether one can take advantage of this is debatable, but I think it is an acceptable interpreter- or environment-specific behavior.

\$\endgroup\$
2
  • \$\begingroup\$ Wait... so how do you... sort of, enter the string if Enter adds a newline rather than EOF? Does CTRL+D work on Windows? \$\endgroup\$
    – cat
    Mar 4 '16 at 3:00
  • 1
    \$\begingroup\$ @tac I copy-paste it into IDLE. \$\endgroup\$
    – xnor
    Mar 4 '16 at 3:30
3
\$\begingroup\$

Easiest way to swap two values

>>> a=5
>>> b=4
>>> a,b=b,a
>>> a
4
>>> b
5
\$\endgroup\$
3
\$\begingroup\$

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]
\$\endgroup\$
1
  • 5
    \$\begingroup\$ This still exists in later Pythons. In Python 3, it's called '.0', and it's a generator. \$\endgroup\$
    – isaacg
    Aug 18 '17 at 6:42
3
\$\begingroup\$

To assign to a tuple, don't use parentheses. For example, a=1,2,3 assigns a to the tuple (1, 2, 3). b=7, assigns b to the tuple (7,). This works in both Python 2 and Python 3.

\$\endgroup\$
0
3
\$\begingroup\$

Shorter way to copy/clone a list

(not deep clone. For deep clone see this answer)

(credit to this answer)

a=x[:]
b=[*x]
c=x*1

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Slicing tricks for hard-wired lists of strings

Warning: Python is the language which worships readability above all else; so coding this way is a Mortal Sin.

This sort of thing comes up a lot; such as here where for a given digit in 0<=d<=9, we can get the 7-bit segment b value as a hex string from the list

b=['7e','30','6d','79','33','5b','5f','70','7f','7b'][d]

If the length of such a list is more than just a few elements, you're usually better off at least using split because you can replace a bunch of "','"s with a single character " " as delimiter. E.g.:

b='7e 30 6d 79 33 5b 5f 70 7f 7b'.split()[d]

This can be used for almost any list of strings (possibly at a small additional cost using a delimiter such as ",").

But if in addition, the strings we are selecting for all have the same length k (k==2 in our example), then with the magic of Python slicing, we can write the above as:

b='7e306d79335b5f707f7b'[2*d:][:2]

which saves a lot of bytes because we don't need character delimiters at all. But in that case, usually even shorter would be:

b='7367355777e0d93bf0fb'[d::10]
\$\endgroup\$
3
\$\begingroup\$

Unpacking in Python3

If you only need the first few values in the array

>>> a, b, *c = [1, 2, 3, 4, 5]
>>> a
1
>>> b
2
>>> c
[3, 4, 5]

Same applies to when you need last few values

>>> *a, b, c = [1, 2, 3, 4, 5]
>>> a
[1, 2, 3]
>>> b
4
>>> c
5

Or even with the first few and last few

>>> a, *b, c = [1, 2, 3, 4, 5]
>>> a
1
>>> b
[2, 3, 4]
>>> c
5
\$\endgroup\$
1
  • 3
    \$\begingroup\$ I was experimenting with this, and I found out you can also initialise an empty array if the number of values is one less than the number of variables, such as a,*b,c=1,2 or a,*b,c="ab" \$\endgroup\$
    – Jo King
    Oct 22 '18 at 11:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.