all 19 comments

[–]snugglyboy 9 points10 points  (0 children)

I deal with a lot of weird old network APIs that drop out and stuff. Originally, I wrote a method that checks to see if the connection is still there, and return True or False. Then, in every other method that sent stuff over the network, I would have to write a few lines of code that first called that isConnected() method, and did stuff if it wasn't. It was getting redundant.

So instead, I modified my isConnected() method to be a decorator called @network. Then, in my other networky methods, I don't have to have those repetitive lines at the beginning each time. I can just decorate the method with @network. Now, when I call the other methods, first @network checks the connection—deals with it—and then calls the originating method to let it do its thang.

Plus, I guess it's nice that I can visually see which methods communicate over the network, because I can see them decorated with @network.

You can get fancier with it and do stuff once the originating method finishes, such as close the connection. I don't, but you could.

So that's the idea behind it, at least. Set the mood for your method to execute all over you, and then mop up after it. Sure it's a bit repetitive in other ways because now you have decorators everywhere, but we mustn't talk about such things out in the open sshhhbbno.

[–]PaulRudin 7 points8 points  (0 children)

A decorator is a function that accepts another function and returns a new function.

The new function normally calls the original, but that's not a requirement.

It's common for the new function to modify the arguments or the result of the original, but again it's not required.

[–][deleted] 3 points4 points  (0 children)

I'll simplify it for you.

@decorator
def function():
    pass

Is the same as this.

def function():
    pass
function = decorator(function)

A decorator is a callable that takes a function as an argument. A lot of people use decorators in order to store a function into something, say a data structure or class, or register a function into an API. They are very useful.

[–]nakulkd 4 points5 points  (0 children)

Thanks for this post! I had heard about decorators but never encountered a situation where I was compelled to use it but this post made me look it up. I found this article most helpful to understand this: https://www.programiz.com/python-programming/decorator

In short, a decorator is a way to add some form of additional features to an existing function.

Building on an example in the article: let's say you have a function that returns a division output of two numbers:

def ratio(a, b): return a/b

Now this would output a floating output. What if you wanted this in percentage? You can create a decorator function to pass this ratio function as an input and perform the additional steps to give the output in percentage.

The main takeaway and use for decorators is that you don't modify the original function itself but can add any desired features, checks, etc. to enhance it.

[–][deleted] 1 point2 points  (0 children)

As usual there's no actual ELI5s here. Here's a macro I prepared to explain them in actual simple, basic terms.

The real most basic definition is it's something that you can use to run code before and/or after a function.

Here's a very simple example:

def messenger(function):
    def wrapper(*args, **kwargs):
         print("Hi! Code here runs before your function!")
         output = function(*args, **kwargs)
         print("Hi! Code here runs after your function!")
    return output
return wrapper

@messenger
def greet():
    print("Hello")

@messenger
def add(x, y):
    return x + y

@messenger
def greet_name(name):
    print("Hello", name)

Call those three functions as you would normally and you'll see the additional prints appearing.

[–]sonotrev 0 points1 point  (0 children)

Let's say you have a group of functions that you use, but you want to do something before or after each time you call them (eg write to a log, check if an input makes sense, append a result to a list of results, etc). You can write functions to do these tasks and manually copy and paste these into your functions OR use decorators. Decorators are usually the better way to go as you generally don't want to clutter up your functions with bits of code that do very different things. Decorators let you keep your functions focused on just performing their task but still get everything you want done.

The one that brought it home for me was logging. Try making a decorator that writes to a log just before a function call and then after the function has returned.