【问题标题】:Avoid code duplication of try/except blocks, from a class避免类中 try/except 块的代码重复
【发布时间】:2021-03-13 04:06:03
【问题描述】:

我有一个类Test,它是另一个类的子类(它已经是一个上下文管理器,为了简单起见,我在这里选择了nullcontext)。

如何避免重复try/except 块,并将其直接在类中定义?

Avoiding Multiple Try/Except blocks in Python 及其答案不同,我想使用类而不是创建新函数。

例子:

import contextlib

class Test(contextlib.nullcontext):
    pass

try:
    with Test('abc') as t1:
        do_something(t1)
        do_something_else()   
except ValueError:      # these exceptions are thrown from Test's parent     
    print('a')          # class/context-manager methods  (nullcontext in this example)
except KeyError:
    print('b')

try:
    with Test('def') as t2:
        do_something(t2)
        do_this(t2)
except ValueError:
    print('a')
except KeyError:
    print('b') 

TL;DR:如何将 try:except ValueError:except KeyError: 移动到 Test 类中?

【问题讨论】:

  • 由于看到代码重复,我有制作函数或将代码置于循环中的动机。有什么你没有展示的东西会改变我的动机吗?
  • @quamrana 不是循环:我简化了我的真实情况,但他们做的事情不一样,而且他们有不同的论点,想象不同的Test(param1=..., param2=...) 调用,以及块pass 非常不同。
  • 我认为你过度简化了你的例子,你期望从哪里抛出 ValueError 或 KeyError ?如果错误发生在 Test.method() 内部,为什么不让 test.method 自己处理错误呢?
  • @JeffUK 这就是准确的一点,我应该补充一点:这些异常是从父类/上下文管理器(在我的示例中为nullcontext)抛出的。
  • 什么时候扔?什么时候创建对象?如果它们是从 init 抛出的,您是否可以覆盖 init,使用错误处理包装对父 init 的调用?

标签: python class exception try-catch contextmanager


【解决方案1】:

将代码放入__init__ 能解决您的问题吗?

import contextlib


class Test(contextlib.nullcontext):
    def __init__(self, abc, *args, **kwargs):
        super().__init__(*args, **kwargs)
        try:
            if abc == 'def':
                raise ValueError("VALUEERROR")
            elif abc == 'ghi':
                raise KeyError("KEYERROR")
            else:
                print("OK")
        except ValueError:
            print('a')
        except KeyError:
            print('b')


x1 = Test('abc')
x2 = Test('def')
x3 = Test('ghi')

【讨论】:

  • 我觉得不错!也许只需添加super().__init__(*args, **kwargs) 将参数传递给父类/上下文管理器。
  • 更好的方法是能够捕获与 Test 实例相关的 any 错误(不仅是__init__),但我不知道这是否可能直接在类本身...
  • @Basj 你是对的 *args**kwargs,我添加了它们。对于您的第二点,这将需要修改一个无论调用什么方法都会被调用的方法,而这在 Python 中是不可能的(否则我会感到惊讶)。您可以使用单个公共方法execute 来解决它,或者按照这些方法命名,它将一个字符串作为参数并调用该名称的私有方法;然后,您将有一个入口点,您可以将 try/except 块放入其中。这对我来说听起来很可疑,但它可能是值得的。
  • 谢谢@OctaveL!最后一件事:Test 是一个上下文管理器,我想与with Test() as t1: t1.dosomething() 一起使用(参见原始问题)。如何使此上下文t1 终止而没有错误,而不是raise,例如在您的示例中abc == 'def',以便t1.dosomething()执行?我试图用self.__exit__() 替换raise ...,但它不起作用。
  • @Basj 这很复杂。我已经完成了,但这是一个非常讨厌的解决方案:用简单的passes 的 lambda 替换类的每个方法,并在 __exit___ 调用中替换回方法。恐怕我现在想不出更好的办法,但如果你愿意,我可以分享我的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-23
  • 2020-11-26
  • 1970-01-01
  • 2013-02-20
  • 2015-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多