Por que IoC / DI não é comum em Python?

313

No Java IoC / DI, é uma prática muito comum usada extensivamente em aplicativos da Web, quase todas as estruturas disponíveis e Java EE. Por outro lado, também existem muitas aplicações Web em Python, mas além do Zope (que ouvi dizer que deve ser realmente horrível de codificar), a IoC não parece ser muito comum no mundo Python. (Por favor, cite alguns exemplos, se você acha que estou errado).

É claro que existem vários clones de estruturas populares de Java IoC disponíveis para Python, springpython , por exemplo. Mas nenhum deles parece se acostumar praticamente. Pelo menos, nunca me deparei com um aplicativo da Web baseado em Django ou sqlalchemy + <insert your favorite wsgi toolkit here>que usa algo parecido.

Na minha opinião, a IoC tem vantagens razoáveis ​​e facilitaria a substituição do modelo django-default-user-model, por exemplo, mas o uso extensivo de classes de interface e IoC no Python parece um pouco estranho e não »pythonic«. Mas talvez alguém tenha uma explicação melhor, por que a IoC não é amplamente usada em Python.

tux21b
fonte
2
Meu palpite, mesmo motivo que ele é menos popular em Ruby, built-in mixins e aulas abertas
Sam Saffron
3
você já tentou o springpython? nem funciona como anunciado. pelo menos na parte aop. tudo o resto não é muito útil, a menos que você seja proveniente de java e precise de algum nível de conforto durante a transição.
Tom Willis
6
Por favor, tome cuidado para distinguir entre o uso de DI e o uso de uma estrutura do COI. O primeiro é um padrão de design, o último é uma estrutura para auxiliar no uso automatizado do primeiro.
Doug
Doug, acredito que você quis dizer que DI é o recurso de criação obtido com o uso do padrão Decorator.
Njappboy
4
Eu adoraria ver uma resposta que resolva os problemas do mundo real que o DI resolve: gerenciamento da vida útil, facilidade de remoção de testes, etc.
Josh Noe

Respostas:

198

Na verdade, não acho que DI / IoC seja tão incomum em Python. O que é incomum, no entanto, são estruturas / contêineres DI / IoC .

Pense nisso: o que um contêiner DI faz? Permite que você

  1. conecte componentes independentes em uma aplicação completa ...
  2. ... em tempo de execução.

Temos nomes para "ligar juntos" e "em tempo de execução":

  1. scripting
  2. dinâmico

Portanto, um contêiner de DI não é senão um intérprete para uma linguagem de script dinâmico. Na verdade, deixe-me reformular: um contêiner DI Java / .NET típico nada mais é do que um intérprete de baixa qualidade para uma linguagem de script dinâmica realmente ruim com sintaxe horrível, às vezes baseada em XML.

Quando você programa em Python, por que você gostaria de usar uma linguagem de script feia e ruim quando tem uma linguagem de script bonita e brilhante à sua disposição? Na verdade, essa é uma pergunta mais geral: quando você programa em praticamente qualquer linguagem, por que deseja usar uma linguagem de script feia e ruim quando tem o Jython e o IronPython à sua disposição?

Então, para recapitular: a prática de DI / IoC é tão importante em Python quanto em Java, exatamente pelas mesmas razões. A implementação do DI / IoC, no entanto, é incorporada à linguagem e geralmente é tão leve que desaparece completamente.

(Aqui está um breve resumo de uma analogia: na montagem, uma chamada de sub-rotina é muito importante - você precisa salvar as variáveis ​​locais e os registros na memória, salvar o endereço de retorno em algum lugar, alterar o ponteiro da instrução para a sub-rotina que você está chamando, organize para que, de alguma forma, volte à sua sub-rotina quando terminar, coloque os argumentos em algum lugar onde o receptor possa encontrá-los, etc. IOW: em assembly, "chamada de subrotina" é um padrão de design e antes havia idiomas como Para o Fortran que tinha chamadas de sub-rotina integradas, as pessoas estavam criando suas próprias "estruturas de sub-rotina". Você diria que as chamadas de sub-rotina são "incomuns" no Python, apenas porque você não usa estruturas de sub-rotina?)

