Python装饰器应该多久使用一次?

时间:2022-09-02 11:03:54

I recently started experimenting with Python decorators (and higher-order functions) because it looked like they might make my Django unit tests more concise. e.g., instead of writing:

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

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

I could instead do

我可以改为做

@handle_login
def visit1():
    do_stuff()

However, after some experimenting, I have found that decorators are not as simple as I had hoped. First, I was confused by the different decorator syntax I found in different examples, until I learned that decorators behave very differently when they take arguments. Then I tried decorating a method, and eventually learned that it wasn't working because I first have to turn my decorator into a descriptor by adding a __get__ method. During this whole process I've ended up confused more than a few times and still find that debugging this "decorated" code is more complicated than it normally is for Python. I'm now re-evaluating whether I really need decorators in my code, since my initial motivation was to save a bit of typing, not because there was anything that really required higher-order functions.

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

So my question is: should decorators be used liberally or sparingly? Is it ever more Pythonic to avoid using them?

所以我的问题是:装饰者是应该大量使用还是谨慎使用?避免使用它们是否更加Pythonic?

4 个解决方案

#1


12  

Decorators are fine in their place and definitely not to be avoided -- when appropriate;-). I see your question as meaning essentially "OK so when are they appropriate"?

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

Adding some prefix and/or postfix code around some but not all methods of some classes is a good example. Were it all methods, a class decorator to wrap all methods would be better than repeating @thisonetoo endlessly;-). If it's once in a blue moon then it's not worth refactoring out to wrappers (decorators or otherwise). In the middle, there's a large ground where decorators are quite suitable indeed.

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

It boils down to one of the golden rules of programming -- DRY, for Don't Repeat Yourself. When you see your code becoming repetitious, you should refactor the repetition out -- and decorators are an excellent tool for that, although they're far from the only one (auxiliary methods and functions, custom metaclasses, generators and other iterators, context managers... many of the features we added to Python over the last few years can best be thought of as DRY-helpers, easier and smoother ways to factor out this or that frequent form of repetition!).

它归结为编程的黄金法则之一 - 干,因为不要重复自己。当你看到你的代码变得重复时,你应该重构重复 - 装饰器是一个很好的工具,虽然它们远非唯一的(辅助方法和函数,自定义元类,生成器和其他迭代器,上下文管理器) ...我们在过去几年中添加到Python中的许多功能最好被认为是DRY-helpers,更容易和更平滑的方法来分解这种或频繁的重复形式!)。

If there's no repetition, there's no real call for refactoring, hence (in particular) no real need for decorators -- in such cases, YAGNI (Y'Ain't Gonna Need It) can trump DRY;-).

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

#2


3  

Alex already answered your question pretty well, what I would add is decorators, make your code MUCH easier to understand. (Sometimes, even if you are doing it only once).

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

For example, initially, I write my Django views, without thinking about authorisation at all. And when, I am done writing them, I can see which need authorised users and just put a @login_required for them.

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

So anyone coming after me can at one glance see what views are auth protected.

因此,任何追随我的人都可以一目了然地看到哪些观点是受版权保护的。

And of course, they are much more DRY and putting this everywhere.

当然,它们更加干燥并且无处不在。

if not request.user.is_authenticated(): return HttpResponseREdiect(..)

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

#3


3  

Decorators are a way to hoist a common Aspect out of your code.

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

Aspect-Oriented Programming proponents will tell you that there are so many common aspects that AOP is essential and central. Indeed, you can read a silly debate on this topic here:

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

Aspect Oriented Programming vs. Object-Oriented Programming

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

There are a few common use cases for AOP. You can read a few here:

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

Do you use AOP (Aspect Oriented Programming) in production software?

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

There a few cross-cutting concerns for which decorators are helpful.

关于装饰器有用的一些横切关注点。

  • Access Controls ("security") Authentication, Authorization, Permissions, Ownership

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

  • Logging (including Debugging aids and Auditing)

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

  • Caching (often an implementation of Memoization)

    缓存(通常是Memoization的实现)

  • Some error handling might be a common aspect and therefore suitable for decorator implementation.

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

