Is there any good resource about class decorators specifically? It is more common to see function decorators in the wild, so my knowledge about the class ones is negligible at best
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
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
... 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: