如何在装饰器

时间:2016-02-03 09:33:17

标签: python exception dictionary python-decorators

我想知道是否有办法捕获在另一个装饰器中的一个装饰器中引起的所有异常并处理这些异常。

然而,在对我的问题提出某种复杂的解决方案之前,我想我会问专家,看看是否有我遗漏的东西。

我的应用程序看起来与此类似:

输入将以numGen函数给出。此numGen函数将输入添加到随机数。在我的例子中,我正在检查10个不同的随机数。

请注意,输入也会随着随机数生成的范围而变化。

看来,一旦你在Python中引发了用户定义的异常,就无法恢复测试的执行。但在我的场景中,我想检查不同输入值的错误。但是当前实现限制了继续检查不同输入向量的错误。

然而,在对我的问题提出某种复杂的解决方案之前,我想我会问专家,看看是否有我遗漏的东西。不幸的是,如果没有重要的重新分解,我无法轻易改变这种模式。

我的应用程序看起来与此类似: •输入将作为numGen函数给出。此numGen函数将输入添加到随机数。在我的例子中,我正在检查10个不同的随机数。 •注意输入也将随着随机数生成的范围而变化

**:编辑异常类

from random import randint
class RND_ERROR(Exception):
    def __init__(self, ErrNum, *arg, **kwargs):
        self.RND_ERR_NR = int(ErrNum)
        self.RND_ERR_MSG = ""         
        if self.RND_ERR_NR == 0x00000000:
            self.RND_ERR_MSG = "NO ERROR"
        elif self.RND_ERR_NR == 0x00000001:
            self.RND_ERR_MSG = "RANDOM NUMBER IS ONE"
        elif self.RND_ERR_NR == 0x00000002:
            self.RND_ERR_MSG = "RANDOM NUMBER IS TWO"
        elif self.RND_ERR_NR == 0x00000003:
            self.RND_ERR_MSG = "RANDOM NUMBER IS THREE"
        else:
            self.RND_ERR_MSG = "RANDOM NUMBER GREATER THAN THREE"
    def __str__(self):
        return "RND ERROR (0x%08X): %s" % (self.RND_ERR_NR,self.RND_ERR_MSG)

    def __repr__(self):
       return self.__str__()



def handleError(func):
    errors =[]
    def wrapper(arg1):
        try:
            result = func(arg1)
        except MyException as e:
            print errors.append(e)
    return wrapper

def findError(func):
    def wrapper(arg1):
        result = func(arg1)
        print result
        for k, v in result.iteritems():
            error_nr = v % 2
            if error_nr ==0:
                pass
            elif error_nr > 0:
                raise RND_ERROR(errornum) #edited lines
    return wrapper

@handleError
@findError
def numGen(input):
    from random import randint
    result= {}
    errors = []
    for i in range(9):
        j = (randint(0,4))
        result[i] = input + j
        result.update()    # This line does nothing...
    return result
if __name__ == '__main__':
    numGen(4)

功能numGen

此函数接受输入并生成10个随机数。 10个随机数保存在带索引的结果字典中。查找错误装饰器在结果字典中称为基础。

装饰者1 findError

在特定条件下,它会为不同的结果生成异常,如果发生错误,则会引发异常。

装饰者2 handleError

捕获先前装饰器中导致的所有异常,追加到列表中。稍后再说一点。

问题陈述:

  1. 我无法在try块中迭代字典,所以我无法捕获特定的错误。

  2. 我想检查每个输入是否发生错误以及是否发生任何错误引发异常并存储输入的信息 例如:      - 针对不同的输入提高异常。捕获异常,并存储发生异常的输入值以及异常类型(比如说)。

  3. 如何通过创建聚合异常来聚合异常,例如MyExceptionsCollection,它将保存数组并将其抬高而不是打印。

  4. 如何重新确认发生的确切异常或所有异常

  5. 注意:实现必须使用2个装饰器,用于生成错误和捕获错误。因为我将有200-250个函数,所以我需要检查所有这些函数的错误

    请帮助我如何实现这一目标。除了例外,任何更好的解决方案也是受欢迎的。

    提前致谢

4 个答案:

答案 0 :(得分:3)

您无需执行任何复杂的异常操作。认为你做的是造成问题的原因。你真正需要的是什么(我的猜测,因为正如其他人说的那样不太清楚)是处理返回的numGen值,并根据它们做一些事情(可能会引发异常)

