244
\$\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\$
  • 26
    \$\begingroup\$ Oh, I can see a whole set of questions like this one coming for each language... \$\endgroup\$ – R. Martinho Fernandes Jan 28 '11 at 4:26
  • 4
    \$\begingroup\$ @Marthinho I agree. Just started a C++ equivalent. I don't think its a bad thing though, as long as we don't see the same answers re-posted across many of these question types. \$\endgroup\$ – marcog Jan 28 '11 at 12:28
  • 48
    \$\begingroup\$ Love the question but I have to keep telling myself "this is ONLY for fun NOT for production code" \$\endgroup\$ – Greg Guida Dec 21 '11 at 0:08
  • 2
    \$\begingroup\$ Shouldn't this question be a community wiki post? \$\endgroup\$ – dorukayhan May 29 '16 at 15:35
  • 3
    \$\begingroup\$ @dorukayhan Nope; it's a valid code-golf tips question, asking for tips on shortening python code for CG'ing purposes. Such questions are perfectly valid for the site, and none of these tags explicitly says that the question should be CW'd, unlike SO, which required CG challenges to be CW'd. Also, writing a good answer, and finding such tips always deserves something, that is taken away if the question is community wiki (rep). \$\endgroup\$ – Erik the Outgolfer Sep 9 '16 at 14:48

139 Answers 139

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\$

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\$
3
\$\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\$
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\$
  • \$\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
  • \$\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\$

Take multi-line input

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.

\$\endgroup\$
  • \$\begingroup\$ 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\$ – Mego Nov 30 '15 at 3:15
  • \$\begingroup\$ Is shorter than what? \$\endgroup\$ – J Atkin Nov 30 '15 at 3:33
  • \$\begingroup\$ Than what you have posted, because it has an extraneous space. \$\endgroup\$ – Mego Nov 30 '15 at 3:34
  • \$\begingroup\$ Oh, I see. I assume the reader would remove the space though. I will edit it out now. \$\endgroup\$ – J Atkin Nov 30 '15 at 3:38
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\$
  • \$\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\$

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\$
  • 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\$

Use Splat (*) to pass a bunch of single character strings into a function

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

\$\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\$
  • 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
2
\$\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\$
  • 4
    \$\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\$ – user202729 Jul 5 '18 at 9:34
2
\$\begingroup\$

Run your code through an space-remover, like this one:

#Pygolfer
a=raw_input()
for i in [i for i in range(len(a)) if a[i]==" "]:
    try:b=a[:i]+a[i+1:];eval(b);a=b;print a
    except:pass

(This just tries to remove the spaces one by one, and try if the code still works. Please still do check your code manually.)

Manual things to do: print'string' works.

[str(i)for i in(1,2,3,4)] works.

etc.

\$\endgroup\$
2
\$\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\$
  • 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\$ – Esolanging Fruit Jun 5 '17 at 0:59
2
\$\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\$
  • \$\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
2
\$\begingroup\$

Try a lambda expression

By default, submissions may be functions and functions may be anonymous. A lambda expression is often the shortest framework for input/output. Compare:

lambda s:s+s[::-1]
def f(s):return s+s[::-1]
s=input();print s+s[::-1]

(These concatenate a string with its reverse.)

The big limitation is that the body of a lambda must be a single expression, and so cannot contain assignments. For built-ins, you can do assignments like e=enumerate outside the function body or as an optional argument.

This doesn't work for expressions in terms of the inputs. But, note that using a lambda might still be worth repeating a long expression.

lambda s:s.lower()+s.lower()[::-1]
def f(s):t=s.lower();return t+t[::-1]

The lambda is shorter even though we save a char in the named function by having it print rather than return. The break-even point for two uses is length 12.

However, if you have many assignments or complex structures like loops (that are hard to make recursive calls), you're probably be better off taking the hit and write a named function or program.

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

cmp in Python 2

Say you want to output P if x>0, N if x<0, and Z if x==0.

"ZPN"[cmp(x,0)]

Try it online

This function was removed in Python 3.0.1, although it remained in Python 3.0 by mistake.

