在python中使用装饰器进行错误处理

时间:2017-11-21 17:31:48

标签: python oop error-handling

我正在使用以下模型:

import time

class A:
    def do_action_1(self):
        print("A: action 1")

    def do_action_2(self):
        print("A: action 2")
        raise Exception

class B:
    def __init__(self,A):
        self.a = A
        self.status = None

    def call_action_1(self):
        self.a.do_action_1()

    def call_action_2(self):
        self.a.do_action_2()

a = A()
b = B(a)

while True:
    try:
        print("call action 1")
        b.call_action_1()
        print("call action 2")
        b.call_action_2()
    except Exception as e:
        print ("exception catched")
        while True:
            try:
                b.call_action_2()
                break
            except Exception:
                print ("exception catched")
                print ("waiting 3s ...")
                time.sleep(3)

我需要以某种方式修改b.status,当从B内部调用的a.do_action_2引发异常时。 b.call_action_2在不同的地方被多次调用,因此硬编码try except不是我想要的,也不是优雅的。我试图使用某种装饰,但我总是失败。看起来我错过了什么。

如果您有任何建议,请告诉我。此外,欢迎任何有关设计的评论。

此致

Ĵ

2 个答案:

答案 0 :(得分:0)

我不完全确定我理解你的问题,但我会对它进行一次尝试。

装饰器的一般想法是你想要为你已经喜欢的类添加行为,但由于某种原因不能直接改变。

你基本上想要围绕原始类包装一个新类,并给它额外的行为。

当你这样做时,你想将新的功能推送到新的装饰器中,这样你就不必在其他任何地方改变代码。

在您的示例中,最重要的是状态是B类的一部分,而不是A类。您还希望将所有重试逻辑移动到B类。

看起来像这样:

import time

class A:
    def do_action_1(self):
        print("A: action 1")

    def do_action_2(self):
        print("A: action 2")
        raise Exception

class B:
    def __init__(self,A):
        self.a = A
        self.status = 'None'

    def call_action_1(self):
        self.a.do_action_1()

    def call_action_2(self):
        while self.status != 'Success':
            try:
                self.a.do_action_2()
                self.status = 'Success'
            except Exception as e:
                self.status = 'Failure'
                print("exception caught inside decorator B")
                print("> waiting 3s ...")
                time.sleep(3)
            ## some sort of safety maximum attempt should be implemented so you don't get into an infinite loop here. 

a = A()
b = B(a)

while True:
    try:
        print("call action 1")
        b.call_action_1()
        print("call action 2")
        b.call_action_2()
    except Exception as e:
        print("exception in main")

为了安全起见,您应该为B类实现某种最大尝试次数,以便在X尝试do_action_2()后停止尝试。

答案 1 :(得分:0)

最后使用装饰器完成:

import time

global x
x = 0

def errorDecorator(func):#check if it is called by correct class need be done
    def wrapper(self,*args):
        try:
            return func(self,*args)
        except ZeroDivisionError as e:
            print ('error catched and processed ')
            global x
            x = 1 + x
            self.status='updated' + str(x)
            raise e
    return wrapper

class A:
    def do_action_1(self):
        print("A: action 1")

    def do_action_2(self):
        print("A: action 2")
        1/0

class B:
    def __init__(self,A):
        self.a = A
        self.status = None

    def call_action_1(self):
        self.a.do_action_1()

    @errorDecorator
    def call_action_2(self):
        self.a.do_action_2()

a = A()
b = B(a)

while True:
    print (b.status)
    try:
        print("call action 1")
        b.call_action_1()
        print("call action 2")
        b.call_action_2()
    except Exception as e:
        while True:
            try:
                print (b.status)
                b.call_action_2()
                break
            except ZeroDivisionError:
                time.sleep(3)