YouTip LogoYouTip

Python Decorators

## Python3.x Python Decorators Decorator (decorator) is an advanced feature in Python used to **dynamically extend the functionality of a function or class without modifying the original function's code**. Essentially, a decorator is a function: it takes a function as a parameter and returns a new function (usually an enhanced version of the original function). !(#) Decorators are applied to function or method definitions using the @decorator_name syntax. Python also provides some built-in decorators, such as @staticmethod and @classmethod. **Common Use Cases:** * **Logging:** Record function call information, parameters, and return values * **Performance Statistics:** Measure function execution time * **Access Control:** Restrict function access permissions * **Caching:** Cache function results to improve performance * * * ### Basic Syntax The core idea of a decorator is: **"wrapping" another function with a function**. ## Syntax def decorator_function(original_function): def wrapper(*args, **kwargs): # Before call print("Before execution") result = original_function(*args, **kwargs) # After call print("After execution") return result return wrapper @decorator_function def target_function(): print("Original function execution") **Analysis:** * `decorator_function`: The decorator function (receives the original function) * `wrapper`: The wrapper function (actually executed) * `@decorator_function`: Equivalent to function replacement **Equivalentapproach:** target_function = decorator_function(target_function) ? When calling `target_function()`, it actually executes `wrapper()` * * * ### Using Decorators Decorators are applied to function definitions using the @ syntax sugar: @time_loggerdef target_function(): pass Equivalent to: def target_function(): pass target_function = time_logger(target_function) This mechanism allows us to add functionality (such as logging, permissions, etc.) uniformly without modifying the original function. * * * ## Example: Printing Logs def my_decorator(func): def wrapper(): print("Before function execution") func() print("After function execution") return wrapper @my_decorator def say_hello(): print("Hello!") say_hello() Output: Before function executionHello!After function execution * `my_decorator` receives `say_hello` * `@my_decorator` replaces the original function * * * ### Decorators with Parameters If the original function has parameters, you need to use `*args, **kwargs` in the `wrapper`: ## Example def my_decorator(func): def wrapper(*args, **kwargs): print("Before execution") func(*args, **kwargs) print("After execution") return wrapper @my_decorator def greet(name): print(f"Hello, {name}!") greet("Alice") Output: Before executionHello, Alice!After execution **Note:** Using `*args, **kwargs` allows compatibility with functions of any parameters. * * * ## Decorators with Parameters (Advanced) def repeat(num_times): def decorator(func): def wrapper(*args, **kwargs): for _ in range(num_times): func(*args, **kwargs) return wrapper return decorator @repeat(3) def say_hello(): print("Hello!") say_hello() **Note:** This is a "decorator factory", where the outer function is used to receive parameters. Hello!Hello!Hello! !(#) * * * ## Class Decorators In addition to functions, decorators can also be applied to classes. Class decorators receive a class and return a modified class or wrapped class. * Enhance class methods * Control instantiation process * Implement singleton, logging, and other features * * * ### Function-style Class Decorators ## Example def log_class(cls): class Wrapper: def __init__ (self, *args, **kwargs): self.wrapped= cls(*args, **kwargs) def __getattr__ (self, name): return getattr(self.wrapped, name) def display(self): print("Before call") self.wrapped.display() print("After call") return Wrapper @log_class class MyClass: def display(self): print("Original method") obj = MyClass() obj.display() Before callOriginal methodAfter call * * * ### Class-style Class Decorators ## Example: Singleton Pattern class SingletonDecorator: def __init__ (self, cls): self.cls= cls self.instance=None def __call__ (self, *args, **kwargs): if self.instance is None: self.instance=self.cls(*args, **kwargs) return self.instance @SingletonDecorator class Database: def __init__ (self): print("Initialization") db1 = Database() db2 = Database() print(db1 is db2) InitializationTrue * * * ## Built-in Decorators Commonly used built-in decorators: 1. **@staticmethod**: Defines a static method 2. **@classmethod**: Defines a class method 3. **@property**: Converts a method to a property ## Example class MyClass: @staticmethod def static_method(): print("Static method") @classmethod def class_method(cls): print(cls.__name__) @property def name(self): return self._name @name.setter def name(self, value): self._name = value * * * ## Stacking Multiple Decorators Multiple decorators **wrap the function from bottom to top during the definition phase**, and **execute from top to bottom during the call phase**: ## Example def decorator1(func): def wrapper(): print("Decorator 1") func() return wrapper def decorator2(func): def wrapper(): print("Decorator 2") func() return wrapper @decorator1 @decorator2 def say_hello(): print("Hello!") say_hello() Final output: Decorator 1Decorator 2Hello! * * * ## Core Summary Decorator = Function wrapping function + extending functionality without modifying original code * The @ syntax is essentially function replacement * wrapper is the actually executed function * Recommended to use *args, **kwargs for better versatility * Supports functions, classes, and even decorators with parameters
← C VscodeSeaborn Tutorial β†’