0

I'm learning Python and am up to decorators.

I'm trying to understand why they would be used.

If I code a veeeeeery simple decorator,

def new_func(inserted_func):
    def wrap_func():
        print("Start")
        inserted_func()
        print("End")
    return wrap_func

@new_func
def existing_func():
    print("Middle")

existing_func()

It will return,

Start
Middle
End

But I could also achieve the same thing by coding,

def func1():
    print("Start")

def func2():
    print("Middle")

def func3():
    print("End")

func1()
func2()
func3()

Now I appreciate that my decorator function is very simple, but, other than "because you can", what are the reasons for choosing decorators over multiple functions?

Paul65
  • 19
  • 1
    Nothing...for the very limited case that you gave. Here are some tasks for you: 1. Add logging of arguments and return values to every single function in your python codebase 2. Add memoization to every pure function in your codebase 3. Add performance timing to every function in your codebase. Now, do you want to edit every single function in your codebase by hand, or do you want to write a couple of decorators? – Jared Smith Mar 18 '20 at 12:06
  • 1
    Simplicity's sake and reusability. The exact reason why we use functions as well. Imagine that you'd have to write the staticmethod decorator every time you start a new project! – Bram Vanroy Mar 18 '20 at 12:07
  • Or this: https://stackoverflow.com/questions/489720/what-are-some-common-uses-for-python-decorators – Jared Smith Mar 18 '20 at 12:08
  • Well, imagine that you need to call that wrapped function more than once. Would you prefer typing the three call for the price of one each time? – bipll Mar 18 '20 at 12:08

2 Answers2

1

Your example for the decorator is most likely the reason you are thinking to yourself "why, mein gott WHY!?"

but please take a look at, for example, flash solutions for routing (tutorial: https://medium.com/python-pandemonium/build-simple-restful-api-with-python-and-flask-part-1-fae9ff66a706)

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

The decorator here is doing you a great favor by letting you just create code, without having to manually type whatever is inside the @app.route() decorator.

Remember DRY? Decorators are an easy way to reuse code in many places. Again, the route example allows you to use one decorator across the entire project with different parameters, and everything just works.

Unamata Sanatarai
  • 6,475
  • 3
  • 29
  • 51
  • Gang, this question has been asked on SO multiple times already. Please don't answer dupes, flag for closure instead. – Jared Smith Mar 18 '20 at 12:09
0

You can write a decorator that:

  • measures the executiong time of a method: self explanatory
  • modifies the input parameter(s) of a method: You want to reuse the method several times but the logic differs slightly depending on the current object you have. -> You write multiple decorators that trim your input into the correct format
  • modifies the return parameter(s) of a method: same reasoning
  • ...

Decorators can be a really powerful tool to write more advanced code. You can live without them but at some point your code will get messy.

More importantly decorators are reusable and can be applied to any method. You write that logic once and slap it on any method you need.

Tin Nguyen
  • 5,250
  • 1
  • 12
  • 32
  • Gang, this question has been asked on SO multiple times already. Please don't answer dupes, flag for closure instead. – Jared Smith Mar 18 '20 at 12:09
  • @JaredSmith Hmm, if that's the case, then it's a question without an answer, as I've yet to see a good answer for the question. – Chuckk Hubbard Nov 19 '22 at 14:38
  • Everything you've said was *already* simple to do in Python by passing the target function as an argument to the decorator function. The @ Python decorator implementation changes this by changing what calling the target function does. I see no advantage to this because, if you later want to run your code WITHOUT the extra overhead of the timing, logging, etc. decorators, you have to go through and remove that line "@decorator" from every single place you put it. Otherwise, even if you use a switch to disable the extra functionality, your program still calls 2 functions instead of 1. – Chuckk Hubbard Nov 19 '22 at 14:45
  • @ChuckkHubbard you raise a good point in the case where you want both the decorated and undecorated versions. But *usually* that's not the case. The thing the decorator *syntax* buys you is that you can tell from the method declaration in the source that it is in fact decorated. Without the syntax the place where the method is defined and the place where the method is decorated may be hundreds of lines of code apart: it makes it harder to understand the code when you're reading it. This motivation is well covered in the PEP and in [this SO answer](https://stackoverflow.com/a/52593993/3757232). – Jared Smith Nov 19 '22 at 15:46
  • @JaredSmith I will look into the PEP some time. If one insists on using the same function name to refer to the decorated function, there's no reason the foo = decorator(foo) needs to be anywhere but right after the definition of foo(). But using that same name anyway seems like a potentially confusing habit. Incidentally, the SO answer you linked links to an article that offers a function that returns a function that returns a function?! as a way to send an argument to a decorator. I'm definitely not convinced that's an improvement over just writing the function for what it is. – Chuckk Hubbard Nov 22 '22 at 22:12
  • @ChuckkHubbard ...and you may be right. Or not. Enough people apparently thought it was worth it that the PEP got accepted. Doesn't mean they were right. FWIW I think the point you're making is well argued, but I wouldn't call your case against decorators a "slam dunk" either. But back to the task at hand. As far as me VTCing this as a dupe goes: that other question is definitely the one for posterity, if you have a problem with the adequacy of the answers on it comment on those (or even write your own!), this question is still a dupe of it. – Jared Smith Nov 22 '22 at 22:34
  • 1
    @JaredSmith Point taken. I obviously can't change that decision, but I can't help thinking there's something I don't get. I can see how it could be useful in some cases, so I guess I'll use them in those cases and otherwise not. Point taken also about the dupe. I could have read 3 pages of answers I disagreed with on one question instead of spread out over 3 questions! – Chuckk Hubbard Nov 22 '22 at 23:20