Code Golf Techniques — Deep Dive
The competitive landscape
Python consistently ranks in the top five languages on code-golf sites. Its concise syntax, rich standard library, and duck typing make it naturally terse. However, dedicated golf languages like Jelly, 05AB1E, and Pyth are even shorter for most problems. Python golfers compete not for absolute shortest solutions but for the shortest within general-purpose languages — and for the elegance of exploiting a well-known language in unexpected ways.
Advanced byte-saving techniques
Import minimisation
Standard library imports cost bytes. Strategies to minimise them:
# Full import (17 bytes)
from math import*
# Access without import via __import__ (saves when you need one function)
__import__('math').gcd(12,8)
# But for multiple uses, the import statement wins
For re, a common pattern:
# 16 bytes
import re;re.sub
# 15 bytes using __import__
__import__('re').sub
# But if you use re.sub multiple times:
import re;s=re.sub # assign to short name
exec with string compression
For repetitive output, compress the program as a string:
exec(bytes(range(33,127)).decode()) # execute ASCII art as code
More practically, use exec to avoid def/return:
# Instead of:
def f(n):
for i in range(n):print(i)
f(10)
# Use:
exec("for i in range(10):print(i)")
Recursive lambda with default arguments
Python lambdas cannot use statements, but recursion via default-argument binding is a classic trick:
# Factorial in 28 bytes
f=lambda n:n<2or n*f(n-1)
For problems requiring a helper variable:
# Fibonacci sequence
f=lambda n,a=0,b=1:n and f(n-1,b,a+b)or a
The default arguments a=0,b=1 serve as state accumulators. Each recursive call shifts the window.
Abusing or and and as control flow
Python’s short-circuit evaluation turns boolean operators into conditional expressions:
# Instead of: x if condition else y
# Use (when x is truthy):
condition and x or y
# Print only if condition:
condition and print("yes")
Caveat: this fails when x is falsy (0, empty string). The ternary x if c else y is safer but costs more characters.
Integer-to-string and back
# Convert list of digits to number
int("".join(map(str,digits)))
# Shorter:
int(''.join(str(d)for d in digits)) # actually longer
# Shortest for known range:
eval(''.join(map(str,digits))) # same length but works for expressions too
For base conversion:
# Decimal to binary string
bin(42) # '0b101010'
f"{42:b}" # '101010' — no prefix, 7 bytes shorter in context
itertools golf
itertools functions replace verbose loops:
from itertools import*
# All permutations
[*permutations("abc")]
# Cartesian product (replaces nested loops)
[*product(range(3),repeat=2)]
# Accumulate (running sum without a loop)
[*accumulate(range(10))]
The from itertools import* costs 22 bytes. It pays off when you use two or more functions from the module.
Encoding and output tricks
chr and ord manipulation
Building strings character by character is sometimes shorter than string literals:
# "Hello" is 7 bytes (with quotes)
# chr-based might be longer... but for non-printable or repetitive patterns:
''.join(chr(i)for i in[72,101,108,108,111])
More useful: generate alphabets without typing them:
# All lowercase letters
[chr(i)for i in range(97,123)]
# Shorter with map:
[*map(chr,range(97,123))]
print with sep and end
# Print space-separated list
print(*[1,2,3]) # "1 2 3"
# Print with custom separator
print(*[1,2,3],sep='\n') # one per line
# Suppress newline
print(x,end='')
Starred unpacking in print
# Instead of:
for x in range(5):print(x)
# Use:
print(*range(5),sep='\n')
This replaces a two-line loop with a single expression.
Algorithmic tricks
Mathematical replacements
Many conditional patterns have mathematical equivalents:
# Absolute value without abs()
(x,-x)[x<0] # but abs(x) is only 6 bytes — not always a win
# Clamp to non-negative
x*(x>0)
# Sign function
(x>0)-(x<0)
# Ceiling division
-(-a//b)
String multiplication for patterns
# Triangle of stars
for i in range(1,6):print("*"*i)
# Checkerboard
for i in range(8):print(("# "*8)[i%2:16])
Set operations for uniqueness
# Unique elements preserving order
dict.fromkeys(lst) # Python 3.7+ dicts preserve insertion order
# Shorter than list(set(lst)) when order matters
Platform-specific tricks
Reading input efficiently
# Multiple lines of input
import sys;L=sys.stdin.read().split('\n')
# Shorter:
L=open(0).read().split('\n')
# Even shorter for line-by-line:
L=[*open(0)]
open(0) opens file descriptor 0 (stdin). This is the shortest way to read all input in Python golf.
Recursion limit
For recursive solutions on large inputs:
import sys;sys.setrecursionlimit(9**9)
This costs 41 bytes. For problems where iteration is possible, it is usually shorter to avoid recursion entirely.
Competitive strategy
Step 1: Solve correctly first
Write a clear, correct solution. Count its bytes.
Step 2: Identify the expensive parts
What costs the most bytes? A long import? A multi-line loop? A verbose conditional? Attack the biggest cost first.
Step 3: Look for built-in replacements
Python’s sum, min, max, sorted, zip, map, filter, any, all, enumerate — each replaces a loop pattern in fewer bytes.
Step 4: Flatten control flow
Replace if/elif/else chains with dictionary lookups, conditional expressions, or arithmetic. Replace for loops with map or comprehensions. Replace while loops with recursive lambdas.
Step 5: Micro-optimise
- Remove spaces around operators (Python allows
1+2not1 + 2in golf context) - Use
;to merge lines - Replace
True/Falsewith1/0 - Replace
not xwith1-xwhen x is boolean - Use
~xfor-(x+1)in indexing:a[~0]isa[-1]
Tradeoffs and ethics
| Benefit | Cost |
|---|---|
| Deep language mastery | Unreadable output |
| Creative problem-solving practice | Bad habits if applied to production |
| Community and competition | Time-consuming for diminishing returns |
| Exposure to obscure stdlib functions | Version-dependent tricks may break |
Code golf explicitly violates every clean-code principle. That is the point. The skill is knowing when to golf and when to write for humans. The best golfers are often excellent production programmers because they understand the language at a level most developers never reach.
One thing to remember: The shortest Python solution to a problem reveals the language’s hidden expressiveness. Studying golf solutions — even if you never compete — teaches you corners of Python that years of normal use might never expose.
See Also
- Ci Cd Why big apps can ship updates every day without turning your phone into a glitchy mess — CI/CD is the behind-the-scenes quality gate and delivery truck.
- Containerization Why does software that works on your computer break on everyone else's? Containers fix that — and they're why Netflix can deploy 100 updates a day without the site going down.
- Python 310 New Features Python 3.10 gave programmers a shape-sorting machine, friendlier error messages, and cleaner ways to say 'this or that' in type hints.
- Python 311 New Features Python 3.11 made everything faster, error messages smarter, and let you catch several mistakes at once instead of stopping at the first one.
- Python 312 New Features Python 3.12 made type hints shorter, f-strings more powerful, and started preparing Python's engine for a world without the GIL.