\$\endgroup\$
  • 1
    \$\begingroup\$ Congratulations on the 100th answer to this question! \$\endgroup\$ – NinjaBearMonkey Mar 2 '16 at 20:51
2
\$\begingroup\$

Abuse of or in lambdas

I'm surprised this isn't in here yet, but if you need a multi-statement lambda, or evaluates both of its operands, as opposed to and which doesn't evaluate the second one if the first one is not True. For instance, a contrived example, to print the characters in a string one by one with an interval:

list(
    map(
        (lambda i: 
            sleep(.06) or print(i) or print(ord(i)) # all of these get executed
        ), 
        "compiling... "
    )
)

In this case it isn't shorter, but I've found it to be, sometimes.

\$\endgroup\$
  • \$\begingroup\$ Related \$\endgroup\$ – Sp3000 Mar 4 '16 at 3:21
  • \$\begingroup\$ @Sp3000 *sighs* I tried searching this question for or, lambda, evaluation etc but didn't see that \$\endgroup\$ – cat Mar 4 '16 at 3:24
  • \$\begingroup\$ lambda i:[sleep(.06),print(i),print(ord(i))] \$\endgroup\$ – user202729 Jul 5 '18 at 9:37
2
\$\begingroup\$

Omit needless spaces

Python tokens only need to separated by a space for

  • A letter followed by a letter
  • A letter followed by a digit

In all other cases, the space can be omitted (with a few exceptions). Here's a table.

  L D S
 +-----
L|s s n
D|n - n
S|n n n    

First token is row, second token is column
L: Letter
D: Digit
S: Symbol

s: space
n: no space
-: never happens (except multidigit numbers)

Examples

Letter followed by letter: Space

not b
for x in l:
lambda x:
def f(s):
x in b"abc"

Letter followed by digit: Space

x or 3
while 2<x:

Letter followed by symbol: No space

c<d
if~x:
x and-y
lambda(a,b):
print"yes"
return[x,y,z]

Digit followed by letter: No space

x+1if x>=0else 2
0in l

(Some versions of Python 2 will fail on a digit followed by else or or.)

Digit followed by digit: Never occurs

Consecutive digits make a multidigit number. I am not aware of any situation where two digits would be separated by a space.

Digit followed by symbol: No space

3<x
12+n
l=0,1,2

A space is needed for 1 .__add__ and other built-ins of integers, since otherwise the 1. is parsed as a float.

Symbol followed by letter: No space

~m
2876<<x&1
"()"in s

Symbol followed by digit: No space

-1
x!=2

Symbol followed by symbol: No space

x*(a+b)%~-y
t**=.5
{1:2,3:4}.get()
"% 10s"%"|"
\$\endgroup\$
  • \$\begingroup\$ In general, you can't have a letter after a digit if it confuses the lexer. A digit followed by e is expected to be a float literal, so something like 1else wouldn't work for versions of python that support exponents in the literal. Similarly, as 0o is the prefix of an octal literal, o can follow any digit but 0. For the complete lexical rules, refer to docs.python.org/2/reference/lexical_analysis.html \$\endgroup\$ – xsot Aug 1 '16 at 5:20
  • \$\begingroup\$ @xsot Do you know what versions of Python will parse this way? I remember a comment thread on this, but I can't find it. \$\endgroup\$ – xnor Aug 1 '16 at 5:51
  • \$\begingroup\$ I've always assumed these rules so I'm not sure which versions of python deviate from them. Possibly the older ones, if any. \$\endgroup\$ – xsot Aug 1 '16 at 6:12
  • \$\begingroup\$ @xsot It works on 2.7.10 but fails on Anachy's 2.7.2. \$\endgroup\$ – xnor Aug 1 '16 at 6:28
2
\$\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\$
  • \$\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
2
\$\begingroup\$

Booleans are integers, too!

assert True == 1
assert False == 0
assert 2 * True == 2
assert 3 * False == 0
assert (2>1)+(1<2) == 2

