2015-05-27 7 views
8

Я видел How to use a context manager inside a decorator and how to pass an object created in decorator to decorated function, а также python decorators with parameters, и я пытаюсь совместить эти два ... но я изо всех сил пытаюсь обвести голову.Как написать декоратор, чтобы обернуть что-то в менеджер контекста, который принимает параметры?

Я бы скорее использовал инструменты func @wrap decorator, чтобы сделать это, если это возможно, так как я знаю, сохранит ли строка doc.

То, что я хочу сделать это:

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 

Я не думаю, что это работает таким образом, метод return_employee_names на службу в другом конце соединения. Должен ли я просто вернуть вызов функции? Если да, то как мне передать params тогда?

ответ

6

Вы должны передать объект, связанный с with ... as, с завернутой функцией; функция будет иметь, чтобы принять такой аргумент.

Это аналогично тому, как работают методы; они просто функции с дополнительным первым аргументом (self) прошел в:

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) 

Обратите внимание, что я должен был добавить еще одну вложенную функцию в pyro_opener(), чтобы сделать это правильный декоратор завод.

+0

Итак, когда я называю 'get_employee_names', откуда мне получить параметр obj? Кроме того, я думал, что использование '@ wraps' означает, что мне не нужен дополнительный уровень декоративности ...? – Pureferret

+0

@Pureferret: внимательно посмотрите на мою версию 'get_employee_names()'; аргумент 'obj' * * явно *. 'functools.wraps()' не имеет ничего общего с фабриками декораторов и всего, что копирует метаданные из обернутой функции в оболочку, так что последняя больше похожа на оригинал. –

+0

@martjinpieters, что я имею в виду, когда я хочу использовать 'get_employee_names', мне нужно предоставить параметры obj (только строка, мне нужно предоставить зарплату). Я не могу как-то вызвать метод вроде 'get_employee_names (???, 300000)', но что я вставляю в '???'? – Pureferret