BTW: para um exemplo de como se parece a tomar DI à sua conclusão lógica, dê uma olhada Gilad Bracha 's Novilíngua Linguagem de programação e seus escritos sobre o assunto:

Jörg W Mittag
fonte
58
Enquanto eu concordo. O comentário XML está errado. Muitos (pelo menos os modernos) contêineres IOC usam convenção (código) sobre configuração (XML).
Finglas
20
Não há nada que impeça que você escreva a fiação explicitamente em Java, mas como você tem mais e mais serviços, as dependências ficam mais complexas. Um contêiner de DI é como Make: você declara as dependências e o contêiner as inicializa na ordem correta. Guice é uma estrutura Java DI em que tudo é escrito em código Java. Ao escrever declarativa um recipiente DI também adiciona suporte para pós processamento dos declerations antes da inicialização (por exemplo, substituir espaços reservados de propriedade com valores reais)
IttayD
133
"A implementação do DI / IoC, no entanto, está embutida na linguagem e geralmente é tão leve que desaparece completamente". Voto negativo, porque isso é categoricamente falso. DI é um padrão em que uma interface é passada para o construtor. Não está embutido no python.
Doug
146
downvote, fiação juntos não tem nada a ver com scripting, DI é um padrão, e não é equivalente a scripting
Luxspes
38
Eu discordo disso. O DI não resolve a falta de scripts dinâmicos em linguagens estáticas. Ele fornece uma estrutura para configurar e compor as partes do seu aplicativo. Certa vez, ouvi um desenvolvedor Ruby dizer que o DI não é necessário em linguagens dinâmicas. Mas ele usou o Rails ... O Rails é apenas um grande tipo de contêiner de DI, que usa convenção para descobrir quais partes configurar quando. Ele não precisava de DI porque Rails resolveu o problema de encontrar as peças para ele.
Brian Genisio
51

Parte disso é a maneira como o sistema de módulos funciona em Python. Você pode obter uma espécie de "singleton" de graça, apenas importando-o de um módulo. Defina uma instância real de um objeto em um módulo e, em seguida, qualquer código de cliente pode importá-lo e obter um objeto funcional, totalmente construído / preenchido.

Isso contrasta com o Java, onde você não importa instâncias reais de objetos. Isso significa que você sempre precisará instancia-los você mesmo (ou usar algum tipo de abordagem no estilo IoC / DI). Você pode atenuar o incômodo de ter que instanciar tudo sozinho usando métodos estáticos de fábrica (ou classes reais de fábrica), mas ainda incorre na sobrecarga de recursos para criar novos a cada vez.

TM.
fonte
2
Isso faz sentido. Se eu quiser alterar uma implementação em Python, simplesmente importo de um local diferente usando o mesmo nome. Mas agora estou pensando se também é possível o contrário, definindo uma MyClassInstancesclasse para cada uma MyClassem Java, que contém apenas instâncias estáticas e totalmente inicializadas. Isso seria conectado: D
tux21b
2
E outra idéia: fornecer uma maneira de alterar essas importações em python tornaria possível substituir implementações facilmente sem tocar em todos os arquivos python. Em vez disso from framework.auth.user import User , seria melhor escrever User = lookup('UserImplentation', 'framework.auth.user.User')(o segundo parâmetro pode ser um valor padrão) dentro da estrutura. Em seguida, os usuários da estrutura poderão substituir / especializar a Userimplementação sem tocar na estrutura.
Tux21b
14
Simplificando, responda, na vida real, você raramente precisa apenas de "um singleton", precisa controlar o escopo (pode ser necessário um singleton local de thread ou um singleton de sessão e assim por diante), isso me faz pensar que esse tipo de problema resolvido em Python não são o tipo de problemas do mundo real realmente resolvido em um ambiente empresarial
Luxspes
3
Na verdade, o DI é capaz de testar e desacoplar dependências de código. Além disso, o recurso de importação é semelhante às importações estáticas em Java, que permitem importar uma única instância de um objeto.
Richard Warburton 28/11
1
"Você pode obter uma espécie de" singleton "gratuitamente, apenas importando-o de um módulo." Pode ser facilmente feito em Java, declarando um campo de instância estático e configurando-o como um valor. Este não é um sol
ggranum
45