If you have a statement like [a,a+x][c] (where c is some boolean expression), you can do a+x*c instead and save a few bytes. Doing arithmetic with booleans can save you lots of bytes!

\$\endgroup\$
2
\$\begingroup\$

If you're drawing, for colors, instead of typing:

'#000' for black you can just use 0 (no apostrophes)
'#fff' for white you can simply use ~0 (no apostrophes)
'#f00' for red you can just use 'red'


Example of white being used with ~0

from PIL.ImageDraw import*
i=Image.new('RGB',(25,18),'#d72828')
Draw(i).rectangle((1,1,23,16),'#0048e0',~0)
i.show()
\$\endgroup\$
  • 2
    \$\begingroup\$ 255 is even shorter than 'red'. Some more ideas: ~255 is '#0ff' (cyan). 1<<7 is #800000 (half-brightness red); similarly 1<<15 and 1<<23 are half-brightness green and blue. \$\endgroup\$ – Lynn Jan 3 '18 at 19:10
2
\$\begingroup\$

Rename everything

Here's a little Python 2 snippet that takes a module and a string, and renames every function in that module whose name is longer than 2 characters to a single character with the provided string prefixed. If you're writing a VERY LONG python program that uses many library or builtin functions (and if you manage to golf this snippet better than I have), it has the potential to save quite a few characters. On short programs or programs that use few functions, it will be useless. Since dir() sorts the names in a module, this will always provide the same names to the same functions, and you can use globals() to inspect which names it has given to which functions.

import string
def _(x,y):
 for c,f in zip(string.letters,[x.__dict__[q]for q in dir(x)if q in x.__dict__ and(len(q)>2)*type(x.__dict__[q]).__name__.find('eth')>0]):globals()[y+c]=f

You can use it to rename all the string and builtin functions like so:

_(str,'s')
_(__builtins__,'')

And then see what you actually ended up naming them like so:

for k in sorted(globals().keys(),key=lambda x:`len(x)`+x):print k,globals()[k]

If you only want to rename the builtin functions, it's best not to define the function and just use the body directly:

import string
b=__builtins__
for c,f in zip(string.letters,[b.__dict__[q]for q in dir(b)if(len(q)>2)*type(x.__dict__[q]).__name__.find('eth')>0]):globals()[c]=f
\$\endgroup\$
2
\$\begingroup\$

Pathlib from shorter files manipulations:

# get current dir, go up one dir, go down one dir, list all "py" files
# and get the whole file bytes

import os.path as p
import glob

d = p.join(p.dirname(p.abspath(__file__))), 'foo', '*.py')
for x in glob.glob(d):
    with open(x, 'rb') as f:
        do_stuff(f)

Becomes:

import pathlib as p

d = p.Path(__file__).absolute().parent / 'foo'
for f in d.glob('*.py'):
    do_stuff(f.read_bytes())
\$\endgroup\$
2
\$\begingroup\$

List all substrings

You can generate the contiguous substrings of a string s with a recursive function (Python 3 for [*s]).

f=lambda s:[*s]and[s]+f(s[1:])+f(s[:-1])

This will repeat substrings multiple times, but can be made a set to avoid repeats.

f=lambda s:{*s}and{s}|f(s[1:])|f(s[:-1])
\$\endgroup\$
2
\$\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\$
2
\$\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\$
2
\$\begingroup\$

Python 2 and 3 differences

Recent challange pushed me to search for differences in two major versions of python. More precisely - same code, that returns different results in different versions. This might be helpful in other polyglot challenges.

1) Strings and bytes comparisson

  • Python 2: '' == b''
  • Python 3: '' != b''

2) Rounding (Luis Mendo answer)

  • Python 2: round(1*0.5) = 1.0
  • Python 3: round(1*0.5) = 0

3) Division (Jonathan Allan answer)

  • Python 2: 10/11 = 0
  • Python 3: 10/11 = 0.9090909090909091

4) Suggestions?

\$\endgroup\$
  • 1
    \$\begingroup\$ comparisson, challange \$\endgroup\$ – Jonathan Frech Aug 28 '18 at 20:11

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.