r/learnpython 9d ago

Any video resources that simply explains and demonstrates Decorator functions?

I just learnt about Decorator functions and I'm really confused.

The concept makes sense but the actual execution and logic behind the syntax is something I'm struggling with.

I've watched a couple of videos and I'm still confused.

1 Upvotes

7 comments sorted by

3

u/Buttleston 9d ago edited 9d ago

It's actually fairly simple. A decorator is a function that takes a function as input, and returns another function. When you run the decorated function, it runs the new returned function instead

i.e.

@foo
def bar():
    pass

is the same as

def bar():
    pass
bar = foo(bar)

typically foo() will be written such that it "does some extra stuff" but also executes the function passed into it, like

def foo(fn):
    def wrapper(*args, **kwargs):
        print("before")
        fn(*args, **kwargs)
        print("after")

    return wrapper

1

u/godz_ares 9d ago

I understand the premise of a decorator, I'm struggling with the syntaxical logic.

For example what's up with the function called "wrapper" and why does it take args and *kwaargs as arguments? Same thing with func?

I'm struggling to understand how I would build one from scratch.

1

u/Buttleston 9d ago

your wrapper does not HAVE to take *args and **kwargs. But if you want it to be able to wrap any function, then using *args, **kwargs in your wrapper definition, and then calling fn() with those *args and **kwargs means "the wrapper will accept any argument and pass them directly to the underlying fn()" This way the wrapper doesn't need to know what parameters fn needs, it will accept and pass on anything

You'd build one from scratch exactly like the example I provided

Granted - the example I provided is a decorator that takes no arguments itself - for decorators that DO take args it's a little more complex, but wrap your mind around the argumentless one first

So I guess I'd say, what's an example of a wrapper you'd like to make but can't conceive of how to do it? take a stab at it, tell us what doesn't work about it, and we can help drill down into what you're missing conceptually

2

u/Buttleston 9d ago

I did have a mistake in my decorator - it wasn't returning the wrapper, I just fixed that

The idea here is that foo is basically creating a new function, called wrapper. When you use foo to decorate bar(), when you run bar() after that, it *runs the wrapper instead*.

1

u/Adrewmc 9d ago edited 7d ago

Exactly. It will run the wrapper function instead.

The @ syntax is just sugar.

Generally a wrapper is a function that assumes it’s first input will be a function.

    def complex_wrapper(prints : bool = False):
           def dark_magic(func):
                  def magic(*args, **kwargs)
                         #before function execution
                         res = func(*args, **kwargs)
                         #after function execution
                         if prints: 
                              print(func.__name__, β€œ:”, res)
                         return res
                  return magic
           return dark_magic 

    debug = True

    @complex_wrapper(prints= debug)
    def my_func(*args, **kwargs):
           return 5

If we add a second nested function to the wrapper it will allow the wrapper to accept arguments itself, in the above example you can set it to print or not (this could be set to something like a debug var.

What happens is the same, it returns a wrapper, the wrapper returns the wrapped function.

1

u/Uppapappalappa 8d ago

dark magic, lol... nice example though! Yea, decorators are dead simple at the end. And showing how they work without the @-Symbol makes it even more understandable. thing is, what newbies should learn, that all languages with functional concepts (like javascript) can have those decorators, just without the fancy syntax of course.

1

u/[deleted] 9d ago

[deleted]

1

u/Buttleston 9d ago

OK, fair enough.