There are very few other design patterns that are truly cross-cutting and deserve an AOP decorator.

很少有其他设计模式真正横切,值得一个AOP装饰。

#4


0  

If you have the same code at the beginning and end of many functions, I think that would justify the added complexity of using a decorator.

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

Rather like using a nice (but perhaps complex) template for a website with a lot of pages, it really saves time and adds clarity in the end.

更像是为具有大量页面的网站使用一个漂亮的(但也许是复杂的)模板,它确实可以节省时间并最终增加清晰度。

#1


12  

Decorators are fine in their place and definitely not to be avoided -- when appropriate;-). I see your question as meaning essentially "OK so when are they appropriate"?

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

Adding some prefix and/or postfix code around some but not all methods of some classes is a good example. Were it all methods, a class decorator to wrap all methods would be better than repeating @thisonetoo endlessly;-). If it's once in a blue moon then it's not worth refactoring out to wrappers (decorators or otherwise). In the middle, there's a large ground where decorators are quite suitable indeed.

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

It boils down to one of the golden rules of programming -- DRY, for Don't Repeat Yourself. When you see your code becoming repetitious, you should refactor the repetition out -- and decorators are an excellent tool for that, although they're far from the only one (auxiliary methods and functions, custom metaclasses, generators and other iterators, context managers... many of the features we added to Python over the last few years can best be thought of as DRY-helpers, easier and smoother ways to factor out this or that frequent form of repetition!).

它归结为编程的黄金法则之一 - 干,因为不要重复自己。当你看到你的代码变得重复时,你应该重构重复 - 装饰器是一个很好的工具,虽然它们远非唯一的(辅助方法和函数,自定义元类,生成器和其他迭代器,上下文管理器) ...我们在过去几年中添加到Python中的许多功能最好被认为是DRY-helpers,更容易和更平滑的方法来分解这种或频繁的重复形式!)。

If there's no repetition, there's no real call for refactoring, hence (in particular) no real need for decorators -- in such cases, YAGNI (Y'Ain't Gonna Need It) can trump DRY;-).

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

#2


3  

Alex already answered your question pretty well, what I would add is decorators, make your code MUCH easier to understand. (Sometimes, even if you are doing it only once).

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

For example, initially, I write my Django views, without thinking about authorisation at all. And when, I am done writing them, I can see which need authorised users and just put a @login_required for them.

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

So anyone coming after me can at one glance see what views are auth protected.

因此,任何追随我的人都可以一目了然地看到哪些观点是受版权保护的。

And of course, they are much more DRY and putting this everywhere.

当然,它们更加干燥并且无处不在。

if not request.user.is_authenticated(): return HttpResponseREdiect(..)

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

#3


3  

Decorators are a way to hoist a common Aspect out of your code.

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

Aspect-Oriented Programming proponents will tell you that there are so many common aspects that AOP is essential and central. Indeed, you can read a silly debate on this topic here:

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

Aspect Oriented Programming vs. Object-Oriented Programming

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

There are a few common use cases for AOP. You can read a few here:

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

Do you use AOP (Aspect Oriented Programming) in production software?

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

There a few cross-cutting concerns for which decorators are helpful.

关于装饰器有用的一些横切关注点。

  • Access Controls ("security") Authentication, Authorization, Permissions, Ownership

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

  • Logging (including Debugging aids and Auditing)

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

  • Caching (often an implementation of Memoization)

    缓存(通常是Memoization的实现)

  • Some error handling might be a common aspect and therefore suitable for decorator implementation.

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

There are very few other design patterns that are truly cross-cutting and deserve an AOP decorator.

很少有其他设计模式真正横切,值得一个AOP装饰。

#4


0  

If you have the same code at the beginning and end of many functions, I think that would justify the added complexity of using a decorator.

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

Rather like using a nice (but perhaps complex) template for a website with a lot of pages, it really saves time and adds clarity in the end.

更像是为具有大量页面的网站使用一个漂亮的(但也许是复杂的)模板,它确实可以节省时间并最终增加清晰度。