装饰器周围有* args功能

时间:2016-01-28 08:30:45

标签: python function decorator

我尝试学习python装饰器,因为这些东西非常有用。我理解装饰器的工作原理是多么简单,但是我试图围绕功能制作装饰器,它带有* args并且它不起作用。我肯定错过了一些元素。我一直在浏览互联网寻找答案,但我找不到一个。

内部函数在列表中添加所有整数,包装器应检查列表中的所有元素是否为整数。

def wrapper(func):
    def inner(*args):
        for i in range(0, len(args[0])): #It does not iven get there.
            if not isinstance(i, int):
                return 'Invaild values.'
        else:       
            return func(*args)
    return inner

def add(*args):
    result = 0
    for i in range(0, len(args[0])):
        result += args[0][i]
    return result


def main():
    numbers = [1, '2', 3, 4]
    print(add(numbers))
    numbers = [1, 2, 3, 4]
    print(add(numbers))


if __name__ == '__main__':
    main()

我得到的错误。

Traceback (most recent call last):
  File "wrapper_of_function.py", line 23, in <module>
    main()
  File "wrapper_of_function.py", line 20, in main
    print(add(numbers))
  File "wrapper_of_function.py", line 15, in add
    result += args[0][i]
TypeError: unsupported operand type(s) for +=: 'int' and 'str'

5 个答案:

答案 0 :(得分:3)

也许你打算真正使用你的装饰

def wrapper(func):
    def inner(*args):
        for i in args[0]:
            if not isinstance(i, int):
                raise Exception('a non integer was encountered')
        else:       
            return func(*args)
    return inner

@wrapper
def add(*args):
    total = 0
    for i in args[0]:
        total += i
    return total


def main():
    numbers = [1, '2', 3, 4]
    try:
        print(add(numbers))
    except Exception as e:
        print 'invalid input %r - %s' % (numbers, e)
    numbers = [1, 2, 3, 4]
    print(add(numbers))


if __name__ == '__main__':
    main()

请注意,此实现的一个弱点是wrapped必须知道传递给它的内容才能正常工作。它需要知道检查第0个元素。这对于其他目的来说不是非常有用的功能。即使您使用*args,您仍然只将一个参数传递给add。如果您将多个参数传递给它所装饰的任何参数,您可能会发现wrapped通常更有用。

要做到这一点

def wrapper(func):
    def inner(*args):
        for i in args:
            if not isinstance(i, int):
                raise Exception('a non integer was encountered')
        else:       
            return func(*args)
    return inner

@wrapper
def add(*args):
    total = 0
    for i in args:
        total += i
    return total


def main():
    numbers = [1, '2', 3, 4]
    try:
        print(add(*numbers))
    except Exception as e:
        print 'invalid input %r - %s' % (numbers, e)
    numbers = [1, 2, 3, 4]
    print(add(*numbers))


if __name__ == '__main__':
    main()

答案 1 :(得分:3)

您测试i是否为int的实例,何时应测试args[0][i]int的实例:

def wrapper(func):
    def inner(*args):
        for i in range(len(args[0])): #It does not iven get there.
            if not isinstance(args[0][i], int):
                return 'Invalid values.'       
        return func(*args)
    return inner

@wrapper
def add(*args):
    result = 0
    for i in range(0, len(args[0])):
        result += args[0][i]
    return result


def main():
    numbers = [1, '2', 3, 4]
    print(add(numbers))
    numbers = [1, 2, 3, 4]
    print(add(numbers))


if __name__ == '__main__':
    main()

答案 2 :(得分:2)

你应该在@wrapper函数上使用add

def wrapper(func):
    def inner(args):
        for item in args:
            if not isinstance(item, int):
               return  'Invalid value found'
        return func(args)
    return inner

@wrapper    
def add(args):
    return sum(args)


def main():
    numbers = [1, '2', 3, 4]
    print(add(numbers))
    numbers = [1, 2, 3, 4]
    print(add(numbers))


if __name__ == '__main__':
    main()

答案 3 :(得分:1)

抛出的类型错误是因为你不能像[1,'2',3,4]那样添加Int和Str。您的装饰者应该在系统抛出错误之前执行检查,但您并没有真正使用它。

此外,还有一些错误。

def wrapper(func):
    def inner(*args):
        # 1, you don't use args other than args[0], what's the point of using list arguments?
        for i in range(0, len(args[0])): #It does not iven get there.
            # 2, you are running isinstance on array indexes, you should run this on values.
            if not isinstance(i, int):
                # 3, it's a bad practice to return different types in different scenarios. Return a special value and print the error message, or just raise a exception
                return 'Invaild values.'
        # 4, else keyword is redundant. the if statement is inside the loop.
        else:       
            return func(*args)
    return inner

# 5, you didn't use wrapper at the first place.
def add(*args):
    result = 0
    # 6, only using the first argument rather than the list
    for i in range(0, len(args[0])):
        result += args[0][i]
    return result

我为你重写了这段代码,希望它可以按你的需要工作。

def wrapper(func):
    def inner(*args):
        for arg in args:
            if not isinstance(arg, int):
                raise TypeError('Invalid values')
        return func(*args)
    return inner

@wrapper
def add(*args):
    result = 0
    for arg in args:
        result += arg
    return result

检查它是否有效

答案 4 :(得分:0)

@Zetys:在数字= [1,&#39; 2&#39;,3,4]中,第二个元素是一个字符串 因此,它无法添加到result,因为它的int(结果= 0)。如果您希望string参数转换为int以防它们是数字,则应使用int(str)函数。所以你的代码将是:

def add(*args):
    result = 0
    for i in range(0, len(args[0])):
        result += int(args[0][i])
    return result
顺便说一下,你还没有在代码中的任何地方使用wrapper类,所以它不会运行:)