Curso
Injeção de dependência é um padrão de design em que objetos ou serviços (aqui, dependências) são fornecidos a uma classe de fora, em vez de a classe criá-los internamente. Isso separa os componentes.
Usar injeção de dependência em Python tem várias vantagens, como:
- Modularidade: Seu código é dividido em partes menores e reutilizáveis.
- Testabilidade: É mais fácil testar seu código porque você pode trocar a parte real por uma simulada.
- Manutenção: Você pode atualizar ou mudar partes do seu código sem mexer no resto do sistema.
Neste tutorial, vou mostrar como usar injeção de dependência em Python com exemplos simples e práticos.
Entendendo a injeção de dependência em Python
Pra entender como implementar a injeção de dependência, é essencial que você entenda os princípios fundamentais que a regem.
A injeção de dependência é baseada em algo chamado princípio da inversão de controle (IoC), que significa que, em vez de uma classe criar e gerenciar suas dependências, ela as recebe de uma fonte externa. Isso ajuda a focar em uma única tarefa e deixa seu código mais limpo.
Injetar dependências em Python inclui essas maneiras comuns, embora existam outras:
- Injeção do construtor: Passa as dependências pelo construtor da classe.
- Injeção do setter: Defina as dependências usando um método setter depois que o objeto for criado.
- Injeção de método: Passa as dependências direto pro método que precisa delas.
Por que usar injeção de dependência em Python?
Como desenvolvedor, entender e implementar a injeção de dependências pode fazer uma grande diferença no design do seu código. Vamos ver algumas vantagens da injeção de dependência.
Modularidade, reutilização e flexibilidade
A injeção de dependência permite dividir seu código em componentes menores e mais focados, proporcionando maior flexibilidade e modularidade.
Cada parte ou componente faz uma tarefa específica e depende de outras coisas, o que facilita reutilizá-las em diferentes partes do seu aplicativo ou do aplicativo de outra pessoa.
Por exemplo, se você tem uma classe que manda mensagens. Em vez de criar uma lógica de e-mail ou SMS diretamente no seu serviço, você pode usar uma classe de remetente de e-mail ou SMS.
Agora, sua classe que manda mensagens não liga pra como a mensagem é enviada, só usa o remetente que foi fornecido pra ela. Isso quer dizer que você pode usar seu remetente de mensagens com diferentes remetentes de e-mail ou SMS.
Manutenção e testabilidade
Quando você usa injeção de dependência, dá pra trocar facilmente as dependências reais por dados simulados durante os testes. Isso facilita escrever testes unitários sem depender de APIs ou bancos de dados.
Imagina, só pra pensar, que você tem uma aula que salva dados em um banco de dados. Para fins de teste, você pode usar um banco de dados falso em vez de um real para evitar que o seu teste fique ligado ao banco de dados de produção.
A injeção de dependência permite que você modifique partes específicas do seu código sem quebrar todo o sistema. Isso é super útil quando você precisa trocar de provedor de pagamento em um aplicativo, tipo do Stripe para o PayPal, sem mexer no resto do seu código.
Inversão de controle e dependências trocáveis
A ideia da inversão de controle é a seguinte: a injeção de dependência vai passar a responsabilidade de criar e gerenciar dependências para uma fonte externa.
Isso quer dizer que você pode trocar facilmente uma implementação por outra; por exemplo, se você tem uma classe ReportGenerator que formata e exporta relatórios.
Em vez de a classe decidir o formato de exportação, você pode colocar uma classe exportadora, como PDFExporter, ExcelExporter ou CSVExporter, nela.
A classe ` ReportGenerator ` não liga pra como a exportação rola, então, pra mudar um formato, é só trocar o exportador que você injeta, sem mexer no ` ReportGenerator `.
Implementando injeção de dependência em Python
Agora que você já tem uma ideia clara do que é injeção de dependência e por que ela é útil, vamos ver como você pode implementá-la em Python. Vamos começar com o método mais simples: injeção manual de dependências.
Injeção manual de dependências
Na injeção de dependência manual, você mesmo cria as dependências e as passa para a classe ou função que precisa delas.
Esse método funciona bem para pequenas aplicações, mas conforme sua aplicação cresce, você precisa usar uma estrutura de injeção de dependência para evitar erros.
Aqui tá um exemplo de código sem injeção de dependência
class EmailService:
def send_email(self, message):
print(f"Sending email: {message}")
class UserNotifier:
def __init__(self):
self.email_service = EmailService() # Creates its own dependency
def notify(self, message):
self.email_service.send_email(message)
notifier = UserNotifier()
notifier.notify("Welcome!")
No exemplo acima, UserNotifier está bem ligado a EmailService. Não é fácil trocar ou simular um objeto de serviço ( EmailService ) para testes.
Aqui está outra versão, mas com injeção de dependência manual.
class EmailService:
def send_email(self, message):
print(f"Sending email: {message}")
class UserNotifier:
def __init__(self, email_service):
self.email_service = email_service # Dependency is injected
def notify(self, message):
self.email_service.send_email(message)
email_service = EmailService()
notifier = UserNotifier(email_service)
notifier.notify("Welcome!")
A versão acima é flexível e permite que você insira vários serviços de mensagens; você também pode substituir EmailService por uma simulação nos testes.
Usando a estrutura do injetor de dependências
À medida que sua aplicação cresce, fica mais complicado e confuso gerenciar as dependências.
A estrutura dependency-injector estrutura dá uma abordagem organizada.
Arquitetura do provedor de contêineres
A estrutura do dependency-injector funciona com base numa arquitetura de fornecedor de contêineres.
- Embalagem: Esse é o registro central das dependências do seu aplicativo.
- Provedores: Isso define como suas dependências são criadas.
- Configuração: Isso permite que você altere as configurações e as insira nos objetos.
- Substituição: Permite substituir dependências sem alterar o código da aplicação, especialmente durante os testes.
from dependency_injector import containers, providers
# Services
class EmailService:
def send_email(self, message):
print(f"Sending email: {message}")
class UserNotifier:
def __init__(self, email_service):
self.email_service = email_service
def notify(self, message):
self.email_service.send_email(message)
# Container
class Container(containers.DeclarativeContainer):
email_service = providers.Singleton(EmailService)
user_notifier = providers.Factory(UserNotifier, email_service=email_service)
# Usage
container = Container()
notifier = container.user_notifier()
notifier.notify("Hello!")
No exemplo acima:
-
Containerdefine como as instâncias são criadas -
Singletongarante que só exista uma instância deEmailService -
Factorycria um novo objetoUserNotifiercom oEmailServiceinjetado automaticamente.
Mecanismo de fiação
Você pode usar decoradores como @inject pra reduzir a necessidade de passar dependências manualmente.
Aqui está outra versão do exemplo anterior:
from dependency_injector import containers, providers
# Define services
class EmailService:
def send_email(self, message):
print(f"Sending email: {message}")
class UserNotifier:
def __init__(self, email_service: EmailService):
self.email_service = email_service
def notify(self, message):
self.email_service.send_email(message)
# Create container
class Container(containers.DeclarativeContainer):
email_service = providers.Singleton(EmailService)
user_notifier = providers.Factory(UserNotifier, email_service=email_service)
from dependency_injector.wiring import inject, Provide
@inject
def main(notifier: UserNotifier = Provide[Container.user_notifier]):
notifier.notify("Hello!")
if __name__ == "__main__":
container = Container()
container.wire(modules=[__name__]) # This wires the current module
main()
Na versão atual;
-
Sem adicionar manualmente a dependência, o decorador `
@inject` injeta automaticamente a dependência da função ou classe. -
A classe `
Provide` diz ao `dependency-injector` qual dependência deve ser injetada.
Essa abordagem elimina a necessidade de dependências de fiação manual do contêiner.
Isso é útil em aplicações maiores, onde os serviços podem depender de vários componentes (daí a necessidade de inicializá-los automaticamente).
Usando injeção de dependência em frameworks Python populares
A maioria das estruturas Python modernas facilita o trabalho com injeção de dependência, permitindo que você escreva um código mais limpo e testável.
Nesta seção, você vai aprender como a injeção de dependência é aplicada no Flask, Django e FastAPI.
Injeção de dependência no Flask
O Flask não tem suporte integrado para injeção de dependências, mas você pode implementar isso usando a biblioteca dependency-injector seguindo esses passos.
Passo 1: Defina seus serviços
class GreetingService:
def get_greeting(self, name):
return f"Hello, {name}!"
Passo 2: Configure seu contêiner de injeção de dependências
from dependency_injector import containers, providers
class Container(containers.DeclarativeContainer):
greeting_service = providers.Factory(GreetingService)
Passo 3: Crie o aplicativo Flask e injete as dependências.
from flask import Flask, request
from dependency_injector.wiring import inject, Provide
container = Container()
app = Flask(__name__)
@app.route("/greet")
@inject
def greet(greeting_service: GreetingService = Provide[Container.greeting_service]):
name = request.args.get("name", "World")
return greeting_service.get_greeting(name)
container.wire(modules=[__name__])
if __name__ == "__main__":
app.run(debug=True)
A partir do código acima:
-
A função
name = request.args.get(“name”, “World”)pega onameda string de consulta e, se não tiver, usa”World”por padrão. -
return greeting_service.get_greeting(name)chama o método no serviço injetado e retorna uma mensagem de saudação. -
container.wire(modules=[__name__])diz ao injetor de dependências para procurar neste módulo por decoradores de dependência (@inject) e marcadores de dependência (Provide[...]) para conectá-los aos provedores reais.
Passo 4: Teste o aplicativo
Execute o aplicativo no seu terminal usando o comando python .py e acesse o URL http://localhost:5000/greet?name=Jacob.
Você deve ver o seguinte.

