Whitespace

They'll tell you I'm insane, but I've got a blank space, baby, and I'll write your name.

You've probably heard that Python has significant whitespace, but whitespace has special significance to any esoteric pythonista.

Indentation

Unlike many programmers, Python won't fight you about whether you use tabs or spaces. If you replace all of the spaces and tabs in a Python file with each other, your code should still run. Using · for space and for tab, the following is valid Python:

if↹True:
·print(end="Hello")
·print("",↹"World")

You can combine both in one indentation level, if you're careful to always use the same mix of spaces and tabs:

if True:
↹·↹·↹a = 1
↹·↹·↹if a < 10:
↹·↹·↹···a = 10
↹·↹·↹···print(a)

However, the following will not work, because the order of the tab and space are different:

if True:
↹·a = 1
·↹b = 2 # IndentationError: unindent does not match any outer indentation level

Separators

Python is lax with whitespace, letting you put it in strange places and leave it out in stranger ones. Whenever Python thinks it can unambiguously figure out where a token ends, you don't need whitespace following. For instance:

print(arg1,arg2,kwarg=kwarg)
for(a)in[1]:b=a
print(1and 2in[]) #keywords and variables can't begin with digits
foo=lambda*args:lambda arg,/:args+[arg]

This is a godsend for golfing. Never put spaces around your operators, and try to manoeuvre your terms so that any keywords are right next to punctuation. For instance, checking if a number is odd, if 1-i%2: can be if~i%2: instead.

Numbers

Spaces can't go in numeric literals. Python views 1.__eq__ as (1.) __eq__ or (1.0) __eq__, which is a syntax error. You can fix it with a space: 1 .__eq__ is the dunder method for == 1 because 1 . isn't a valid float literal.

If you want to put a space in a long number for readability, you're reading the wrong guide. However, _ can be used instead, meaning 1_000_000 is a valid number.

Oddities

Numbers can be extremely misleading: [0x_for x in (1, 2, 3)] evaluates to [15]. It startles enough people that Python 3.10 has deprecated this kind of syntax misuse.

Expand for an explanation. This means [0xF or (x in (1, 2, 3))]. 0x_f is a hexadecimal integer literal, and F in hex equals 15 as a decimal. o isn't a hex digit, so Python doesn't lump or into the literal. (15 is truthy, so using Boolean short circuiting, the x in (1, 2, 3) is never executed. That means x being undefined causes no error. The 15 is in a list literal rather than a list comprehension.)

Quasi-operators

Whitespace can be a very confusing tool for things other than numbers. For instance, the so called 'pistol operator' or 'comma assignment' —

numbers = [42]
only_element ,= numbers
print(only_element) # 42

— is better rendered as only_element, = numbers, (only_element,) = numbers, or equivalently [only_element] = numbers. The last makes it clear that the pistol operator uses iterable unpacking and irresponsible whitespace to extract the only element of a list. The 'space-invader increment operator' x -=- 1 is in a similar vein (parsing as x -= -1).

Semicolons

Semicolons can be useful to avoid needing to type indentation characters; they act as a replacement newline for separating statements because Python and C are basically the same language.

while 2+2!=5: print("Try again."); break;

Both statements are part of the loop.

Practicalities

—Whitespace is great, but what does it mean for golfing?

I'm glad you asked. If you have only one indentation level, put it all on the same line. for x in y:a;b;c

If you have more than one of them, the outer indentation levels will need their own line. You don't need to use four spaces for each indent. A single space (or tab, you heathen!) will suffice.

if-1>a:
 a
 b
 while c:
  try:d
  except:0