2012-06-21 41 views
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。我试图了解是什么让它出错,以及如何纠正它。

+1

请定义您的意思是**错误** - 给出您收到的错误或不正确的结果。 –

+0

'IndexError:元组索引超出范围' – John

回答

4

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

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

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 

同时,应注意像“安全”笼统的名字 - 其他异常可能仍然是抛出。

+0

我见过的例子是他们使用类而不是函数来包装原始函数。我们什么时候需要采取这种方法? – John

+1

@John如果你的包装函数需要某种内存,你应该这样做,例如,如果你想做[记忆](http://en.wikipedia.org/wiki/Memoization)。这并不是说你必须*,但有时候使用一个类或者一个[functor](http://en.wikipedia.org/wiki/Function_object)是很整洁的,因为它会像这样被调用。 –

+0

一般来说,如果你需要使用它,你会知道你需要。 –

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他张贴了他的后:直到后,我开始写我的这个回答并没有解决所有问题,而现在我我添加了比他更多的信息,所以我不会删除它,因为它不是完全相同的副本。

+0

感谢您的额外信息 – John

+0

+1在任何情况下,您都可以获得积分。 –

+0

@Lattyware Wohoo!谢谢你让我超过5000! :) –