3

We have an input flag in our API which indicates whether we should keep the mid level resources involved in fulfilling current request or not. I've decided to use some context managers at interface level instead of passing the some store flag around the code.

For example, we should decide whether to store requests images permanently or just temporarily and I implemented a context manager in our storage module to handle this instead of passing a parameter to function calls.

It is irrelevant to most of the code, whether we want to keep that stuff or not; It doesn't affect the logic. But modules involved this flag, are inner most function calls in stack trace and for a flag to reach them, We should pass it around and around, increasing number of function/method parameters to just pass them to the next function/method.

Is this a good/common practice for context managers? Have you ever seen something like this? If this is some sort of anti pattern what do you suggest?

1
  • 1
    What does context manager will exactly do? How you'll access it? If you gonna just change globals it might be not good with multiple threads
    – RiaD
    Dec 3, 2020 at 15:34

3 Answers 3

4

This PyCon 2012 talk summarized several patterns that you'd consider context manager:

  • Open - Close
  • Lock - Release
  • Change - Reset
  • Enter - Exit
  • Start - Stop
  • Error handling

Maybe your use case slightly falls into change-reset category above, so it is fine by creating the context that assigns the flag variable inside, and it looks like with store_image(*args): (even if reducing only one parameter in the function could be trivial).

2

I'd say your example is fine. You hide the tedious part of passing arguments around the code by providing strict borders with the context manager. You are managing the surrounding context! It is a relatively safe, enough explicit, and pythonic way to introduce the state into your application.

0

Remember that one main function of context managers is to guarantee that __exit__() is invoked.

It's kind of a syntactic sugar around

try:
    something = SomeClass()
    something.__enter__()
finally:
    something.__exit__()

So if there's a chance that your code by design won't call the store() method, say when aborting a transaction, you should NOT use context managers.

Fun fact: The finally part will still be executed even if you return from out of the try block. Try this code:

def fun():
    try:
        print("I'm inside!")
        return 42
    finally:
        print("I'm final!")
    print("I'm outside!")

print(fun())

# You'll get:
# I'm inside!
# I'm final!
# 42
1
  • In case of omitting the store, one can manage that with error handling in context managers. To guarantee the __exit__ is called, does not mean calling store() necessarily.
    – Mehraban
    Jan 19, 2021 at 13:49

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.