1

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?

3
  • 1
    "Only the organization of the text has changed, but it has affected the behavior. " Well, no, the entire semantics have changed... In any case, there is no built-in functionality to do this. Commented Jul 24, 2019 at 16:42
  • The problem is you're using global variables. Try to avoid doing that for all the well-know reasons. Commented Jul 24, 2019 at 17:11
  • Yes, global variables should be avoided. However, the same problem occurs in other scopes, like moving a nested function from one function to another. Commented Jul 24, 2019 at 18:15

1 Answer 1

1

I found the pure-func package on PyPi just as I finished writing this question up. I still think the question is worth asking, but I wanted to share this find as well.

Sign up to request clarification or add additional context in comments.

2 Comments

it seems like you want more of a static analysis tool, though, right? from what I can grok, that package checks purity at runtime.
That's just one possibility. Convenience is the most important aspect, because ultimately I just want to get the refactoring done.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.