Injeção de dependência no Django
Assim como o Flask, o Django não oferece injeção de dependência integrada. Mas você pode usar as visualizações baseadas em classes, o middleware e a estrutura do aplicativo para integrar a injeção de dependências manualmente ou usando a biblioteca dependency-injector.
Aqui está um passo a passo para implementar a injeção de dependência no Django.
Passo 1: Defina o seu serviço
Crie um serviço simples com a lógica do seu negócio em um novo arquivo chamado “ services.py ” dentro da pasta do seu aplicativo.
# myapp/services.py
class GreetingService:
def get_greeting(self, name):
return f"Hello, {name}!"
Passo 2: Configurar o contêiner do injetor de dependências
Dentro do diretório do seu aplicativo, crie um contêiner usando a biblioteca dependency-injector dentro de um novo arquivo containers.py.
# myapp/containers.py
from dependency_injector import containers, providers
from .services import GreetingService
class Container(containers.DeclarativeContainer):
greeting_service = providers.Factory(GreetingService)
Passo 3: Criar uma visualização com dependências injetadas
Use o decorador ` @inject ` na sua visualização para receber dependências em ` views.py`.
# myapp/views.py
from django.http import HttpResponse
from dependency_injector.wiring import inject, Provide
from .containers import Container
from .services import GreetingService
@inject
def greet_view(
request, greeting_service: GreetingService = Provide[Container.greeting_service]
):
name = request.GET.get("name", "World")
message = greeting_service.get_greeting(name)
return HttpResponse(message)
Passo 4: Atualize o arquivo urls.py
Na pasta do seu projeto, vá até o arquivo urls.py e conecte o seu injetor de dependências ao sistema de roteamento de URL do Django.
from django.contrib import admin
from django.urls import path
from myapp.views import greet_view
urlpatterns = [
path("admin/", admin.site.urls),
path("greet/", greet_view),
]
Passo 5: Conecte o contêiner em apps.py
Vá até apps.py e conecte o contêiner ao aplicativo.
# myapp/apps.py
from django.apps import AppConfig
from .containers import Container
class MyAppConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "myapp"
def ready(self):
container = Container()
container.wire(modules=["myapp.views"])
Depois, vá até a configuração do seu aplicativo em INSTALLED_APPS e adicione seu aplicativo.
# settings.py
INSTALLED_APPS = [
'myapp.apps.MyAppConfig',
...
]
Passo 6: Teste a visualização
Inicie o servidor Django e acesse a visualização através da URL http://localhost:8000/greet/?name=Django.
Você deve ver o seguinte.