IoC e DI são super comuns em código Python maduro. Você simplesmente não precisa de uma estrutura para implementar o DI, graças à digitação do duck.

O melhor exemplo é como você configura um aplicativo Django usando settings.py:

# settings.py
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': REDIS_URL + '/1',
    },
    'local': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'snowflake',
    }
}

O Django Rest Framework utiliza DI intensamente:

class FooView(APIView):
    # The "injected" dependencies:
    permission_classes = (IsAuthenticated, )
    throttle_classes = (ScopedRateThrottle, )
    parser_classes = (parsers.FormParser, parsers.JSONParser, parsers.MultiPartParser)
    renderer_classes = (renderers.JSONRenderer,)

    def get(self, request, *args, **kwargs):
        pass

    def post(self, request, *args, **kwargs):
        pass

Deixe-me lembrar ( fonte ):

"Injeção de dependência" é um termo de 25 dólares para um conceito de 5 centavos. [...] Injeção de dependência significa atribuir a um objeto suas variáveis ​​de instância. [...]

Max Malysh
fonte
8
+1. Bem colocado. Sendo um programador Python, fiquei completamente perplexo com toda uma apresentação de entrevista sobre estruturas de DI em C #. Demorei um pouco para perceber que eu já fazia isso o tempo todo nos aplicativos Flask sem sequer pensar nisso, porque você não precisa de uma estrutura. Para alguém que não sabe nada além de C # / Java, a pergunta faz sentido. Para programadores de linguagem tipográficos, é natural e, como você diz, "termo de 25 dólares por um conceito de 5 centavos".
Samuel Harmer
5
err ... isso não é injeção de dependência, pois as instâncias ( IsAuthenticated, ScopedRateThrottle) são instanciadas pela classe. Eles não são passados ​​para o construtor.
Dopatraman 7/07/19
5
IsAuthenticatede ScopedRateThrottlenão são instâncias, são classes. Eles são instanciados quando um FooView é construído (na verdade, quando o FooView processa uma solicitação). Enfim, isso é apenas um detalhe de implementação. IsAuthenticatede ScopedRateThrottlesão as dependências; eles são injetados no FooView. Não importa quando ou como isso é feito. Python não é Java, portanto, existem diferentes maneiras de implementar isso.
Max Malysh
3
@MaxMalysh Eu concordo com o dopatraman neste. Isso nem é IoC, pois a própria classe possui dependências "codificadas" para uma classe específica. Na IoC, a dependência deve ser fornecida em vez de codificada. Além disso, em Injeção de Dependências, você terá uma entidade responsável por gerenciar os ciclos de vida de cada serviço e os injetará quando for o caso. A solução fornecida em nenhum deles.
Ricardo Alves
3
@alex Não, você não precisa alterar seu código para usar outro renderizador. Você ainda pode usar vários prestadores simultaneamente: renderer_classes = (JSONRenderer, BrowsableAPIRenderer, XMLRenderer). Zombar é tão simples quanto @unittest.patch('myapp.views.FooView.permission_classes'). Uma necessidade desesperada de "passar alguma coisa" é uma conseqüência da "maneira de fazer as coisas do Java", devido ao fato de o Java ser uma linguagem compilada e com estaticamente tipicamente sem grandes recursos de metaprogramação.
Max Malysh 14/04
35

O Django faz um ótimo uso da inversão de controle. Por exemplo, o servidor de banco de dados é selecionado pelo arquivo de configuração e, em seguida, a estrutura fornece instâncias apropriadas de wrapper do banco de dados para os clientes do banco de dados.

