Understanding Python Decorators: A Practical Introduction
Tags: python, beginners, decorators, flatironschool
Published: 2023-08-28 05:23:35

## What Are Decorators?
In Python, functions are first-class citizens. This means they can be passed around as arguments to other functions, returned as values from other functions, and even assigned to variables. Decorators leverage this feature to extend or modify the behavior of target functions.

## Basic Syntax
The basic syntax for decorators involves the "@" symbol, followed by the name of the decorator function. This is placed just above the function intended to be decorated. Think of decorator syntax as syntactic sugar.

```
@decorator_function
def target_function():
    print("Target function executed.")
```

## How Does It Work?
When you use a decorator, you are essentially doing three things:

Passing the target function as an argument to the decorator function.
Modifying or extending the behavior of the target function within the decorator function.
Returning the modified function or even a completely new function from the decorator function.
```
def decorator_function(target_function):
    def wrapper_function():
        print("Before the target function.")
        target_function()
        print("After the target function.")
    return wrapper_function

@decorator_function
def say_hello():
    print("Hello!")

say_hello()
```
When you call `say_hello()`, it actually executes `wrapper_function()`. This, in turn, calls the original `say_hello()` function between two print statements. The output would be:

```
Before the target function.
Hello!
After the target function.
```

## Chaining Decorators
Decorators can be chained, meaning you can apply multiple decorators to a single function:

```
def decorator_one(func):
    def wrapper_one():
        print("Decorator one: Before calling the function.")
        func()
        print("Decorator one: After calling the function.")
    return wrapper_one

def decorator_two(func):
    def wrapper_two():
        print("Decorator two: Before calling the function.")
        func()
        print("Decorator two: After calling the function.")
    return wrapper_two

@decorator_one
@decorator_two
def my_function():
    print("The original function.")

my_function()
```

Here, `my_function` is first passed to `decorator_two`, and then the result is passed on to `decorator_one`. The output for this code would be:

```
Decorator one: Before calling the function.
Decorator two: Before calling the function.
The original function.
Decorator two: After calling the function.
Decorator one: After calling the function.
```

## Class Decorators
During my time at Flatiron School, I came across a few useful class decorators:

## @staticmethod
- A static method is bound to the class itself and not to an instance of the class.
- These methods serve as utility functions that operate on their parameters.

Example:
```
class MyClass:
    def __init__(self,name):
        self.name = self.capitalize_name(name)

    @staticmethod
    def capitalize_name(name):
        return name.capitalize()

instance1 = MyClass('john')
print(instance1.name)
```
The output would be:
```
John
```
### @classmethod
- Similar to a static method, a class method is bound to the class and not an instance of the class.
- The first parameter for a class method is `cls`, which stands for 'class'.
- Class methods can access or modify the class state.

Example:
```
class MyClass:
    def __init__(self,name):
        self.name = name
    
    @classmethod 
    def create_with_capitalized_name(cls,name):
        name = name.capitalize()
        return cls(name)

instance1 = MyClass.create_with_capitalized_name('john')
print(instance1.name)
```

The output would be:

```
'John'
```

There's a whole world of decorators out there, but these are the key ones that I've encountered on my Python learning journey at Flatiron School. I genuinely hope you've found this article to be a helpful guide. I'm always open to feedback, so feel free to share your thoughts. Thanks so much for taking the time to read!