一旦你以这种方式表达你的目标,很明显你需要更简单的东西。只是一个装饰器,它存储numGen返回的所有“错误”值(根据您对错误的定义)并允许您稍后处理它们。所以这是我的解决方案:

# Using a class as a decorator, so you can easily access its .wrong_values attribute
class ErrorHandler:
     def __init__(self, func):
         self.func = func
         self.wrong_values = []

     def __call__(self, arg):
         # Remove the first line if you want to keep wrong values from previous calls
         self.wrong_values.clear()
         result = self.func(arg)
         self.register_errors(result)
         return result

     def register_errors(self, result):
         wrong_values = [(k, v) for k, v in result.iteritems() if v % 2]
         self.wrong_values += wrong_values

@ErrorHandler
def numGen(input):
    from random import randint
    # You say you want 10 numbers, so the argument to range should be 10
    # And you can use dict-comp, which requires only one line and is faster
    return {i: randint(0, 4) + input for i in range(10)}

if __name__ == '__main__':
    print 'result', numGen(4)
    print 'wrong values', numGen.wrong_values

当我运行时,我得到了

result {0: 4, 1: 8, 2: 6, 3: 8, 4: 7, 5: 5, 6: 6, 7: 5, 8: 6, 9: 5}
wrong values [(4, 7), (5, 5), (7, 5), (9, 5)]

现在您可以轻松访问numGen.wrong_values;做任何你想做的事。

回顾你的问题陈述:

  

问题陈述:

     

我无法在try块中迭代字典,所以我是   无法捕捉特定错误。

没问题,因为您不需要try阻止。

  

如何通过创建聚合异常来聚合异常,例如   MyExceptionsCollection,它将保存数组并改为引发它   印刷。

我不知道聚合异常是什么。我认为从收集的值中收集值并引发异常(或其他)更为明智。这是实现的。

  

如何重新确认发生的确切异常或所有异常

同样,这是一个人为的问题,因为你必须首先提出异常才能“聚合”它们。你没有。相反,您聚合值并处理它们。

  

注意:实现必须使用2个装饰器来生成错误   并捕捉错误。因为我需要200到250个功能   检查所有这些功能的错误

我认为不需要两个装饰器。如果您对不同的函数有不同的错误捕获逻辑,则只需子类ErrorHandler并覆盖register_errors方法。 (使用类而不是函数作为装饰器的另一个优点。)

答案 1 :(得分:2)

我建议使用生成器而不是抛出异常:

class MyException(Exception):pass


def handleError(func):
    errors =[]
    def wrapper(arg1):
        result = func(arg1)

        for err in findError(result):
            errors.append(err)

        print errors
        return result

    return wrapper

def findError(result):
    print result
    for k, v in result.iteritems():
        error_nr = v % 2
        if error_nr ==0:
            pass
        elif error_nr > 0:
            yield MyException

@handleError
def numGen(input):
    from random import randint
    result= {}
    errors = []
    for i in range(9):
        j = (randint(0,4))
        result[i] = input + j
    return result

if __name__ == '__main__':
    numGen(4)

答案 2 :(得分:1)

很难理解你的要求。这是我最好的猜测。

findErrors检查并收集错误。如果有,它会引发异常。否则它只返回结果。

handleErrors打印异常(如果有)。否则,它只返回结果。

因为你使用print语句我认为你使用的是Python 2.7。

class MyException(Exception):pass

def handleError(func):
    def wrapper(arg1):
        try:
            return func(arg1)

        except MyException as e:
            print "Error:", e.args

    return wrapper

def findError(func):
    def wrapper(arg1):
        errors = []
        result = func(arg1)

        for k, v in result.iteritems():
            error_nr = v % 2
            if error_nr > 0:
                errors.append((k, v, error_nr))

        if errors:
            raise MyException, errors

        return result

    return wrapper

@handleError
@findError
def numGen(input):
    from random import randint
    result= {}
    for i in range(9):
        j = randint(0,4)
        result[i] = input + j
    return result

if __name__ == '__main__':
    numGen(4)

答案 3 :(得分:1)

@Sana我回答了您最近发布的Handing multiple exception of same type and resume execution in python

这个问题似乎是对原始问题的重述,因此原始答案仍然适用。 : - )

这里的代码片段可以在你的装饰者里面使用。

记住 - Python不能引发多个错误 - 第一个未捕获的错误将终止执行。如果您需要知道哪些项目失败,您可以收集错误,然后将其格式化为“主”错误。