Explorando o poder dos decoradores Python: casos de uso prático e técnicas avançadas
Os decoradores Python são um recurso elegante e poderoso que permite aos desenvolvedores modificar ou aprimorar o comportamento de funções ou métodos sem alterar seu código. Frequentemente subutilizados, os decoradores podem tornar seu código mais conciso, reutilizável e sustentável. Neste artigo, exploraremos o conceito de decoradores, seus casos de uso prático e mergulharemos em técnicas avançadas, como criar decoradores parametrizados, empilhar vários decoradores e implementar programação orientada a aspectos.
O que são Decoradores?
Os decoradores em Python são essencialmente funções de ordem superior que recebem uma função como entrada e retornam uma nova função com comportamento adicional ou modificado. Eles são definidos usando o símbolo '@' seguido pelo nome da função do decorador colocado acima da definição da função de destino.
Uso Básico
Vamos começar criando um decorador simples que mede o tempo que uma função leva para ser executada:
import time
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.2f} seconds to execute.")
return result
return wrapper
@timer_decorator
def slow_function():
time.sleep(2)
slow_function()
slow_function took 2.00 seconds to execute.
- Registro e depuração: decoradores podem ser usados para registrar informações sobre chamadas de função, como argumentos de entrada, valores de retorno e tempo de execução.
- Autorização e controle de acesso: você pode criar decoradores para verificar as funções, permissões ou autenticação do usuário antes de permitir o acesso a uma função ou método específico. ( Exemplo : No framework Django como um atalho, você pode usar o conveniente decorador login_required() )
- Cache e Memoização: Os decoradores podem armazenar os resultados de chamadas de função caras, evitando computação redundante e melhorando o desempenho.
- Decoradores parametrizados: Esses decoradores aceitam argumentos que podem ser usados para customizar seu comportamento. Para criar um decorador parametrizado, defina uma função externa que receba os parâmetros desejados e retorne a função real do decorador.
def retry_decorator(max_retries):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Attempt {i + 1} failed with error: {e}")
raise Exception("All attempts failed")
return wrapper
return decorator
@retry_decorator(max_retries=3)
def unreliable_function():
"""
Let's assume that we have made an incorrect operation, for example;
ZeroDivisionError is a built-in Python exception thrown when a
number is divided by 0
"""
print(100/0)
unreliable_function()
Attempt 1 failed with error: division by zero
Attempt 2 failed with error: division by zero
Attempt 3 failed with error: division by zero
Traceback (most recent call last):
File "/Users/aliyaman/Desktop/main.py", line 24, in <module>
unreliable_function()
File "/Users/aliyaman/Desktop/main.py", line 9, in wrapper
raise Exception("All attempts failed")
Exception: All attempts failed
@decorator1
@decorator2
def my_function():
pass
Os decoradores são ferramentas poderosas, mas também podem ser uma fonte de confusão e erros se não forem usados corretamente. Ao compreender as armadilhas comuns e as práticas recomendadas associadas aos decoradores, você pode evitar esses problemas e escrever um código Python mais eficaz.
- Esquecer de chamar a função encapsulada: Um erro comum é esquecer de chamar a função encapsulada dentro do decorador. Certifique-se de chamar a função original com os argumentos necessários (*args e **kwargs) dentro da função wrapper do decorador.
- Não retornando o resultado: sempre retorne o resultado da chamada de função original da função wrapper, a menos que você queira suprimir ou modificar intencionalmente o valor de retorno.
- Perda de metadados de função: ao usar decoradores, metadados importantes, como o nome da função, docstring e anotações, podem ser perdidos. Use a
functools.wrapsfunção para preservar essas informações adicionando@functools.wraps(func)imediatamente antes de definir a função wrapper dentro do decorador:
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Decorator logic here
return func(*args, **kwargs)
return wrapper
Decoradores Embutidos
Os decoradores integrados do Python oferecem aos desenvolvedores uma maneira conveniente de modificar o comportamento de funções e métodos sem alterar seu código. Esses decoradores podem ajudar a tornar seu código mais eficiente, fácil de manter e legível. Neste artigo, discutiremos três decoradores integrados comumente usados em Python: @staticmethod , @classmethod e @property . Abordaremos seus casos de uso e forneceremos exemplos para demonstrar suas aplicações práticas.
- O decorador @staticmethod é usado para definir métodos estáticos dentro de uma classe. Um método estático é um método que pertence à classe em vez de uma instância da classe e não requer que uma instância seja chamada. Isso significa que métodos estáticos não podem acessar ou modificar atributos ou métodos específicos da instância.
class MathOperations:
@staticmethod
def add(a, b):
return a + b
result = MathOperations.add(5, 3)
print(result) # Output: 8
Os métodos de classe são úteis quando você deseja criar métodos de fábrica ou executar ações que dependem do estado da classe em vez do estado da instância.
class Employee:
_id = 0
def __init__(self, name):
self.name = name
self.id = Employee._id
Employee._id += 1
@classmethod
def get_next_id(cls):
return cls._id
employee1 = Employee("Alice")
employee2 = Employee("Bob")
print(Employee.get_next_id()) # Output: 2
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@property
def diameter(self):
return self._radius * 2
@property
def area(self):
return 3.14159 * self._radius ** 2
circle = Circle(5)
print(circle.radius) # Output: 5
print(circle.diameter) # Output: 10
print(circle.area) # Output: 78.53975
Como conclusão, os decoradores Python são uma ferramenta poderosa que permite modificar ou aprimorar o comportamento de funções e métodos de maneira limpa e reutilizável. Compreender os decoradores e suas técnicas avançadas pode melhorar muito suas habilidades de programação em Python e ajudá-lo a escrever um código mais eficiente e sustentável. Não hesite em explorar o mundo dos decoradores e potenciar o seu potencial nos seus projetos!





































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)