0

我正在学习装饰器,在这里我试图将下面的内容更改为装饰器模式。

def invert(x):
    return 1/x

print invert(5)

可以使用装饰器进行更改。

def safe(fun, *args):
    if args[0]!=0:
        return fun(*args)
    else:
        "Division by 0"

def invert(x):
    return 1/x

print safe(invert, 5) 

使用@wapper 语法,

def safe(fun, *args):
    if args[0]!=0:
        return fun(*args)
    else:
        "Division by 0"
@safe
def invert(x):
    return 1/x

print invert(5)

上面的代码给出了错误IndexError: tuple index out of range。我试图了解是什么造成了错误以及如何纠正它。

4

2 回答 2

4

您的主要问题是装饰器需要返回一个函数,而不是一个值。装饰器将定义的函数替换为基于它的新函数。

除此之外,您在块中没有return语句else,只有字符串文字。你可能打算退回那个。

def safe(fun):
    def f(*args):
        if not args[0] == 0:
            return fun(*args)
        else:
            return "Division by 0"
    return f

就像一个注释,我认为这只是为了练习的目的,但错误不应该在 Python 中静默传递 - 发出异常的行为通常比在错误时返回字符串有用得多。事实上,为了更自然地为 Python 实现这一点,您需要遵循请求宽恕,而不是许可的口头禅:

def safe(fun):
    def f(*args):
        try:
            return fun(*args)
        except ZeroDivisionError:
            return "Division by 0"
    return f

此外,请注意像“安全”这样的广泛语句名称 - 仍然可能引发其他异常。

于 2012-06-21T10:48:43.110 回答
3

你这样做是错的。

def safe(fun):
    def wrapper(*args)
        if args[0]!=0:
            return fun(*args)
        else:
            return "Division by 0"
    return wrapper

该函数safe为您用它装饰的每个函数调用一次。每次调用装饰函数时都会调用由safe-- 这里称为--返回的内部函数。wrapped它负责调用原始函数,或者完全做其他事情。

所以装饰器只接受一个参数:要包装的函数。但是,有装饰器函数,它是一个返回装饰器的函数(因此多了一层包装函数):

def safe(singularities):
    def decorator(fun):
        def wrapper(*args)
            if args[0] not in singularities:
                return fun(*args)
            else:
                return "Division by 0"
        return wrapper
    return decorator

所以safe装饰器函数现在可能会返回无数个不同的装饰器。像这样使用:

@safe([0])
def invert(x):
    return 1 / x

@safe([-1, 1])
def foo(x)
    return 1 / ((x - 1) * (x + 1))

对于那些想知道为什么在他发布他的 Lattyware 之后我发布了与 Lattyware 基本相同的答案的人:直到我开始编写我的答案之后,该答案才解决了所有问题,现在我添加的信息比他的更多,所以我会不要删除它,因为它不是完全重复的。

于 2012-06-21T10:59:51.663 回答