3

我最近开始尝试使用 Python 装饰器(和高阶函数),因为看起来它们可能会使我的 Django 单元测试更加简洁。例如,而不是写:

def visit1():
    login()
    do_stuff()
    logout()

我可以改为

@handle_login
def visit1():
    do_stuff()

然而,经过一些实验,我发现装饰器并不像我希望的那么简单。首先,我对在不同示例中发现的不同装饰器语法感到困惑,直到我了解到装饰器在接受参数时的行为非常不同。然后我尝试装饰一个方法,最终发现它不起作用,因为我首先必须通过添加一个将我的装饰器变成描述符__get__方法。在整个过程中,我已经多次感到困惑,但仍然发现调试这个“装饰”的代码比通常的 Python 更复杂。我现在正在重新评估我的代码中是否真的需要装饰器,因为我最初的动机是节省一些打字,而不是因为有任何东西真正需要高阶函数。

所以我的问题是:应该自由使用装饰器还是谨慎使用?避免使用它们是否更像 Pythonic?

4

4 回答 4

12

装饰器在他们的位置上很好,绝对不能避免——在适当的时候;-)。我认为您的问题本质上是“好的,所以它们什么时候合适”?

在某些类的一些但不是所有方法周围添加一些前缀和/或后缀代码就是一个很好的例子。如果都是方法,包装所有方法的装饰器会比@thisonetoo无休止地重复要好;-)。如果它曾经在一个蓝色的月亮中,那么它不值得重构为包装器(装饰器或其他)。中间有一块很大的场地,装饰器确实很适合。

它归结为编程的黄金法则之一——DRY,即不要重复自己。当你看到你的代码变得重复时,你应该重构重复——装饰器是一个很好的工具,尽管它们远不是唯一的(辅助方法和函数、自定义元类、生成器和其他迭代器、上下文管理器...我们在过去几年中添加到 Python 中的许多功能最好被认为是 DRY 助手,更简单、更流畅的方法来排除这种或那种频繁的重复形式!)。

如果没有重复,就没有真正需要重构,因此(特别是)不需要装饰器——在这种情况下,YAGNI(Y'Ain't Gonna Need It)可以胜过 DRY;-)。

于 2009-06-28T05:02:09.420 回答
3

亚历克斯已经很好地回答了你的问题,我要添加的是装饰器,让你的代码更容易理解。(有时,即使你只做一次)。

例如,最初,我编写我的 Django 视图,根本没有考虑授权。当我写完它们时,我可以看到哪些需要授权用户并为他们添加一个@login_required。

因此,任何追随我的人都可以一眼看出哪些视图受到了身份验证保护。

当然,它们更干燥,到处都是。

如果不是 request.user.is_authenticated():返回 HttpResponseREdiect(..)

于 2009-06-28T06:12:16.033 回答
3

装饰器是一种从代码中提升公共方面的方法。

面向方面的编程支持者会告诉您,有很多共同方面,AOP 是必不可少和核心的。事实上,你可以在这里阅读关于这个话题的愚蠢辩论:

面向方面编程与面向对象编程

AOP 有一些常见的用例。你可以在这里阅读一些:

您在生产软件中使用 AOP(面向方面​​编程)吗?

装饰器对一些横切关注点很有帮助。

  • 访问控制(“安全”)身份验证、授权、权限、所有权

  • 日志记录(包括调试辅助和审计)

  • 缓存(通常是Memoization的实现)

  • 一些错误处理可能是一个常见方面,因此适用于装饰器实现。

很少有其他设计模式是真正跨领域的并且值得一个 AOP 装饰器。

于 2009-06-28T12:12:57.350 回答
0

如果您在许多函数的开头和结尾都有相同的代码,我认为这将证明使用装饰器增加的复杂性是合理的。

就像为一个有很多页面的网站使用一个漂亮(但可能很复杂)的模板,它确实节省了时间并最终增加了清晰度。

于 2009-06-28T04:58:22.327 回答