Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write a decorator to wrap something in a context manager, that takes parameters?

I've seen How to use a context manager inside a decorator and how to pass an object created in decorator to decorated function as well as python decorators with parameters, and I'm trying to combine the two..but I'm struggling to get my head round it.

I'd much rather use the func tools @wrap decorator to do this if possible, as I know if will preserve the doc string.

What I want to do is this:

def pyro_opener(func,service,database,port,secret_key):
    def wrapper(params):
        with Pyro4.Proxy("PYRO:"+service+"@"+database+":"+port) as obj:
            obj.set_secret_key(secret_key)
            return obj.func(params)
    return wrapper


@pyro_opener(output_service, employee_db,port=9876,secret_key="h3llow0rld")
def get_employee_names(salary):
    return obj.return_employee_names(salary)  # obj is clearly not in scope here
                                              # but what else can I do?


get_employee_names(25000)

>>>> Bob, Jane, Mary

I don't think this works this way, the method return_employee_names is on the service at the other end of the connection. Should I just return the function call? If so how do I pass the params in then?

like image 382
AncientSwordRage Avatar asked May 27 '15 17:05

AncientSwordRage


People also ask

What is wrapper in decorator?

Wrappers around the functions are also knows as decorators which are a very powerful and useful tool in Python since it allows programmers to modify the behavior of function or class. Decorators allow us to wrap another function in order to extend the behavior of the wrapped function, without permanently modifying it.

Which of the following module helps in creating a context manager using decorator context manager?

contextmanager() uses ContextDecorator so the context managers it creates can be used as decorators as well as in with statements.

What is the correct syntax for using a decorator?

Decorators use a special syntax in JavaScript, whereby they are prefixed with an @ symbol and placed immediately before the code being decorated.

Why do we need wrapper function in decorators?

The purpose of having a wrapper function is that a function decorator receives a function object to decorate, and it must return the decorated function.


1 Answers

You'd pass in the object bound to with with ... as to the wrapped function; the function would have to accept such an argument.

This is analogous to how methods work; they are just functions with an extra first argument (self) passed in:

def pyro_opener(service, database, port, secret_key):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kw):
            with Pyro4.Proxy("PYRO:{}@{}:{}".format(service, database, port)) as obj:
                obj.set_secret_key(secret_key)
                return func(obj, *args, **kw)
        return wrapper
    retutrn decorator

@pyro_opener(output_service, employee_db, port=9876, secret_key="h3llow0rld")
def get_employee_names(obj, salary):
    return obj.return_employee_names(salary)

Note that I had to add another nested function in the pyro_opener() to make it a proper decorator factory.

like image 115
Martijn Pieters Avatar answered Oct 13 '22 00:10

Martijn Pieters