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

Oh, I can see a whole set of questions like this one coming for each language...
– R. Martinho FernandesJan 28 '11 at 4:26

4

@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.
– marcogJan 28 '11 at 12:28

46

Love the question but I have to keep telling myself "this is ONLY for fun NOT for production code"
– Greg GuidaDec 21 '11 at 0:08

2

Shouldn't this question be a community wiki post?
– dorukayhanMay 29 '16 at 15:35

3

@dorukayhan Nope; it's a valid code-golftips 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).
– Erik the OutgolferSep 9 '16 at 14:48

These aren't exactly the same. The first one evaluates only the expression that is returned while the second one always evaluates them both. These ones do short-circuit: a if a<b else b and a<b and a or b
– marinusMay 3 '11 at 11:34

r=range and the other two r's are 9 characters; using range twice is 10 characters. Not a huge saving in this example but all it would take is one more use of range to see a significant saving.
– FrankAug 25 '16 at 19:52

9

@Frank The additional newline is another character.
– L3viathanNov 14 '16 at 20:45

Note that the first example is exactly the same length as for x in ("foo","bar","baz"): print x
– Mateen UlhaqJun 2 '17 at 7:21

1

@MateenUlhaq, That's just an example of how the different values of 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.
– gnibblerJun 2 '17 at 7:31

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 nth table entry. We access the nth 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

Collapse two numerical loops into one

Say you're iterating over the cells of an m*n grid. Instead of two nested for loops, one for the row and one of the columns, it's usually shorter to use 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 faster to assign their values i=k/n, j=k%n inside the loop.

In some cases, 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'
– Aaron3468Mar 16 at 3:24

@proudhaskeller I think the point of the line you removed was that "In addition to the obvious character savings you get because [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".
– undergroundmonorailAug 18 '14 at 17:13

If this is being used in a list comprehension, this can be used to loop with a variable. Useful in lambdas. What I'm saying is instead of for i in[1]*n:a=(expression);, you do for a in[expression]*n:
– ArtyerJun 4 '17 at 18:41

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:

if you need both cases, the shortest way I know is filter(str.isalpha,map(chr,range(256))). It's just barely shorter than s=map(chr,range(256));s+=map(str.lower,s)
– quintopiaNov 18 '15 at 3:40

@quintopia: Why 256 instead of 122 (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))).)
– Tim PederickDec 21 '15 at 5:36

1

If you going to be unfair and use range as 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
– JBernardoDec 21 '17 at 20:26

Exploit Python 2 string representations

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.

Concatenating single digits string slicing is also effective in Python 3, albeit less so: 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!
– Tim PederickDec 21 '15 at 2:08

or c=lambda a:a+[-5,10][a<3]. the and/or trick is more useful when you are depending on the shortcircuit behaviour
– gnibblerFeb 3 '11 at 13:23

3

In your function, 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)
– JeromeJSep 14 '15 at 8:15

In many (but not all) cases, return 0 or return 1 is equivalent to return False or return True.
– undergroundmonorailApr 16 '14 at 8:30

5

(1) only works if you already know the number is negative, in which case you can save a further 2 characters by simply using a minus sign. -x rather than x*-1. --8.32 rather than -8.32*-1. Or just 8.32...
– trichoplaxApr 20 '14 at 22:56

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.

You can make the second example into for i in[0]*x:s+=input() to save another space. Also, you can remove the space between the exec and the first quotation mark to get exec's+=input();'*x
– Justin PeelApr 19 '11 at 6:12

shouldn't the second line be: for i in[0]*x:s+=input()
– micsthepickAug 5 '15 at 7:47

Your Answer

If this is an answer to a challenge…

…Be sure to follow the challenge specification. However, please refrain from exploiting obvious loopholes. Answers abusing any of the standard loopholes are considered invalid. If you think a specification is unclear or underspecified, comment on the question instead.

…Try to optimize your score. For instance, answers to code-golf challenges should attempt to be as short as possible. You can always include a readable version of the code in addition to the competitive one.
Explanations of your answer make it more interesting to read and are very much encouraged.

…Include a short header which indicates the language(s) of your code and its score, as defined by the challenge.

More generally…

…Please make sure to answer the question and provide sufficient detail.

…Avoid asking for help, clarification or responding to other answers (use comments instead).