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.
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!).
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;-).
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).
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.
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(..)
- [Django]-Python: two way partial credit card storing encrytion
- [Django]-MySQL Query error when run within Python but not when run directly
- [Django]-Django Import Issue
3đź‘Ť
Decorators are a way to hoist a common Aspect out of your code.
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:
Aspect Oriented Programming vs. Object-Oriented Programming
There are a few common use cases for AOP. You can read a few here:
Do you use AOP (Aspect Oriented Programming) in production software?
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)
-
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.
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.