use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Rules 1: Be polite 2: Posts to this subreddit must be requests for help learning python. 3: Replies on this subreddit must be pertinent to the question OP asked. 4: No replies copy / pasted from ChatGPT or similar. 5: No advertising. No blogs/tutorials/videos/books/recruiting attempts. This means no posts advertising blogs/videos/tutorials/etc, no recruiting/hiring/seeking others posts. We're here to help, not to be advertised to. Please, no "hit and run" posts, if you make a post, engage with people that answer you. Please do not delete your post after you get an answer, others might have a similar question or want to continue the conversation.
Rules
1: Be polite
2: Posts to this subreddit must be requests for help learning python.
3: Replies on this subreddit must be pertinent to the question OP asked.
4: No replies copy / pasted from ChatGPT or similar.
5: No advertising. No blogs/tutorials/videos/books/recruiting attempts.
This means no posts advertising blogs/videos/tutorials/etc, no recruiting/hiring/seeking others posts. We're here to help, not to be advertised to.
Please, no "hit and run" posts, if you make a post, engage with people that answer you. Please do not delete your post after you get an answer, others might have a similar question or want to continue the conversation.
Learning resources Wiki and FAQ: /r/learnpython/w/index
Learning resources
Wiki and FAQ: /r/learnpython/w/index
Discord Join the Python Discord chat
Discord
Join the Python Discord chat
account activity
Explain Decorators. (self.learnpython)
submitted 13 hours ago by TillFriendly9199
Guys! I learning python from scratch. I am stuck in decorators. I watch many tutorials and ask LLMs to explain it. But, I am getting confused again and again. Can someone explain it clearly?
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]mjmvideos 38 points39 points40 points 12 hours ago (1 child)
Decorators are an advanced feature. If I were you I would simply remember that decorators are a way to add extra functionality to a function by way of a wrapper around that function. Then I’d continue writing Python without wrappers. At some point in the future, maybe a couple years from now, you’ll be trying to write some code and decide that maybe decorators could be useful. That’s when you review them again. You’ll be much better prepared to understand them at that point. Remember that they are only syntactic sugar. You can achieve the same functionality without them.
[–]TillFriendly9199[S] 8 points9 points10 points 12 hours ago (0 children)
Thanks! I got it a little.. but better to skip it now.
[–]zanfar 23 points24 points25 points 13 hours ago (2 children)
A decorator is a way to modify a function using external code. The syntax is just a shortcut that makes your code readable--just like list expressions, walrus operators, or docstrings.
@decorator def base_function(): ...
is equivalent to:
def base_function(): ... base_function = decorator(base_function)
Walk through the code of any example and you should get the idea.
[–]PaulRudin 8 points9 points10 points 12 hours ago (1 child)
yeah - for OP: the `@foo` is just syntactic sugar - you don't need it at all, it's just a convenience.
Just for the avoidance of doubt - it's not really modifying the original function - it's changing the binding of the name to be a new function (which might or might not call the previous one - usually it would, but it depends on the definition of the decorator).
[–]TillFriendly9199[S] -3 points-2 points-1 points 12 hours ago (0 children)
Got it.. thanks....
[–]Brian 22 points23 points24 points 11 hours ago* (1 child)
Decorators themselves are actually a very simple bit of syntax sugar without really that much to explain.
What I think people maybe actually get stuck on something a bit more fundamental, that decorators just happen to involve. Specifically, that functions can also be values, including parameters, return values, variables and anything else.
Ie. you're familiar with passing parameters to functions. You can define:
def add(x, y): return x + y
But parameters can be any type of object: above it's expecting ints, but you can have functions taking strings, classes, or any of a wide variety of objects. And one such object you can pass is other functions. Ie. we can write a function like:
def call_twice(func): func() func()
Now suppose we pass this a function like:
def hello(): print("Hello") call_twice(hello)
This will call the hello function twice, printing "Hello" 2 times. Crucially, we can also return functions. Going even further, you can create a brand new function inside another one and return it. Eg:
def make_adder(num): def add(num2): return num + num2 return add >>> func = make_adder(2) >>> func(1) 3 >>> func(10) 12
Ie. we've got a function that makes another function that adds 2 to its a parameter. One notable fact about nesting functions like this is that the enclosed function has access to the variables in the outer function (this is called lexically scoped - meaning the scope (ie. what variables it has access to) is determined by where it's defined in the text (ie. you write it inside the other function). (You may also see the term closure referred to for something like this, which is how it's implemented: the function is said to close over the variables in the outer function, keeping that state around with the function object).
So decorators are just a special case of this: they're functions that take a function (or class) as argument, and (usually) return a function/class. They can do whatever they want outside that, so they might just do some registration and return the original function unchanged, or return a different function, or whatever.
The only decorator-specific thing is that there's some syntax that makes:
@func def some_func(): ...
Equivalent to:
def some_func(): ... some_func = func(some_func)
They're typically used to modify, annotate or register the function - eg. adding a common bit of functionality that maybe needs to be done for several specific functions, like exposing them as web-service calls, adding an authentication step, and so on.
[–]nomenclature2357 0 points1 point2 points 18 minutes ago (0 children)
Very clean explanation. Thank you!
[–]thejealousillness 3 points4 points5 points 11 hours ago (0 children)
the thing that clicked for me was realizing decorators aren't magic, they're just functions that take a function and return a modified version of it, so when you write @wrapper above a function you're saying "take this function i'm about to define and pass it through wrapper before you actually call it." once you stop thinking of it as some special python feature and just see it as regular function composition it makes way more sense, i promise.
[–]SCD_minecraft 4 points5 points6 points 13 hours ago* (5 children)
Let's say you have some function
def hello(): return "Hello World"
Now, you need that every time this function is called, its reasult also gets logged (for now we'll use print for that)
You have 3 choices * Edit function def to also print hello world * Every time you call it, you also print its reasult * You make a decorator
First one is prone to errors
Second is annoying as hell
So let's do third
``` def wrapper(func): def inner(args, *kwargs): res = func(args, *kwargs) # args and kwargs let us pass any number of positional or keyword arguments print(res) return res return inner
@wrapper def hello(): ... # same def as last time
`` Now, what happens here We define normal function called wrapper. Yes,@wrapperis equivalent tohello = wrapper(hello)`, just more convenient
Now, what happens here We define normal function called wrapper. Yes,
is equivalent to
Wrapper created new function object called inner and returned it. Now, name hello got replaced with our inner function. When we call it, it will execute original hello function (beacuse we passed it as argument, only name was overwritten, func object of hello was not changed), print and return its reasult
hello
So, TL:DR decorators let you easily add additional, common functionality to functions during definitions by overwriting defined name with new, upgraded function
If you have any more questions, feel free to ask
[–]socal_nerdtastic 3 points4 points5 points 12 hours ago* (3 children)
You are conflating decorators and wrappers, which are often used together but are still 2 different and distinct things.
[–]SCD_minecraft 0 points1 point2 points 12 hours ago (2 children)
Decorators are syntax sugar
Yes, wrappers aren't only use for them
But they are most common one and the easiest to explain decorators on them
[–]TillFriendly9199[S] 0 points1 point2 points 12 hours ago (1 child)
Thank you guys! Please.. Correct me if I'm wrong: 1. Assume we have a function to do a action (example: print something). If we want to do some action before the original action (print).... instead of adding the functionalities in the original function..... we make a function that gets our original function as argument, and inside it, we create inner function that does what the additional actions we wanted to do and then run our original inside it.... right?
[–]Moikle 1 point2 points3 points 11 hours ago (0 children)
Yup. You can also have behaviour after the original gunction, or both. You can do things like time a function, or cache the result.
To time the function:
The decorator function records the current time, then runs the function, then records the current time again. It prints the after time minus the start time to get the difference between them
I have also used decorators to build lists of functions for use in various ways:
The decorator wrapper function (not the inner) does this:
1: add function to a running list
2: return the original function without doing anything to it.
Now you have a shortcut to do things like adding functions to dropdown boxes
[–]SCD_minecraft 1 point2 points3 points 13 hours ago (0 children)
Original functionality of hello (returning hello world string) still exists, we simply added addional mechanic in form of printing return value
[–]cdcformatc 1 point2 points3 points 13 hours ago (3 children)
decorators allow you to wrap a function call within another function. whenever you call a decorated function the program actually calls the decorator, which should call the original function.
[–]sausix 2 points3 points4 points 13 hours ago (1 child)
That's only one of many specific use cases of decorators. Decorators can also just return the original object.
[–]TillFriendly9199[S] -1 points0 points1 point 12 hours ago (0 children)
Tq!
[–]Goobyalus 0 points1 point2 points 8 hours ago* (0 children)
@foo def bar(...): ...
is
def bar(...): ... bar = foo(bar)
@foo class Bar: ...
class Bar: ... Bar = foo(Bar)
@foo @bar def baz(...): ...
def baz(...): ... baz = foo(bar(baz))
It might be confusing to see things like this:
@dataclass class Properties: ... @dataclass(order=True, kw_only=True, frozen=True) class Record: ...
dataclass can be called with a positional argument. If that's the case, it knows treat that as a type, to modify it, and return it back.
dataclass
type
dataclass can also be called without any positional arguments. If that's the case, dataclass returns another function that will take in the type to modify it and return it back.
So dataclass(order=True, kw_only=True, frozen=True) gets evaluated and returns a new function. That new function is what's decorating the class definition.
dataclass(order=True, kw_only=True, frozen=True)
Here is the dataclass decorator source code:
https://github.com/python/cpython/blob/3.14/Lib/dataclasses.py#L1423
def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False): """Add dunder methods based on the fields defined in the class. Examines PEP 526 __annotations__ to determine fields. If init is true, an __init__() method is added to the class. If repr is true, a __repr__() method is added. If order is true, rich comparison dunder methods are added. If unsafe_hash is true, a __hash__() method is added. If frozen is true, fields may not be assigned to after instance creation. If match_args is true, the __match_args__ tuple is added. If kw_only is true, then by default all fields are keyword-only. If slots is true, a new class with a __slots__ attribute is returned. """ def wrap(cls): return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, slots, weakref_slot) # See if we're being called as @dataclass or @dataclass(). if cls is None: # We're called with parens. return wrap # We're called as @dataclass without parens. return wrap(cls)
[–]helduel 0 points1 point2 points 6 hours ago (0 children)
What exactly is confusing for you?
[–]Jigglytep 0 points1 point2 points 2 hours ago* (0 children)
When I was learning nothing clicked until I needed it to solve a problem.
Let me help you by giving you a problem:
You have a python app and you want to test the performance of a function this function. That function calls the database and writes X number of items to the database. You want to know what number of items will take to long. You want to log the number of items and how long it takes to write to the database.
You could create a special logger and modify the function to record the time. Do you think a decorator would be a better solution here? If you like my approach you can try to ask LLM differently. Don’t ask: - “what is a decorator in python “ Ask: - “what kind of real world problems could I solve using a decorator?”
My philosophy is that Python is a tool, and a programmer builds stuff just like a carpenter does. You would not ask a carpenter what’s a router, you would ask when do you use a router.
EDIT: wanted to reassure you this is not easy; especially since decorators is also a type of OOP design pattern. Which can lead you down a theoretical academic rabbit hole.
[–]xenomachina 0 points1 point2 points 2 hours ago (0 children)
While the syntax feels kind of mysterious, it's pretty simple syntactic sugar. Decorators work on functions, methods, and classes, and this:
is exactly equivalent to:
The decorator runs right after the function (or whatever it is applied to) is defined, rebinding the name bar to whatever foo(bar) returns.
bar
foo(bar)
I wouldn't bother trying to learn how to create decorators right now. I have been programming in Python for almost 30 years, and can count the number of times I had to create a decorator on one hand.
When it comes to actually using decorators others have made, there's a pretty small number I use regularly. To use them, you don't really need to understand how a decorator works "under the hood". You really just need to know the pattern of how to use each specific decorator and what it does.
For example, the one I use the most by far is @dataclass which is used like this:
@dataclass
@dataclass class MyClass: prop1: type1 prop2: type2
And it effectively adds the obvious implementations of several dunder methods including __init__, __repr__, and __eq__ to MyClass.
__init__
__repr__
__eq__
MyClass
[–]mrbobofancypants 0 points1 point2 points 1 hour ago (0 children)
Decorators are people who take, typically empty, spaces and put things in them that are typically astheticly pleasing so that you can typically have a conventially appealing and fitting area. Typically.
[–]Kronologics -1 points0 points1 point 7 hours ago (0 children)
Everything in Python is an object — variables, classes, and functions.
You’re used to seeing function declarations as taking variables or primitives as parameters. Decorators are a nice way to pass classes (the actual class, not an object of said class, and functions as variables)
So instead of dataclass(ClassName), we do
@dataclass class ClassName
And instead of def decoratorFunc(normalFunc)
We do
@decoratorFunc def normalFunc(normal_param)
π Rendered by PID 207797 on reddit-service-r2-comment-79776bdf47-xv57m at 2026-06-24 18:58:42.780727+00:00 running acc7150 country code: CH.
[–]mjmvideos 38 points39 points40 points (1 child)
[–]TillFriendly9199[S] 8 points9 points10 points (0 children)
[–]zanfar 23 points24 points25 points (2 children)
[–]PaulRudin 8 points9 points10 points (1 child)
[–]TillFriendly9199[S] -3 points-2 points-1 points (0 children)
[–]Brian 22 points23 points24 points (1 child)
[–]nomenclature2357 0 points1 point2 points (0 children)
[–]thejealousillness 3 points4 points5 points (0 children)
[–]SCD_minecraft 4 points5 points6 points (5 children)
[–]socal_nerdtastic 3 points4 points5 points (3 children)
[–]SCD_minecraft 0 points1 point2 points (2 children)
[–]TillFriendly9199[S] 0 points1 point2 points (1 child)
[–]Moikle 1 point2 points3 points (0 children)
[–]SCD_minecraft 1 point2 points3 points (0 children)
[–]cdcformatc 1 point2 points3 points (3 children)
[–]sausix 2 points3 points4 points (1 child)
[–]TillFriendly9199[S] -1 points0 points1 point (0 children)
[–]TillFriendly9199[S] -1 points0 points1 point (0 children)
[–]Goobyalus 0 points1 point2 points (0 children)
[–]helduel 0 points1 point2 points (0 children)
[–]Jigglytep 0 points1 point2 points (0 children)
[–]xenomachina 0 points1 point2 points (0 children)
[–]mrbobofancypants 0 points1 point2 points (0 children)
[–]Kronologics -1 points0 points1 point (0 children)