Remix.run Logo
shadowgovt a year ago

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