我最近开始尝试使用Python装饰器(以及高阶函数),因为看起来它们可能会使我的Django单元测试更加简洁。例如,而不是写作:
def visit1():
login()
do_stuff()
logout()
我可以改为
@handle_login
def visit1():
do_stuff()
然而,经过一些实验,我发现装饰器并不像我希望的那么简单。首先,我在不同的例子中找到了不同的装饰器语法,直到我了解到装饰器在它们take arguments时的行为方式非常不同。然后我尝试了一种方法,并最终了解到它无法正常工作,因为我首先要通过添加__get__
方法来turn my decorator into a descriptor。在整个过程中,我最终混淆了几次,仍然发现调试这个“装饰”的代码比通常用于Python更复杂。我现在正在重新评估我的代码中是否真的需要装饰器,因为我最初的动机是节省一些打字,而不是因为有任何真正需要高阶函数的东西。
所以我的问题是:装饰者是应该大量使用还是少量使用?避免使用它们会不会更像Pythonic?
答案 0 :(得分:12)
装饰师在他们的位置很好,绝对不可避免 - 适当时;-)。我认为你的问题基本上是“好的,所以 时它们是合适的”?
在某些类的某些但不是所有方法周围添加一些前缀和/或后缀代码就是一个很好的例子。如果是所有方法,用于包装所有方法的类装饰器将比无休止地重复@thisonetoo
更好;-)。如果它曾经是一个蓝色的月亮,那么不值得重构包装(装饰者或其他)。在中间,有一个很大的地方,装饰者确实非常合适。
归结为编程的黄金法则之一 - 干,因为不要重复自己。当你看到你的代码变得重复时,你应该重构重复 - 装饰器是一个很好的工具,虽然它们远非唯一的(辅助方法和函数,自定义元类,生成器和其他迭代器,上下文管理器) ... 我们在过去几年中添加到Python中的许多功能最好被认为是DRY-helpers,更容易和更顺畅地分解这种或那种频繁的重复形式!)。
如果没有重复,就没有真正的重构要求,因此(特别是)没有真正需要装饰者 - 在这种情况下,YAGNI(Y'Ain't Gonna Need It)可以胜过DRY; - )。< / p>
答案 1 :(得分:3)
Alex已经很好地回答了你的问题,我要添加的是装饰器,让你的代码更容易理解。 (有时候,即使你只做了一次)。
例如,最初,我编写了我的Django视图,而根本没有考虑授权。当我完成编写它们时,我可以看到哪些需要授权用户,只需为它们添加@login_required。
所以任何追随我的人都可以一目了然地看到哪些观点是受版权保护的。
当然,它们更加干燥,无处不在。
如果不是request.user.is_authenticated(): 返回HttpResponseREdiect(..)
答案 2 :(得分:3)
装饰器是一种从代码中提升常见 Aspect 的方法。
Aspect-Oriented Programming支持者会告诉你,有很多共同点,AOP是必不可少的和核心的。实际上,你可以在这里阅读关于这个主题的愚蠢辩论:
Aspect Oriented Programming vs. Object-Oriented Programming
AOP有一些常见的用例。你可以在这里阅读一些内容:
Do you use AOP (Aspect Oriented Programming) in production software?
有一些跨领域的问题,装饰者是有帮助的。
访问控制(“安全”)身份验证,授权,权限,所有权
记录(包括调试辅助工具和审核)
缓存(通常是Memoization的实现)
某些错误处理可能是一个常见方面,因此适合装饰器实现。
很少有其他设计模式真正具有交叉功能,值得一个AOP装饰。
答案 3 :(得分:0)
如果在许多函数的开头和结尾都有相同的代码,我认为这可以证明使用装饰器增加了复杂性。
更像是为一个有很多页面的网站使用一个漂亮的(但也许很复杂的)模板,它确实可以节省时间并最终增加清晰度。