There is a concise rule for Python Scope resolution, These rules are specific to variable names, not attributes. To apply these rules you need to reference it without a period:-
What is LEGB Rule:-
Local is the names assigned within a function (def or lambda), and not declared global in that function.
E, Enclosing-function locals:-
It is the local scope of any and all statically enclosing functions (def or lambda), from inner to outer.
G, Global (module):-
The names assigned at the top-level of a module file, or by executing a global statement in a def within the file.
B, Built-in (Python):-
Here the names are preassigned.
So, in your code:-
In your code, the LEGB order is as follows:-
L: local, in def spam (in code3, code 4, code5).
E: Enclosed function, any enclosing functions (if the whole example were in another def)
G: Global. Was there any x declared globally in the module (code1)?
B: Any builtin x in Python.
The function x will never be found in code2.