Wiki: Python

A 2:1 packer

This is Python's fabled 2:1 packer, for your convenience. For chars scoring, it can reduce code by a factor of two.



Note: the overhead is 25 characters so your uncompressed code must be over 50 characters to get a benefit.



Note: the code size must be divisible by 2 for the compressor to work. If not, adding a trailing space should suffice.


A 3:1 packer

There also exists a 3:1 packer, but it only works with bytes above ASCII character 31.



Note: the overhead is 49 characters so your uncompressed code must be over 73 characters to get a benefit over unpacked code and over 144 characters to get a benefit over the 2:1 packer (assuming a compression ratio of strictly 3:1).

exec(bytes(ord(c)%i+32for c in'...'for i in b'efg'))


def mulinv(a, b):
	if b == 1:
		return 1
	b0, x0, x1 = b, 0, 1
	while a > 1:
		q = a // b
		a, b = b, a % b
		x0, x1 = x1 - q * x0, x0
	if x1 < 0:
		x1 += b0
	return x1

def crt(a, n):
	s, p = 0, 1
	for x in n:
		p *= x
	for x, y in zip(a, n):
		q = p // y
		s += q * x * mulinv(q, y)
	return s % p

code = '''CODE'''

compressed = ''
for i in range(0, len(code), 3):
	a = [ord(c) - 32 for c in code[i:i+3]]
	compressed += chr(crt(a, [101, 102, 103]))


Boolean access

Instead of:

a if condition else b



Only works if a and b can both be safely evaluated, regardless of which one is picked.

Shorter if...else

As seen above, [b,a][condition] may be used instead of an if...else, but only if a and b cause no side effects. A laxer alternative is

condition and a or b

It saves one byte, but has the restriction that a must be truthy. There is also

a*condition or b

but with this one, a must be truthy, in addition to not causing any side effects.

Chained comparison

Use comparison chaining to save bytes on and:

0<a and a<5 and 0<b and b<5
# vs
0<a<5 and 0<b<5
# vs

You can chain in as well. This is less useful, but nice to know:

a in b and b<c
# vs
a in b<c

The next tip on short circuiting also utilizes comparison chaining.

Short circuiting ==

if f(x)>1:print(x)

can be rewritten implementing the short circuit:


Multiple assignment

If you need to assign multiple variables to the same value, it's better to combine them into one statement:

# vs

However, assigning to an object (such as a list) may result in some weird behavior, since all the variables share the same instance:

>>> [1] [1]

Walrus operator

Python 3.8 introduced assignment expressions (A.K.A. the walrus operator). Its main use in golf is to allow assigning and using a variable at the same time:

while 1:x=1;...
# vs
while x:=1:...

# vs

Using byte strings as integer lists

Python's byte strings can act like integer lists, sometimes:

# vs

This can, for example, help with iterating or indexing a list:

# Iteration
for x in 48,96,33:
for x in b'0`!':

# Indexing

Unpacking assignment

Here is a list of tricks for potentially saving bytes on variable assignment. All are based on the powerful feature of iterable unpacking:

# vs
# vs
# vs
# vs
# vs
# vs
# vs

Print list separated by \n

AFAIK, the shortest way to print a list (or any iterator) with each element on a new line is:


Some longer alternatives include:

0in map(print,L)
for x in L:print(x)

Splat on iterables

Splat makes functions like list, set, and tuple a lot shorter:

list(L)  -> [*L]
tuple(T) -> (*T,)
set(S)   -> {*S}

It saves on concatenation as well:

[1,2]+[L]+[3,4] -> [1,2,*L,3,4]
(1,2)+L+(3,4)   -> (1,2,*L,3,4)

A sys.argv trick

Some of the holes on require input through ARGV. Nine out of ten times,

for a in sys.argv[1:]:f(a)

will be the shortest option. But let's take a look at this alternative:

while 1:f(sys.argv.pop(1))

Both of these contain the same amount of bytes, except the second one is less useful as it is not stored in a variable. The advantage with the second option is that the while 1 might have room to fit a walrus operator (as discussed in this tip). Under these specific circumstances, it can usually save one byte.