General tips for golfing in Python

Add a reply

Posted by lifthrasiir 1826 days ago:
After looking Ruby forum, I felt a need of similar thread for Python. :) As an example, the following is some general tips I know:

`x` can be used instead of str(x), if x is int (not long, because it follows with 'L')
use of bounded methods and aliases can shave some bytes, e.g. j=''.join; R=range
get rid of parentheses with bitwise operators. bitwise operators have lower precedences than arithmetic ones, so one can write 3+x>>2 instead of (3+x)/4
-~x and ~-x are equivalent to x+1 and x-1, but without (possible) parentheses.
zip(x, x[1:]) generates [(x[0], x[1]), (x[1], x[2]), ..., (x[-2], x[-1])], good for lookahead and/or lookbehind.
conditional expressions are extremely common. if you can avoid side effects, (x,y)[cond] will be a basic choice. if x=1 and cond>=0 then y**cond can be used. if both x and y are fixed strings with similar length and cond is 0 or 1 then (x[0]+y[0]+x[1]+y[1]+...)[cond::2] can be used. and so on...
bool can be treated as int, and vice versa (although some tips don't work for integer rather than 0 or 1)
some comparisons can be chained. e.g. a>1<b instead of a>1 and b>1
list.append(item) can be shortened with list += [item], or list += item,.
one can use unused variables to trigger exceptions and terminate the program. (stderr is ignored in codegolf)
as well as ruby, 0or 1 is valid python code. of course 0 or1 is not. (note that no spaces between 0 and or)

Obviously there could be more.
Posted by mick 1826 days ago:
These are great tips...thanks for posting them!

I only have one more to add...if you're only using a loop variable for doing something a fixed number of times, like this:


for i in range(10):do something


You can replace it with:


exec"do something\n"*10
Posted by mick 1821 days ago:
Two more tricks:

(1) If you want to put two statements on one line, separate them with ';' like this:

i+=1;j+=1

instead of

i,j=i+1,j+1

(2) If your solution needs to indent two levels deep, use a space for the first level and a tab for the second level, so that each only requires one character of indentation.
Posted by recursive 1791 days ago:
If using windows, make sure your newlines aren't more than one byte, as they are by default.
Posted by Mark Byers 1757 days ago:
Here are two more ways to read standard input that can sometimes be useful:

import os;x=os.read(0,99);....

import sys;for l in sys.stdin:....
Posted by danudey 1744 days ago:
A few other tips I found...

The best method for user input I've found is raw_input(), which returns a string. It's a lot better than importing sys or any such things, and pretty short too.

Also, to reverse a string, try string[::-1]. Very handy.
Posted by toxik 1534 days ago:
If you use raw_input more than once, it is always more efficient to alias it, r=raw_input.

The shortest way of printing out a list of strings together is print"".join(L), other ways always end up being longer.

As noted above, bools can be integers. "ab"[x>0] gives "a" if x is 0, "b" if x is above zero.

Functions with names at less than four bytes are generally not worth aliasing unless you use them *a lot.*

"%c" % (65,) is "A".

map() is very good to have.

Don't bother using semicolons, you can just use UNIX-style newlines and still maintain some code readability.

Python has very flexible tuple unpacking:

for a, (b, c) in ((1, "ab"), (2, "ba")):
....print a, b, c
1 a b
2 b a


That's about it I guess. Module imports are very rarely worth the bytes.
Posted by hallvabo 1350 days ago:
Some tricks which may come in handy:

print'%i'%d saves one byte versus print int(d).

l[x+1:x-1:-1] as substitute for x[x:x+2][::-1] when x>0.

for, while and try have an optional else-clause.

To check if all elements in a sequence evaluates to True: use all(seq).
Use any(seq) to check if at least one element evaluates to True.

hex(n), oct(n) and int('...', base) is very useful when you need to encode something.

convert = lambda number, base: ''.join(str(number/i % base) for i in (..., base**3, base*base, b,1))
will convert numbers of a known upper bound to any base.

Put generator expressions inside ''.join(...) as a replacement for loops when the loop body only contains expressions.

The operator %= is overloaded for strings: s = '%c'; s%=54; print s # prints 6

int('...') works on strings of zero-padded numerals: int('009') gives 9. Useful in conjunction with string interleaving and slicing.

'#'.join('abc') gives 'a#b#c'.

'%s' converts any type or object with str(), '%r' converts with repr().

range(1e3) is shorter than range(1000). This gives a warning, but stderr is ignored in codegolf.
Posted by hendrik 1290 days ago:
Related to one of lifthrasiir's tips I found out recently that you can combine bools with other types. Possibly not everybody is aware of this feature.

4+True => 5
4+False => 4
4*True => 4
4*False => 0
"ABC"*True => 'ABC'
"ABC"*False => ''
Posted by hallvabo 1178 days ago:
Interesting links about Python golf:

* Golfing tips from Mark Byers
* What code golfing taught lbrandy about Python
* jakevoytko's thought process on Saving Time
* André Roberge explains his winning entry in a golfing contest similar to codegolf's own Seven Segment Displays
Posted by hendrik 1137 days ago:
Interesting links about Python golf:

* Golfing tips from Mark Byers
* What code golfing taught lbrandy about Python
* jakevoytko's thought process on Saving Time
* André Roberge explains his winning entry in a golfing contest similar to codegolf's own Seven Segment Displays

As regards

import os
a=os.read(0,1e5).split()


Marks site is a little bit incorrect. The description is only true in case the lines do not contain spaces. In case the lines contain spaces you would have to write

import os
a=os.read(0,1e5).split('\n')


to achieve the same.
Posted by hallvabo 1137 days ago:
Fixed now.
Posted by stumo 1135 days ago:
Python can do functional programming, you can pass functions around like data.
For example, if you need to use int() three or more times, your program will be shorter if you do this:
>>> i=int #Note the no parentheses. Type 'int' into the shell of Python with no parentheses to see why.
>>> i('4')
4

If you need to use range() three or more times:
>>> R=range
>>> R(4)
[0, 1, 2, 3]

If you need to use L.append() 2 or more times:
>>> L=[]
>>> a=L.append
>>> a(4)
>>> L
[4]
>>>

If you need to use L.append(4) 2 or more times:
>>> L=[]
>>> a=L.append(4)
>>> a
>>> L
[4]
>>>

So if you need to type a function more than so and so times, you'll use less characters by assigning something else to be that function. You can't do Haskell-style partial functions in Python, though.
Posted by stumo 1135 days ago:
!!!
Forget the last one, about the a=L.append(x), and the subsequent dialog about partial functions. Stupid, stupid, stupid me.
The a=L.append is still true Python though.
Posted by stumo 1133 days ago:
One so simple that I forgot to mention it:
You can omit the #!/usr/bin/python at the start of the file, it's not needed here.

Add a reply