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?
-
1What does context manager will exactly do? How you'll access it? If you gonna just change globals it might be not good with multiple threadsRiaD– RiaD2020年12月03日 15:34:07 +00:00Commented Dec 3, 2020 at 15:34
3 Answers 3
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).
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.
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
-
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 callingstore()
necessarily.Mehraban– Mehraban2021年01月19日 13:49:27 +00:00Commented Jan 19, 2021 at 13:49