Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use context manager as a function

Tags:

python

I'd like to make a function which would also act as context manager if called with with statement. Example usage would be:

# Use as function    
set_active_language("en")

# Use as context manager
with set_active_language("en"):
    ...

This is very similar to how the standard function open is used.

Here's the solution I came up with:

active_language = None  # global variable to store active language

class set_active_language(object):

    def __init__(self, language):
        global active_language
        self.previous_language = active_language
        active_language = language

    def __enter__(self):
        pass

    def __exit__(self, *args):
        global active_language
        active_language = self.previous_language

This code is not thread-safe, but this is not related to the problem.

What I don't like about this solution is that class constructor pretends to be a simple function and is used only for its side effects.

Is there a better way to do this?

Note that I haven't tested this solution.

Update: the reason why I don't want to split function and context manager into separate entities is is naming. The function and the context manager do the same thing, basically, so it seems reasonable to use one name for both. Naming the context processor would be problematic if I wanted to keep it separate. What should it be? active_language? This name may (and will) collide with variable name. override_active_language might work, though.

like image 440
Andrey Fedoseev Avatar asked Oct 05 '16 22:10

Andrey Fedoseev


1 Answers

Technically no, you cannot do this. But you can fake it well enough that people (who didn't overthink it) wouldn't notice.

def set_active_language(language):
    global active_language
    previous_language = active_language
    active_language = language

    class ActiveScope(object):
        def __enter__(self):
            pass

        def __exit__(self, *args):
            global active_language
            active_language = previous_language

    return ActiveScope()

When used as a function the ActiveScope class is just a slightly wasteful no-op.

like image 170
cjhanks Avatar answered Oct 05 '22 01:10

cjhanks