I sometimes run into a scenario in Python where I'm moving a block of code around (a function typically), and due to Python's scoping rules, the behavior of the function changes because the environment of the function changes. A contrived example:
text = "beef"
def f():
text = "foo"
def g(s):
print(text + s)
g("bar")
prints "foobar". When refactored, this becomes:
text = "beef"
def g(s):
print(text + s)
def f():
text = "foo"
g("bar")
which prints "beefbar." Only the organization of the text has changed, but it has affected the behavior. Now, I'm not saying that this is a bad thing. This is the way Python is meant to work. The issue appears when functions f, and g, and the global scope (or some other scope) become more complex and contain more variables. Ensuring that captured values are unchanged becomes a tedious and error-prone process because every symbol in the code being moved must be evaluated manually. Despite my best efforts, I find that sometimes a bug creeps in during refactoring because it's easy to miss one. Is there some (Pythonic) way that I can reduce the occurrence of these mistakes?
To offer an idea, if I could imagine a convenient construct of my choice, it might look something like:
def g(s):
ignore_values_from_outer_scopes()
print(text + s)
or reworded, perhaps:
def pure g(s):
print(text + s)
The interpreter/compiler would complain that 'text' is not defined. I would drop in this bit when I wanted to move a function, and at the very least it would let me know that I did something wrong.
Follow that by:
def pure g(s):
nonlocal text
print(text + s)
and I can take one variable at a time until no error occurs. Once that's done, I can remove the "pure" and "nonlocal" parts, and I know that the behavior will remain unchanged.
Anyway, what's a supported method of error-resistant function moves?