A diferença é que o Python tem tipos de primeira classe. Os tipos de dados, incluindo classes, são objetos. Se você quiser que algo use uma classe específica, simplesmente nomeie a classe. Por exemplo:

if config_dbms_name == 'postgresql':
    import psycopg
    self.database_interface = psycopg
elif config_dbms_name == 'mysql':
    ...

O código posterior pode criar uma interface de banco de dados escrevendo:

my_db_connection = self.database_interface()
# Do stuff with database.

Em vez das funções de fábrica padrão que Java e C ++ precisam, o Python faz isso com uma ou duas linhas de código comum. Essa é a força da programação funcional versus imperativa.

Daniel Newby
fonte
4
O que você chama de código é na verdade a parte da fiação. Esse seria o XML da sua estrutura ioc. Na verdade, poderia ser escrito simplesmente como import psycopg2 as database_interface. Coloque essa linha em um injections.pyet voilà.
espectros
29
Erm. O que você está fazendo lá é praticamente imperativo Daniel.
precisa
Definitivamente, é um código imperativo, mas é funcional porque usa um valor que pode ser chamado.
Jeremy
5
Mas não são apenas as funções de primeira classe? pt.wikipedia.org/wiki/First-class_function Só porque você os usa e não os utiliza, não torna seu código funcional. Existem alguns efeitos colaterais acontecendo aqui (como a mudança self.database_interface), que gritam imperativos.
precisa saber é
15

Parece que as pessoas realmente não entendem mais o que significa injeção de dependência e inversão de controle.

A prática de usar inversão de controle é ter classes ou funções que dependam de outras classes ou funções, mas, em vez de criar instâncias na classe de código de função, é melhor recebê-lo como parâmetro, para que o acoplamento solto possa ser arquivado. Isso tem muitos benefícios como mais testabilidade e arquivar o princípio de substituição liskov.

Veja que, trabalhando com interfaces e injeções, seu código fica mais fácil de manutenção, pois você pode alterar o comportamento facilmente, porque não precisará reescrever uma única linha de código (talvez uma ou duas linhas na configuração DI) de seu para alterar seu comportamento, pois as classes que implementam a interface que sua classe está esperando podem variar de forma independente, desde que sigam a interface. Uma das melhores estratégias para manter o código dissociado e fácil de manter é seguir pelo menos os princípios de responsabilidade única, substituição e inversão de dependência.

Para que serve uma biblioteca de DI se você pode instanciar um objeto dentro de um pacote e importá-lo para injetar você mesmo? A resposta escolhida é correta, uma vez que o java não possui seções processuais (código fora das classes), tudo o que entra em xmls da configuração chata, daí a necessidade de uma classe instanciar e injetar dependências em um estilo de carregamento lento para que você não se estrague seu desempenho, enquanto em python você apenas codifica as injeções nas seções "procedurais" (código fora das classes) do seu código

jhonatan teixeira
fonte
você ainda sente falta de que um IoC / DI conecte os objetos automaticamente. Não é muito capaz de fazê-lo em tempo de execução (o Java pode fazer isso por meio da reflexão), é que a estrutura cuida disso e você não precisa fazê-lo explicitamente. Ter seções de procedimentos também é irrelevante, nada impede que se escreva um aplicativo inteiramente de procedimentos em Java, usando classes como meros contêineres de sub-rotinas e funções estáticas, sem usar recursos de OOP.
zakmck 11/01
@zakmck: a seção "procedural" do Python aqui não é sobre escrever código processual. O que torna a seção "procedural" do Python diferente das linguagens estáticas é a capacidade de colocar código processual em um corpo de classe, que é executado durante o tempo de definição de classe, e colocar instruções de importação dentro da instrução if, e criar fábrica de classes simplesmente definindo classes dentro de um método de fábrica. Essas são coisas que você realmente não pode fazer em linguagens estáticas e resolve a maioria dos problemas que o IOC / DI tentou resolver. A metaprogramação no Python geralmente se parece com o código regular do Python.
Lie Ryan
@LieRyan, você pode fazer isso com reflexão ou, se precisar com frequência ou em tempo de execução, pode chamar a linguagem estática de outra linguagem como Groovy (que foi projetada para jogar facilmente com Java) ou até o próprio Python. No entanto, isso tem pouco a ver com estruturas de IoC / DI, pois sua finalidade é fazer a maior parte da fiação de objetos procedurais para você, automaticamente, aproveitando apenas as definições. Infelizmente, a maioria das respostas aqui mencionadas não atendem a esse ponto.
zakmck 20/01
12