Injeção de dependência no FastAPI
O FastAPI já vem com suporte para injeção de dependências através do marcador especial ` Depends() `, que injeta o que quer que uma função retorne.
Aqui vai um guia passo a passo sobre como fazer a injeção de dependências no FastAPI.
Passo 1: Defina um serviço
class GreetingService:
def get_greeting(self, name: str) -> str:
return f"Hello, {name}!"
Passo 2: Crie a função de dependência
def get_greeting_service():
return GreetingService()
Passo 3: Configure o aplicativo FastAPI e use a injeção de dependência
app = FastAPI()
@app.get("/greet")
def greet(
name: str = "World", service: GreetingService = Depends(get_greeting_service)
):
return {"message": service.get_greeting(name)}
Passo 4: Executa e testa o aplicativo
Inicie o servidor usando o comando uvicorn main:app –reload e acesse o URL http://localhost:8000/greet?name=FastAPI. Você deve ver a seguinte resposta.

Comparando frameworks de injeção de dependências Python
Existem várias estruturas de dependência Python, cada uma com seus pontos fortes, sintaxe e casos de uso. Escolher a estrutura certa depende do tamanho e da organização do seu projeto.
Aqui tá uma comparação de algumas estruturas comuns de injeção de dependência Python.
|
Framework |
Tudo de bom Para |
Pontos fortes |
Limitações |
|
|
Aplicações complexas em uso na produção |
Completo, rápido e fácil de configurar |
Verbosidade |
|
Simples e ideal para aplicações mínimas |
Sintaxe limpa |
Menos avançado do que outros. |
|
|
Lógica de ligação avançada |
Ligação automática |
Mais lento por causa da introspecção |
|
|
Aplicações simples |
Minimalista e rápido |
Recursos limitados em comparação com outros |
|
|
Aplicativos FastAPI |
Suporte integrado para assíncrono e também testável |
Não reutilizável fora do FastAPI |
|
|
Aplicativos Flask |
Fácil integração com aplicativos Flask |
Depende de |
|
|
Projetos Django |
Oferece injeção de dependência para visualizações e middleware. |
Depende de |
Padrões avançados de implementação
À medida que o código da sua aplicação cresce, fica mais difícil manter a injeção de dependências.
Você pode usar a injeção de dependência avançada para lidar com tarefas como recursos no escopo da solicitação, limpeza e separação de interesses.
Dependências com escopo
As dependências com escopo permitem controlar por quanto tempo uma dependência fica ativa, por exemplo, quando você quer um novo objeto por solicitação, um objeto compartilhado durante toda a vida útil do aplicativo ou a limpeza automática de recursos, como conexões de banco de dados.
A maioria das estruturas de injeção de dependências suporta escopos como:
- Singleton: Uma instância para todo o aplicativo.
- Fábrica: Uma nova instância toda vez que é injetada.
- Local na thread ou na solicitação: Uma única instância por thread/solicitação.
- Recurso: Gerenciado com lógica de configuração e desmontagem.
Aqui vai um exemplo de dependências com escopo usando contêineres aninhados com o ` dependency-injector`.
from dependency_injector import containers, providers, resources
# A simple resource that needs setup and cleanup
class MyResource:
def __enter__(self):
print("Setting up the resource")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Cleaning up the resource")
# Create a container to manage the resource
class MyContainer(containers.DeclarativeContainer):
resource = providers.Resource(MyResource)
# Using the resource with a context manager
container = MyContainer()
with container.resource() as r:
print("Using the resource")
No exemplo acima, MyResource imita uma classe que precisa de configuração e desativação, como abrir/fechar um arquivo ou banco de dados.
O container fornece o recurso usando providers.Resource e, quando você usa with container.resource(), ele entra e sai do contexto corretamente.
Esse padrão garante que recursos, como identificadores de arquivos, conexões de banco de dados ou sessões de rede, sejam gerenciados de forma organizada.
Imagina um endpoint de API que precisa de uma sessão de banco de dados para a solicitação atual ou um logger com contexto específico da solicitação.
Com dependências com escopo, a estrutura cria um contêiner com escopo de solicitação quando a solicitação começa a resolver todas as dependências desse escopo.
Quando a solicitação termina, qualquer limpeza necessária, como fechar sessões do banco de dados, rola automaticamente. Isso garante que os estados não sejam compartilhados entre solicitações e evita vazamentos de recursos.
Injeção assíncrona
Para lidar com tarefas vinculadas a E/S de forma eficiente, você precisa de execução assíncrona. Os sistemas de injeção de dependência em frameworks como FastAPI e dependency-injector oferecem injeção assíncrona usando async/await.
async def async resources Injeção assíncrona é quando a gente injeta dependências que são funções assíncronas ou gerencia coisas assíncronas, tipo conexões de banco de dados assíncronas, APIs externas ou tarefas em segundo plano.
Em vez de resolver tudo ao mesmo tempo, o sistema de injeção de dependências espera que tudo seja resolvido antes de fazer a injeção.
Aqui vai um exemplo de dependência assíncrona no FastAPI:
from fastapi import FastAPI, Depends
app = FastAPI()
# Async dependency
async def get_user():
# Simulate async I/O
await some_async_db_query()
return {"name": "Philip Jones"}
@app.get("/profile")
async def read_profile(user: dict = Depends(get_user)):
return {"user": user}
O FastAPI cuida automaticamente da resolução assíncrona de get_user e injeta o resultado.
dependency-injector também dá suporte ao gerenciamento assíncrono do ciclo de vida usando provedores de gerenciamento de recursos ( AsyncResource ).
from dependency_injector import containers, providers, resources
class AsyncDB:
async def connect(self):
print("Connected")
return self
async def disconnect(self):
print("Disconnected")
class AsyncDBResource(resources.AsyncResource):
async def init(self) -> AsyncDB:
db = AsyncDB()
return await db.connect()
async def shutdown(self, db: AsyncDB):
await db.disconnect()
class Container(containers.DeclarativeContainer):
db = providers.Resource(AsyncDBResource)
# Usage
async def main():
container = Container()
await container.init_resources()
db = await container.db() # Get the AsyncDB instance
# Use db here...
await container.shutdown_resources()
No código acima:
-
resources.AsyncResourceé usado pra lógica de configuração/desconfiguração assíncrona. -
await container.init_resources()inicializa todos os recursos e chamainit. -
await container.shutdown_resources()limpa todos os recursos. -
await container.db()pega a instância real dos recursos, que éAsyncDB.
Usar injeção de dependência assíncrona ajuda a manter o desempenho da sua aplicação, evitando E/S síncronas em rotas assíncronas e eliminando a necessidade de aguardar manualmente as dependências na sua lógica.
Implicações de segurança
Embora a injeção de dependência melhore a modularidade e a testabilidade, ela pode trazer riscos de segurança se não for bem gerenciada.
Um risco importante é a confusão de dependências, em que pacotes maliciosos imitam os legítimos. Por exemplo, os invasores carregaram pacotes no PyPI com nomes usados em sistemas internos da empresa para enganar os aplicativos e fazê-los usar a versão maliciosa.
Para ficar seguro, nunca injete componentes não confiáveis ou controlados pelo usuário e valide as fontes de configuração, como variáveis de ambiente, antes de injetá-las.
Use os arquivos “ requirements.txt ” ou “ poetry.lock ” pra bloquear versões exatas e automatizar a verificação de segurança em caso de alterações nas dependências. Além disso, certifique-se de verificar regularmente se tem vulnerabilidades nas suas dependências.
Centralizar o controle das suas dependências também é essencial, pois garante a consistência entre as suas aplicações e facilita a aplicação de patches de segurança ou atualizações de versão. Isso ajuda a evitar “dependências ocultas” que podem aparecer de várias maneiras no código.
Tem várias ferramentas que podem detectar riscos e melhorar a sua segurança:
- Snyk: Procura vulnerabilidades conhecidas em pacotes Python e sugere correções.
- Xygeni: Oferece proteção para pipelines de CI/CD.
- Segurança: Verifica se tem pacotes inseguros e vulnerabilidades no código.
- Bandido: Um analisador de código estático para Python focado em questões de segurança.
Aplicações no mundo real
A injeção de dependência não é só um padrão teórico; ela é usada em vários sistemas de produção pra gerenciar a complexidade, melhorar a flexibilidade e simplificar os testes.
Como configurar o serviço da Web
Nas aplicações web modernas, a injeção de dependências tem um papel super importante no gerenciamento de serviços padrão, como autenticação, registro em log e acesso a bancos de dados.
Estruturas como FastAPI são super importantes pra resolver rotas e dependências.
O exemplo abaixo mostra como é uma autenticação centralizada no FastAPI.
from fastapi import Depends, HTTPException
def get_current_user(token: str = Depends(oauth2_scheme)):
user = verify_token(token)
if not user:
raise HTTPException(status_code=401)
return user
@app.get("/protected")
def protected_route(user: dict = Depends(get_current_user)):
return {"message": f"Hello {user['name']}"}
No código acima, get_current_user() é injetado como uma dependência de rota, mas a lógica para verificar o token é centralizada e reutilizável.
Você também pode fazer o mesmo para o acesso ao banco de dados, de modo que as sessões do banco de dados sejam gerenciadas e limpas automaticamente.
Aqui tá um exemplo de como você pode usar a injeção de dependência pra centralizar o acesso ao banco de dados.
from sqlalchemy.ext.asyncio import AsyncSession
async def get_db_session() -> AsyncSession:
async with async_session() as session:
yield session
@app.get("/items")
async def read_items(db: AsyncSession = Depends(get_db_session)):
return await db.execute("SELECT * FROM items")
No código acima, o get_db_session é um provedor de dependências. Quando a rota ` read_items ` é chamada, o FastAPI automaticamente injeta o parâmetro ` db `, permitindo que a rota acesse o banco de dados sem precisar gerenciar manualmente a configuração ou desativação da sessão.
Desenvolvimento orientado por testes
A injeção de dependência facilita a alteração das dependências que os componentes recebem, o que é importante durante os testes.
Você pode trocar serviços reais por simulados durante os testes,deixando seu código mais modular e fácil de testar.
O FastAPI e o dependency-injector aceitam substituir dependências na hora do teste.
Aqui tá um exemplo no FastAPI.
from fastapi.testclient import TestClient
from main import app, get_db_session
def override_db():
return TestDBSession()
app.dependency_overrides[get_db_session] = override_db
client = TestClient(app)
response = client.get("/items")
assert response.status_code == 200
No exemplo de código acima, get_db_session é substituído por um banco de dados simulado durante os testes; por isso, não é preciso corrigir ou alterar o código de produção.
O mesmo também em depedency-injector, você pode substituir seu banco de dados real por um banco de dados simulado para fins de teste, como no exemplo abaixo.
from containers import Container
def test_service_behavior():
container = Container()
container.db.override(providers.Factory(TestDB))
service = container.service()
assert service.get_data() == "mocked"
O método ` override() ` substitui a dependência real por uma simulação, que é limpa, controlada e reversível.
Aqui estão algumas estratégias que você deve usar para substituir dependências:
- Injeção do construtor: Certifique-se de passar os mocks diretamente para o construtor.
- Substituições da estrutura: Use ferramentas de substituição integradas, como
FastAPI.dependency_overridesno FastAPI oudependency_injector.override()nodependency-injector. - Jogos: Use estruturas de teste como
pytestpara criar simulações reutilizáveis e inseri-las por meio de fixtures.
Melhores práticas e anti-padrões
Embora a injeção de dependência tenha como objetivo tornar o código modular e fácil de testar, ela pode causar bugs ou tornar o código mais complexo.
O que a gente recomenda
Aqui estão algumas dicas que você deve seguir ao criar dependências:
- Programe para interfaces, não para implementações: Defina suas dependências usando classes base abstratas ou interfaces em vez de implementações complexas. Isso facilita o teste do seu código e também incentiva o uso de simulações em testes unitários.
- Prefira composição em vez de herança: Em vez de criar hierarquias de classes complicadas, monte objetos usando dependências injetadas pra manter os componentes pequenos e focados.
- Configuração centralizada de dependências: Use um único contêiner ou módulo pra definir e gerenciar dependências, facilitando a substituição e os testes.
- Evite dependências circulares: Planeje bem seu gráfico de dependências pra evitar referências circulares usando funções de fábrica ou provedores pra adiar a instanciação.
Erros comuns
Aqui estão algumas armadilhas comuns que você deve evitar ao usar injeção de dependência.
- Anti-padrão do localizador de serviços: Evite usar um contêiner global para buscar dependências dinamicamente, pois isso pode ocultar dependências e tornar o código complicado de entender e testar.
- Injeção excessiva: Evite colocar muitos serviços em uma única classe ou função pra evitar que seu código fique com construtores pesados e lógica difícil de testar.
- Gestão inadequada do escopo e desvio de recursos públicos: Certifique-se de sempre usar o escopo certo pra evitar compartilhar o estado entre usuários ou testes.
Teste de injeção de dependência em Python
A injeção de dependência facilita a inserção de objetos simulados nos seus componentes, simplificando assim os testes unitários. Isso permite separar os componentes básicos dos específicos do teste.
Com a injeção de dependência, os testes são determinísticos, não têm efeitos colaterais e resultam em uma execução mais rápida dos testes.
Aqui tá um exemplo de como você pode usar a injeção de dependência pra injetar versões simuladas, stubs ou falsas dessas dependências nos seus testes.
class EmailService:
def send_email(self, to: str, message: str): ...
class Notifier:
def __init__(self, email_service: EmailService):
self.email_service = email_service
def alert(self, user_email):
self.email_service.send_email(user_email, "Alert!")
Nos testes, troca EmailService por um mock:
class TestEmailService:
def send_email(self, to, message):
self.sent_to = to
def test_notifier_sends_email():
test_email = TestEmailService()
notifier = Notifier(test_email)
notifier.alert("test@example.com")
assert test_email.sent_to == "test@example.com"
Certifique-se de usar injeção de dependência com frequência e evite monkey patching para facilitar a manutenção e evitar alterações significativas quando nomes internos forem alterados.
Conclusão
Embora você possa não precisar de injeção de dependência no começo para projetos pequenos, conforme o projeto cresce e se expande, você pode aproveitar a estrutura e a modularidade oferecidas pela injeção de dependência.
Olhando para o futuro, a injeção de dependência em Python parece promissora, e a gente pode esperar que ela continue com um sistema de tipos melhorado e um gerenciamento de ciclo de vida assíncrono aprimorado.
Dominar a injeção de dependência é essencial para se tornar um desenvolvedor Python fluente. Mas não para por aí; muitos outros conceitos avançados podem elevar suas habilidades em Python.
Para te ajudar a acelerar sua jornada de aprendizado, aqui estão alguns dos nossos recursos que você deve conferir.
Cursos:
- Desenvolvendo pacotes Python
- Introdução ao PySpark
- Programação Orientada a Objetos em Python
- Programação Orientada a Objetos Intermediária em Python
Postagens no blog:
Instrutor experiente em ciência de dados e bioestatístico com experiência em Python, R e machine learning.
Perguntas frequentes
O que é injeção de dependência?
A injeção de dependência é um padrão de design que te ajuda a escrever um código mais limpo, criando dependências dentro de uma classe, que podem ser passadas de fora, tornando seu código mais fácil de gerenciar e modificar.
Quais são as principais vantagens da injeção de dependência?
A injeção de dependência deixa seu código modular, testável e fácil de manter.
Como posso implementar a injeção de dependência em Python?
Você pode implementar a injeção de dependência em Python manualmente ou usando bibliotecas como dependency_injector.
O que é injeção assíncrona?
async def async resources Injeção assíncrona é quando a gente injeta dependências que são funções assíncronas ou gerencia coisas assíncronas, tipo conexões de banco de dados assíncronas, APIs externas ou tarefas em segundo plano.
Quais são os riscos de segurança da injeção de dependência e como posso lidar com eles?
Um risco importante é a confusão de dependências, em que pacotes maliciosos imitam os legítimos. Para evitar isso, você pode usar ferramentas como Snyk, Xygeni, Safety ou Bandit para verificar se há vulnerabilidades no seu código e nos seus pacotes.



