I'm really confused as to how this works: at least if I understand what you're saying correctly, that certainly would break the principle of least astonishment. Is there a more thorough explanation of the topic that I could look through?
Yes. As an amateur language (lisp-ish) designer myself I was curious. The explanation is as follows (as far as I can tell from the mess that is the reference implementation for 2.3):
Python implements variables as dictionaries. Each scope gets a new dictionary created. When encountering a reference to a variable that must be read the engine traverses the stack upwards until it finds the variable name in a dictionary. If it reaches toplevel without finding a name an exception is thrown.
When encountering a reference to a variable that must be written the engine only searches up to the nearest stack pointer, at which point if the variable is not found it is then created and assigned. Hence the reason swapping around the LHS and the RHS in an assignment changes the scope of those variables, which (usually) loses data if the variable exists in a higher scope. This is the reason for using a global keyword when you want to write a variable but not when you want to read it - the global keyword was a hack around the dictionary implementation. The dictionary may be gone but the hack remains.
My informal discussions with the python community results in "this is pythonic - and besides, if you forget the global keyword you deserve to lose data silently" (you can search stack overflow for this exchange). Python really is the only language that has these (and other) warts. Unfortunately, because I've maintained a ton of python in the past I've run into almost all the gotcha's - it has more than C :-(, which is a pity as it might have been a really great language if only a little language design went into it rather than (like PHP) it having evolved from "runtime config management for C".