Não uso o Python há vários anos, mas eu diria que ele tem mais a ver com ser uma linguagem de tipo dinâmico do que qualquer outra coisa. Para um exemplo simples, em Java, se eu quisesse testar se alguma coisa foi escrita corretamente, eu poderia usar o DI e passar qualquer PrintStream para capturar o texto que está sendo escrito e verificá-lo. No entanto, quando estou trabalhando no Ruby, posso substituir dinamicamente o método 'puts' no STDOUT para verificar, deixando o DI completamente fora de cena. Se o único motivo pelo qual estou criando uma abstração é testar a classe que está sendo usada (pense nas operações do sistema de arquivos ou no relógio em Java), o DI / IoC cria complexidade desnecessária na solução.

bcarlso
fonte
3
Nunca deixa de me surpreender que pessoas dispostas a mudar a forma como um sistema funciona para testar se ele funcionou. Agora você precisa testar se seus testes não causam efeitos colaterais.
Basic
2
ele fala sobre a mudança de método put no escopo de testes, é como um método simulado de objeto injetado.
dpa 24/11
2
@ Básico que é bastante normal em testes de unidade , na verdade é recomendável fazer isso nesses testes, pois você não deseja poluir a cobertura de seu caso de teste com mais de um bloco de código (o que está sendo testado). Seria errado fazer isso nos testes de integração, talvez seja a isso que você está se referindo no seu comentário?
samuelgrigolato 14/01
1
Para mim, a testabilidade é uma preocupação de primeira classe. Se um design não é testável, não é um bom design e não tenho problemas em alterar o design para torná-lo mais testável. Terei que revalidar que ainda funciona, mas tudo bem. A testabilidade é uma razão perfeitamente válida para alterar o código IMO
Carlos Rodriguez
10

Na verdade, é muito fácil escrever código suficientemente limpo e compacto com DI (eu me pergunto, será / permanecerá) pitonico , mas de qualquer maneira :)), por exemplo, eu realmente percebo essa maneira de codificar:

def polite(name_str):
    return "dear " + name_str

def rude(name_str):
    return name_str + ", you, moron"

def greet(name_str, call=polite):
    print "Hello, " + call(name_str) + "!"

_

>>greet("Peter")
Hello, dear Peter!
>>greet("Jack", rude)
Hello, Jack, you, moron!

Sim, isso pode ser visto apenas como uma forma simples de parametrizar funções / classes, mas funciona. Portanto, talvez as baterias incluídas no padrão do Python também sejam suficientes aqui.

PS: Também publiquei um exemplo maior dessa abordagem ingênua na avaliação dinâmica da lógica booleana simples em Python .

mlvljr
fonte
3
Para casos simples que podem funcionar, imagine um controlador simples de blog, que usa vários modelos (publicação, comentário, usuário). Se você deseja que o usuário injete seu próprio modelo de postagem (com um atributo adicional de número de visualizações para rastreá-lo), e seu próprio modelo de usuário com mais informações de perfil e assim por diante, todos os parâmetros podem parecer confusos. Além disso, o usuário também pode querer alterar o objeto Request, para dar suporte à sessão do sistema de arquivos, em vez de uma sessão simples baseada em cookie ou algo assim ... Então, você acabará com muitos parâmetros em breve.
tux21b
1
@ tux21b Bem, há "complexidade essencial" que os usuários desejam que o aplicativo implemente, há soluções arquiteturais para ele (algumas das quais não são piores que as demais em termos de desenvolvimento e, possivelmente, tempo de manutenção, velocidade de execução etc.) ) e existe a capacidade humana de compreender a arquitetura da API e do software. Se não existe uma solução compreensível para o ser humano (não apenas entre aqueles que usam (qualquer forma de) DI) ... bem, quem disse que todos os problemas são solucionáveis? E ter muitos parâmetros atribuídos por padrão (mas que podem ser trocados por opção do usuário) pode ser suficiente.
mlvljr
9

