周围的装饰器使用 *args 功能



我尝试学习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'

你测试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()

也许你打算实际使用你的装饰器

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,'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

检查它是否有效

你应该在

add函数上使用@wrapper

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()

@Zetys : 在数字 = [1, '2', 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类,因此它不会运行:)

最新更新