2013-08-05 2 views
1

Скажем, у меня есть метод python для получения последнего синхронизируемого списка изменений в p4. (Сам вопрос не связан с p4, но только основным питона вопросом)Параметры обработки Python в контексте «с»

def get_last_synced_changelist(p4port, client_name, p4 = None): 
    with P4Connection(p4port) as p4: 
     last_change_list = p4.run_changes("-m1", "@%s" % client_name) 
     if last_change_list: 
      return last_change_list[0]["change"] 
     else: 
      return None 

Вызывающие этот метод может либо питания P4PORT, который является строкой, или они могли бы поставить объект p4 в себе. Мое требование заключается в том, что если «p4» объект поставляется Я хочу, чтобы запустить тело метода безс контекста, то есть, я не хочу, чтобы ввести или Выйдите метод, называемый на p4. Это связано с тем, что ответственность за закрытие/ввод объекта p4 лежит теперь на вызывающем абоненте. Если объект p4 не указан, в этой программе должен быть сконфигурирован синтаксис с использованием строки p4port.

Может ли кто-нибудь сказать мне, что является лучшим способом структурирования этого метода? Я хочу изменить тело как можно меньше. В основном что-то вроде

p4 or with P4Connection(p4port) as p4: 
    p4.run_changes(...) 

Но я не уверен, какой лучший синтаксис.

ответ

2

Вы можете создать фиктивный менеджер контекста:

import contextlib 
@contextlib.contextmanager 
def dummyctx(x): 
    yield x 

def get_last_synced_changelist(p4port, client_name, p4=None): 
    if p4 is None: 
     ctx = P4Connection(p4port) 
    else: 
     ctx = dummyctx(p4) 
    with ctx as p4: 
     last_change_list = p4.run_changes("-m1", "@%s" % client_name) 
     if last_change_list: 
      return last_change_list[0]["change"] 
     else: 
      return None 
+0

+1 довольно элегантный! – delnan

+0

Dummyctx довольно элегантен. Он многоразовый, и я могу назвать его no_op_ctx_mgr или какой-то такой штукой, и это похоже на шаблон Null-Object-Design-Pattern –

2

Это невозможно, with - составной оператор и не может быть встроен в такие выражения. Но вы можете использовать тот факт, что ваша функция также поддерживает «заимствование» ресурс:

def get_last_synced_changelist(p4port, client_name, p4 = None): 
    if p4 is None: 
     with P4Connection(p4port) as p4: 
      return get_last_synced_changelist(p4port, client_name, p4) 
    last_change_list = p4.run_changes("-m1", "@%s" % client_name) 
    if last_change_list: 
     return last_change_list[0]["change"] 
    else: 
     return None 

Этот подход работает даже если у вас есть отдельные функции для двух путей (которые могут иметь смысл в этом примере, как p4port по-видимому, не используется, когда передается существующий P4Connection).

0

В Python 2 вы, вероятно, хотите создать свой собственный менеджер контекста, либо фиктивный один, как @glglgl показывает в своем ответе, или, возможно, тот, который заворачивает дополнительное создание P4Connection:

import contextlib 

@contextlib.context_manager 
def p4_context(p4port, p4=None): 
    p4 is None: 
     with P4Connection(p4port) as p4: 
      yield p4 
    else: 
     yield p4 

def get_last_synced_changelist(p4port, client_name, p4 = None): 
    with p4_context(p4port, p4) as p4: 
     last_change_list = p4.run_changes("-m1", "@%s" % client_name) 
     if last_change_list: 
      return last_change_list[0]["change"] 
     else: 
      return None 

Если вы используете Python 3.3 или более поздней версии, вы можете вместо этого использовать удивительный новый contextlib.ExitStack класс:

import contextlib 

def get_last_synced_changelist(p4port, client_name, p4 = None): 
    with contextlib.ExitStack() as stack: 
     if p4 is None: 
      p4 = stack.enter_context(P4Connection(p4port)) 

     last_change_list = p4.run_changes("-m1", "@%s" % client_name) 
     if last_change_list: 
      return last_change_list[0]["change"] 
     else: 
      return None 
Смежные вопросы