logoalt Hacker News

shadowgovt04/23/20251 replyview on HN

I can't name one off the top of my head, but conceptually they're the same because classes are also first-class in Python (i.e. they can be passed around as function arguments and even modified).

Classes in Python are actually themselves instances (of builtin class 'type'). So to make a decorator for one, you create a function that takes a class (i.e. an instance of 'type' with a lot of duck-typing already applied to it in the class definition) as an argument and returns a class (either the same class or a brand-new one; usually you make a brand new one by creating a new class inside the decorator that subclasses the class passed in, `MyNewClass(cls)`, and you return `MyNewClass`... The fact it's named `MyNewClass` inside the decorator won't matter to anyone because that's a local variable inside the decorator function body).

The syntactic sugar Python does when you go

  @decorator
  class Foo:
... is basically:

* Create a class (with no name yet)

* Pass that class to function `decorator`

* Bind the return value of `decorator` to the variable `Foo`.

---

Before decorators came along, you'd get their effects on classes with this pattern:

  class Foo:
    # the definition of Foo

  Foo.some_new_method = ...  # since Foo is also an instance of a class, you can just modify it in-place.

  Foo = decorate_it(Foo)  # ... or pass it as an argument to a function and re-bind its name to the result

Replies

alkh04/23/2025

Thanks for the detailed explanation! I assume that essentially, the same rules as with function decorators apply(in regards to parameterizing them etc.) but the main difference is that we accept the class object and then return the class object vs the function object and that's it?

show 1 reply