改为装饰模式

时间:2012-06-21 10:46:22

标签: python

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

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。我试图了解是什么导致错误以及如何纠正它。

2 个答案:

答案 0 :(得分: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实现这一点,你想要遵循请求宽恕,而不是许可 mantra:

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

另外,请注意像“安全”这样的清晰语句名称 - 仍然可能抛出其他异常。

答案 1 :(得分:3)

你做错了。

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

对于您用它装饰的每个函数,函数safe被称为一次。然后在每次调用修饰函数时调用由safe返回的内部函数 - 此处称为wrapped。它负责调用原始函数或完全执行其他操作。

所以装饰器只需要一个参数:要包装的函数。 BUT ,有装饰器函数,这是一个返回装饰器的函数(所以还有一层包装函数):

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基本相同答案的答案:直到我开始写我的答案后,答案才解决所有问题,现在我添加的信息比在他的,所以我不会删除它,因为它不是一个完全重复。