IoC / DI é um conceito de design, mas, infelizmente, geralmente é tomado como um conceito que se aplica a certos idiomas (ou sistemas de digitação). Eu adoraria ver os contêineres de injeção de dependência se tornarem muito mais populares no Python. Existe o Spring, mas essa é uma superestrutura e parece ser uma porta direta dos conceitos Java sem muita consideração pelo "The Python Way".

Dadas as anotações no Python 3, decidi fazer um crack em um contêiner de injeção de dependência com todos os recursos, mas simples: https://github.com/zsims/dic . Ele é baseado em alguns conceitos de um contêiner de injeção de dependência do .NET (que IMO é fantástico se você estiver jogando nesse espaço), mas sofreu alterações nos conceitos do Python.

zsims
fonte
6

Acho que devido à natureza dinâmica das pessoas em python, muitas vezes não vêem a necessidade de outra estrutura dinâmica. Quando uma classe é herdada do 'objeto' de novo estilo, você pode criar uma nova variável dinamicamente ( https://wiki.python.org/moin/NewClassVsClassicClass ).

ie, em python simples:

#application.py
class Application(object):
    def __init__(self):
        pass

#main.py
Application.postgres_connection = PostgresConnection()

#other.py
postgres_connection = Application.postgres_connection
db_data = postgres_connection.fetchone()

No entanto, dê uma olhada em https://github.com/noodleflake/pyioc. Isso pode ser o que você está procurando.

ie em pyioc

from libs.service_locator import ServiceLocator

#main.py
ServiceLocator.register(PostgresConnection)

#other.py
postgres_connection = ServiceLocator.resolve(PostgresConnection)
db_data = postgres_connection.fetchone()
Martin Swanepoel
fonte
2
O fato de ambas as versões usarem a mesma quantidade de código ajuda bastante a explicar por que o uso de uma estrutura não é muito popular.
espectros
Na other.pylinha 1, há uma resolução de dependência automatizada, mas não contaria isso como uma injeção de dependência.
andho
Localizadores de serviço geralmente são um anti-padrão, apenas dizendo.
PmanAce 21/02
6

Apoio a resposta "Jörg W Mittag": "A implementação do DI / IoC em Python é tão leve que desaparece completamente".

Para fazer backup dessa declaração, dê uma olhada no famoso exemplo de Martin Fowler portado de Java para Python: Python: Design_Patterns: Inversion_of_Control

Como você pode ver no link acima, um "Contêiner" em Python pode ser escrito em 8 linhas de código:

class Container:
    def __init__(self, system_data):
        for component_name, component_class, component_args in system_data:
            if type(component_class) == types.ClassType:
                args = [self.__dict__[arg] for arg in component_args]
                self.__dict__[component_name] = component_class(*args)
            else:
                self.__dict__[component_name] = component_class
emilmont
fonte
42
Isso fica muito aquém dos contêineres DI mais fracos. Onde está o gerenciamento vitalício, a resolução de dependência recursiva, a capacidade de zombar ou - na falta de tudo isso - a configuração? Isso nada mais é do que uma pesquisa de tipo e cache que não é a mesma coisa que IoC.
Basic
2
Anos atrás, escrevi uma pequena estrutura de DI usando metaclasses como exercício. A coisa toda é um único arquivo com zero importações e documentos que o tornam auto-explicativo. Isso mostra que os recursos básicos não são tão difíceis de implementar de uma maneira que é até "pitônica", mas sinceramente acho que é triste que nenhuma solução completa tenha tido uma grande tração como a Spring em Java e todo mundo está fazendo arquiteturas de plugins personalizadas.
Andrea Ratto
2

Meus 2 centavos é que, na maioria dos aplicativos Python, você não precisa e, mesmo que precise, é provável que muitos haters Java (e violadores incompetentes que acreditam ser desenvolvedores) considerem isso algo ruim, apenas porque é popular em Java .

Um sistema IoC é realmente útil quando você possui redes complexas de objetos, onde cada objeto pode ser uma dependência de vários outros e, por sua vez, ser dependente de outros objetos. Nesse caso, convém definir todos esses objetos uma vez e ter um mecanismo para reuni-los automaticamente, com base no maior número possível de regras implícitas. Se você também possui uma configuração a ser definida de maneira simples pelo usuário / administrador do aplicativo, esse é um motivo adicional para desejar um sistema IoC que possa ler seus componentes a partir de algo como um arquivo XML simples (que seria a configuração).

O aplicativo típico do Python é muito mais simples, apenas um monte de scripts, sem uma arquitetura tão complexa. Pessoalmente, estou ciente do que realmente é uma IoC (ao contrário dos que escreveram certas respostas aqui) e nunca senti a necessidade disso em minha experiência limitada em Python (também não uso o Spring em todos os lugares, não quando as vantagens não justifica a sobrecarga de desenvolvimento).

Dito isto, há situações em Python em que a abordagem de IoC é realmente útil e, de fato, li aqui que o Django a usa.

O mesmo raciocínio acima pode ser aplicado à Programação Orientada a Aspectos no mundo Java, com a diferença de que o número de casos em que a AOP realmente vale a pena é ainda mais limitado.

zakmck
fonte
Existe um URL de referência para a fonte de informação onde o django usa IoC?
Sajuuk
@ Sarajuk, eu aprendi isso sobre o Django no tópico desta pergunta, então eu não sei, você deve perguntar aos outros autores de resposta.
Zakmck #
O primeiro alinea desta resposta agrega valor 0 na minha opinião ... Acho que sou capaz de decidir quando meu código python se beneficiaria da IoC e não me importo com o que o desenvolvedor pensa que é ruim. Eu valorizo ​​o pragmatismo em detrimento de opiniões sem fundamento.
Mike de Klerk
@MikedeKlerk, minha sugestão é que algo que é ao mesmo tempo desconhecido (como muitas respostas aqui provam) e vítima de preconceito dificilmente se tornará popular, não importa o quão objetivo e bem informado alguns sejam. E, é claro, não tenho certeza de que essa é uma razão pela qual você não vê muitos usos de IoC em Python. Acho que a principal razão é que aplicativos de baixa / média compexidade não precisam deles.
zakmck
The typical Python application is much simpler, just a bunch of scripts, without such a complex architecture.- uma suposição
hyankov 06/01
1

acessórios pytest todos baseados em DI ( fonte )

Meng Zhao
fonte
-1

Eu concordo com o @Jorg no ponto em que o DI / IoC é possível, mais fácil e ainda mais bonito em Python. O que falta são as estruturas que o suportam, mas existem algumas exceções. Para apontar alguns exemplos que me vêm à mente:

  • Os comentários do Django permitem que você conecte sua própria classe Comment com sua lógica e formulários personalizados. [Mais informações]

  • O Django permite que você use um objeto Profile personalizado para anexar ao seu modelo de usuário. Isso não é completamente IoC, mas é uma boa abordagem. Pessoalmente, eu gostaria de substituir o modelo de usuário do furo como a estrutura de comentários. [Mais informações]

santiagobasulto
fonte
-3

Na minha opinião, coisas como injeção de dependência são sintomas de uma estrutura rígida e excessivamente complexa. Quando o corpo principal do código se torna pesado demais para mudar com facilidade, você precisa escolher pequenas partes dele, definir interfaces para eles e permitir que as pessoas alterem o comportamento por meio dos objetos que se conectam a essas interfaces. Tudo bem, mas é melhor evitar esse tipo de complexidade em primeiro lugar.

É também o sintoma de uma linguagem de tipo estaticamente. Quando a única ferramenta que você precisa para expressar a abstração é a herança, é isso que você usa em qualquer lugar. Dito isto, o C ++ é bastante semelhante, mas nunca captou o fascínio por Builders e Interfaces em todos os lugares que os desenvolvedores Java fizeram. É fácil ficar exuberante com o sonho de ser flexível e extensível ao custo de escrever muito código genérico com pouco benefício real . Eu acho que é uma coisa cultural.

Normalmente, acho que as pessoas Python estão acostumadas a escolher a ferramenta certa para o trabalho, que é um todo coerente e simples, em vez da Única Ferramenta Verdadeira (com Mil Plugins Possíveis) que pode fazer qualquer coisa, mas oferece uma variedade desconcertante de possíveis permutações de configuração . Ainda existem partes intercambiáveis, quando necessário, mas sem a necessidade do grande formalismo da definição de interfaces fixas, devido à flexibilidade da digitação de patos e à relativa simplicidade da linguagem.

Kylotan
fonte
4
Não é tanto a estrutura, mas a própria linguagem. Para criar o tipo de flexibilidade que as linguagens de digitação de pato desfrutam, as linguagens de tipo estaticamente precisam de estruturas e regras muito sofisticadas. DI é uma dessas regras. O pessoal do Python não pensa duas vezes. O pessoal de Java precisa realmente trabalhar nisso.
S.Lott
6
@ S.Lott - Eu concordo totalmente com você, exceto que as pessoas em C ++ parecem sobreviver sem a explosão dos padrões de design e arquitetura, apesar de trabalhar com restrições semelhantes às do Java. Eu acho que isso implica uma diferença cultural em que, ao se deparar com duas maneiras possíveis de fazer algo, o pessoal de Java prefere extrair outra interface para facilitar o padrão de estratégia, enquanto o pessoal de C ++ mergulha e adiciona uma instrução bool e if ...
Kylotan
3
@Finglas, por isso, se eu tiver uma dúzia de classes usando a minha EmailSendere decidir substituí-la por uma DesktopNotifier, tenho que editar 12 classes manualmente. E você acha que é mais simples e limpo que basta escrever em uma INotifierinterface e deixar o contêiner trabalhar com os detalhes?
Basic
1
Infelizmente, um certo nível de complexidade é uma realidade que os desenvolvedores profissionais de software devem enfrentar. Vejo críticas, mas não há soluções nesta resposta. Qual é a solução "pitônica" para esse problema: estou escrevendo uma biblioteca e desejo fornecer um gancho para o log (algo como o PSR-3 LoggerInterface do PHP). Eu sei como usar os níveis de log, mas não me importo como o programa os relata. Qual é a maneira limpa de permitir que o aplicativo cliente injete esses detalhes de implementação. Nota: outras partes do aplicativo podem ter implementações diferentes dessa interface.
Rob Rob
2
Minha pergunta para você não é como você usa a biblioteca de log padrão, nem sobre a criação de instâncias diferentes de uma classe de logger. Minha pergunta é como você configura seu aplicativo para que diferentes partes dele possam usar implementações diferentes e não se preocuparem com esses detalhes (desde que eles saibam usar a interface). Esse é um problema muito real que o DI resolveu para vários aplicativos PHP em que trabalhei. Estou procurando o equivalente em python. E sugerir "simplesmente não torne sua aplicação tão complexa" não é a resposta que estou procurando.
Rob Rob
-5

Ao contrário da forte natureza tipada em Java. O comportamento de digitação de pato do Python facilita a passagem de objetos.

Os desenvolvedores de Java estão focados na construção da estrutura de classe e na relação entre objetos, mantendo as coisas flexíveis. A IoC é extremamente importante para conseguir isso.

Os desenvolvedores de Python estão focados em fazer o trabalho. Eles apenas ligam as aulas quando precisam. Eles nem precisam se preocupar com o tipo de classe. Contanto que possa grasnar, é um pato! Essa natureza não deixa espaço para a IoC.

Jason Ching
fonte
4
Você ainda precisa encontrar algo que grasna.
andho