Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中的Try/Except:如何避免重复?_Python_Python Decorators_Contextmanager - Fatal编程技术网

Python中的Try/Except:如何避免重复?

Python中的Try/Except:如何避免重复?,python,python-decorators,contextmanager,Python,Python Decorators,Contextmanager,我有一个类可以将API引发的低级异常转换为高级异常。这个类充满了复杂的、重复的错误处理逻辑。我正在寻找减少这种重复的肾盂方法 这里有一个人为的例子 class ApiWrapperException(Exception): pass class ApiWrapper(object): def __init__(self, api): self._api = api def do_one_thing(self): print 'do_one_thing stuff

我有一个类可以将API引发的低级异常转换为高级异常。这个类充满了复杂的、重复的错误处理逻辑。我正在寻找减少这种重复的肾盂方法

这里有一个人为的例子

class ApiWrapperException(Exception):
  pass

class ApiWrapper(object):

  def __init__(self, api):
    self._api = api

  def do_one_thing(self):
    print 'do_one_thing stuff before API call'
    try:
      self._api.do_one_thing()
    except ApiException:
      print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
      raise ApiWrapperException
    print 'do_one_thing stuff after API call'

  def do_another_thing(self):
    print 'do_another_thing stuff before API call'
    try:
      self._api.do_another_thing()
    except ApiException:
      print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
      raise ApiWrapperException
    print 'do_another_thing stuff after API call'
在本例中,
ApiWrapper
类将低级的
ApiException
转换为更好的
ApiWrapperException
。但是有很多重复

选项1:使用函数包装器 我可以将复制的代码放入一个内部函数中,如下所示:

def handle_api_errors(api_callable):
  def call(*args, **kwargs):
    try:
      return api_callable(*args, **kwargs)
    except ApiException:
      print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
      raise ApiWrapperException
  return call
@contextlib.contextmanager
def handle_api_errors():
  try:
    yield
  except ApiException:
    print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
    raise ApiWrapperException
def handle_api_errors(api_calling_func):
  def decorated_func(*args, **kwargs):
    try:
      api_calling_func(*args, **kwargs)
    except ApiException:
      print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
      raise ApiWrapperException
  return decorated_func
ApiWrapper
类简化为:

class ApiWrapper(object):

  def __init__(self, api):
    self._api = api

  def do_one_thing(self):
    print 'do_one_thing stuff before API call'
    handle_api_errors(self._api.do_one_thing)()
    print 'do_one_thing stuff after API call'

  def do_another_thing(self):
    print 'do_another_thing stuff before API call'
    handle_api_errors(self._api.do_another_thing)()
    print 'do_another_thing stuff after API call'
class ApiWrapper(object):

  def __init__(self, api):
    self._api = api

  def do_one_thing(self):
    print 'do_one_thing stuff before API call'
    with handle_api_errors():
      self._api.do_one_thing()
    print 'do_one_thing stuff after API call'

  def do_another_thing(self):
    print 'do_another_thing stuff before API call'
    with handle_api_errors():
      self._api.do_another_thing()
    print 'do_another_thing stuff after API call'
class ApiWrapper(object):

  def __init__(self, api):
    self._api = api

  @handle_api_errors
  def do_one_thing(self):
    print 'do_one_thing stuff before API call'
    self._api.do_one_thing()
    print 'do_one_thing stuff after API call'

  @handle_api_errors
  def do_another_thing(self):
    print 'do_another_thing stuff before API call'
    self._api.do_another_thing()
    print 'do_another_thing stuff after API call'
选项2:使用上下文管理器 我可以将复制的代码放在上下文管理器中,如下所示:

def handle_api_errors(api_callable):
  def call(*args, **kwargs):
    try:
      return api_callable(*args, **kwargs)
    except ApiException:
      print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
      raise ApiWrapperException
  return call
@contextlib.contextmanager
def handle_api_errors():
  try:
    yield
  except ApiException:
    print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
    raise ApiWrapperException
def handle_api_errors(api_calling_func):
  def decorated_func(*args, **kwargs):
    try:
      api_calling_func(*args, **kwargs)
    except ApiException:
      print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
      raise ApiWrapperException
  return decorated_func
ApiWrapper
类简化为:

class ApiWrapper(object):

  def __init__(self, api):
    self._api = api

  def do_one_thing(self):
    print 'do_one_thing stuff before API call'
    handle_api_errors(self._api.do_one_thing)()
    print 'do_one_thing stuff after API call'

  def do_another_thing(self):
    print 'do_another_thing stuff before API call'
    handle_api_errors(self._api.do_another_thing)()
    print 'do_another_thing stuff after API call'
class ApiWrapper(object):

  def __init__(self, api):
    self._api = api

  def do_one_thing(self):
    print 'do_one_thing stuff before API call'
    with handle_api_errors():
      self._api.do_one_thing()
    print 'do_one_thing stuff after API call'

  def do_another_thing(self):
    print 'do_another_thing stuff before API call'
    with handle_api_errors():
      self._api.do_another_thing()
    print 'do_another_thing stuff after API call'
class ApiWrapper(object):

  def __init__(self, api):
    self._api = api

  @handle_api_errors
  def do_one_thing(self):
    print 'do_one_thing stuff before API call'
    self._api.do_one_thing()
    print 'do_one_thing stuff after API call'

  @handle_api_errors
  def do_another_thing(self):
    print 'do_another_thing stuff before API call'
    self._api.do_another_thing()
    print 'do_another_thing stuff after API call'
选项3:使用装饰器(按照@ZachGates的建议) 我可以将复制的代码放入装饰器中,如下所示:

def handle_api_errors(api_callable):
  def call(*args, **kwargs):
    try:
      return api_callable(*args, **kwargs)
    except ApiException:
      print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
      raise ApiWrapperException
  return call
@contextlib.contextmanager
def handle_api_errors():
  try:
    yield
  except ApiException:
    print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
    raise ApiWrapperException
def handle_api_errors(api_calling_func):
  def decorated_func(*args, **kwargs):
    try:
      api_calling_func(*args, **kwargs)
    except ApiException:
      print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
      raise ApiWrapperException
  return decorated_func
ApiWrapper
类简化为:

class ApiWrapper(object):

  def __init__(self, api):
    self._api = api

  def do_one_thing(self):
    print 'do_one_thing stuff before API call'
    handle_api_errors(self._api.do_one_thing)()
    print 'do_one_thing stuff after API call'

  def do_another_thing(self):
    print 'do_another_thing stuff before API call'
    handle_api_errors(self._api.do_another_thing)()
    print 'do_another_thing stuff after API call'
class ApiWrapper(object):

  def __init__(self, api):
    self._api = api

  def do_one_thing(self):
    print 'do_one_thing stuff before API call'
    with handle_api_errors():
      self._api.do_one_thing()
    print 'do_one_thing stuff after API call'

  def do_another_thing(self):
    print 'do_another_thing stuff before API call'
    with handle_api_errors():
      self._api.do_another_thing()
    print 'do_another_thing stuff after API call'
class ApiWrapper(object):

  def __init__(self, api):
    self._api = api

  @handle_api_errors
  def do_one_thing(self):
    print 'do_one_thing stuff before API call'
    self._api.do_one_thing()
    print 'do_one_thing stuff after API call'

  @handle_api_errors
  def do_another_thing(self):
    print 'do_another_thing stuff before API call'
    self._api.do_another_thing()
    print 'do_another_thing stuff after API call'
哪个选项被认为是最具蟒蛇精神的?有更好的选择吗?

这个怎么样

class ApiWrapper(object):

    def __init__(self, api):
        self._api = api

    def api_call(self, methodname, *args, **kwargs):
        method = getattr(self._api, methodname)
        try:
            return method(*args, **kwargs)
        except ApiException:
            print 'ApiWrapper caught an ApiException. Doing complicated error handling logic. Raising a different exception.'
            raise ApiWrapperException

    def do_one_thing(self):
        print 'do_one_thing stuff before API call'
        self.api_call("do_one_thing")
        print 'do_one_thing stuff after API call'

就我个人而言,我会使用decorator包装异常处理程序中的任何函数。在我看来,装潢师背后的意图比包装每个电话更清楚,但这绝不是基于事实。我同意@ZachGates,你为什么不使用装潢师呢?@ZachGates的观点很好。装饰师绝对是一种选择。代码流与基线代码中的代码流不完全相同,因为API调用前后的“填充”部分将包含在try/except处理程序中。但这不是问题,因为try/except处理程序只捕获API异常,而不是“stuff”部分可能引发的异常。我在问题陈述中添加了decorator方法。谢谢