Perché IoC / DI non è comune in Python?


313

In Java IoC / DI è una pratica molto comune che viene ampiamente utilizzata nelle applicazioni Web, quasi tutti i framework disponibili e Java EE. D'altra parte, ci sono anche molte grandi applicazioni Web Python, ma a parte Zope (che ho sentito dovrebbe essere davvero orribile da codificare) l'IoC non sembra essere molto comune nel mondo Python. (Per favore, nomina alcuni esempi se pensi che mi sbagli).

Esistono ovviamente diversi cloni di famosi framework IoC Java disponibili per Python, ad esempio springpython . Ma nessuno di loro sembra abituarsi praticamente. Almeno, non mi sono mai imbattuto in un'applicazione web basata su Django o sqlalchemy + <insert your favorite wsgi toolkit here>che utilizza qualcosa del genere.

A mio avviso, l'IoC presenta vantaggi ragionevoli e semplificherebbe la sostituzione del modello django-default-user, ad esempio, ma l'uso estensivo di classi di interfaccia e IoC in Python sembra un po 'strano e non "pythonic". Ma forse qualcuno ha una spiegazione migliore, perché l'IoC non è ampiamente usato in Python.


2
Suppongo, stessa ragione per cui è meno popolare in Ruby, mixin integrati e classi aperte
Sam Saffron

3
hai mai provato Springpython? non funziona nemmeno come pubblicizzato. almeno nella parte superiore. tutto il resto non è molto utile se non vieni da Java e hai bisogno di un certo livello di conforto durante la transizione.
Tom Willis,

6
Si prega di fare attenzione a distinguere tra l'uso di DI e l'uso di un framework IOC. Il primo è un modello di progettazione, il secondo è un framework per facilitare l'uso automatizzato del primo.
Doug,

Doug, credo che tu intendessi dire che DI è la funzione creazionale che si ottiene usando il modello Decorator.
njappboy,

4
Mi piacerebbe vedere una risposta che affronti i problemi del mondo reale che DI risolve: gestione della vita, facilità di test stubbing, ecc. Se c'è un modo più Pythonic per affrontare questi, sono tutto orecchie.
Josh Noe,

Risposte:


198

In realtà non penso che DI / IoC siano così rari in Python. Ciò che è insolito, tuttavia, sono i framework / container DI / IoC .

Pensaci: cosa fa un contenitore DI? Te lo permette

  1. collega componenti indipendenti in un'applicazione completa ...
  2. ... in fase di esecuzione.

Abbiamo nomi per "cablaggio insieme" e "in fase di esecuzione":

  1. scripting
  2. dinamico

Quindi, un contenitore DI non è altro che un interprete per un linguaggio di script dinamico. In realtà, lascia che lo riformuli: un tipico contenitore DI Java / .NET non è altro che un brutto interprete per un linguaggio di scripting dinamico davvero brutto con una sintassi brutta, a volte basata su XML.

Quando programmi in Python, perché dovresti voler usare un brutto e brutto linguaggio di scripting quando hai un linguaggio di scripting bello e brillante a tua disposizione? In realtà, questa è una domanda più generale: quando programmi in quasi tutte le lingue, perché dovresti usare un brutto e brutto linguaggio di scripting quando hai Jython e IronPython a tua disposizione?

Quindi, per ricapitolare: la pratica di DI / IoC è altrettanto importante in Python come in Java, esattamente per gli stessi motivi. L' implementazione di DI / IoC, tuttavia, è integrata nel linguaggio e spesso così leggera da svanire completamente.

(Ecco un breve accenno per un'analogia: nell'assemblaggio, una chiamata di subroutine è un affare piuttosto importante: devi salvare le variabili locali e i registri in memoria, salvare l'indirizzo di ritorno da qualche parte, cambiare il puntatore delle istruzioni alla subroutine che stai chiamando, fai in modo che salti in qualche modo nella tua subroutine quando è finita, metti gli argomenti da qualche parte in cui la chiamata può trovarli, e così via. IOW: nell'assemblaggio, "chiamata alla subroutine" è un modello di progettazione, e prima che esistessero lingue come Fortran che aveva chiamate subroutine incorporate, la gente stava costruendo i propri "framework subroutine". Diresti che le chiamate subroutine sono "non comuni" in Python, solo perché non usi i framework subroutine?)

BTW: per un esempio di quello che sembra a prendere DI alla sua logica conclusione, dare un'occhiata a Gilad Bracha 's Neolingua linguaggio di programmazione ed i suoi scritti sul tema:


58
Mentre sono d'accordo. Il commento XML è sbagliato. Molti (almeno i moderni) contenitori IOC usano la convenzione (codice) sulla configurazione (XML).
Finglas,

20
Non c'è nulla che ti impedisca di scrivere esplicitamente il cablaggio in Java, ma poiché hai sempre più servizi, le dipendenze diventano più complesse. Un contenitore DI è come Crea: dichiari le dipendenze e il contenitore le inizializza nel giusto ordine. Guice è un framework DI Java in cui tutto è scritto nel codice Java. Scrivendo in modo dichiarativo un contenitore DI aggiunge anche il supporto per la post-elaborazione delle declerazioni prima dell'inizializzazione (ad esempio, sostituire i segnaposto delle proprietà con i valori effettivi)
IttayD

133
"L'implementazione di DI / IoC, tuttavia, è integrata nel linguaggio e spesso così leggera da svanire completamente". Votazione negativa perché questo è categoricamente falso. DI è un modello in cui un'interfaccia viene passata al costruttore. Non è integrato in Python.
Doug,

146
downvote, il cablaggio insieme non ha nulla a che fare con lo scripting, DI è un modello e non è equivalente allo scripting
Luxspes,

38
Non sono d'accordo con questo. DI non risolve la mancanza di script dinamici in linguaggi statici. Fornisce un framework per la configurazione e la composizione delle parti dell'applicazione. Una volta ho sentito un dev di Ruby dire che DI non è necessario nei linguaggi dinamici. Ma ha usato Rails ... Rails è solo un grosso contenitore DI, che usa la convenzione per capire quali parti configurare quando. Non aveva bisogno di DI perché Rails ha risolto il problema di trovare le parti per lui.
Brian Genisio,

51

Parte di esso è il modo in cui il sistema di moduli funziona in Python. Puoi ottenere una sorta di "singleton" gratuitamente, semplicemente importandolo da un modulo. Definire un'istanza effettiva di un oggetto in un modulo, quindi qualsiasi codice client può importarlo e ottenere effettivamente un oggetto funzionante, completamente costruito / popolato.

Ciò è in contrasto con Java, dove non si importano istanze effettive di oggetti. Ciò significa che devi sempre istanziarli tu stesso (o utilizzare una sorta di approccio in stile IoC / DI). Puoi mitigare il fastidio di dover istanziare tutto da solo disponendo di metodi factory statici (o classi factory effettive), ma poi incorri ancora nel sovraccarico di risorse di crearne di nuovi ogni volta.


2
Questo ha senso. Se voglio cambiare un'implementazione in Python, devo semplicemente importare da una posizione diversa usando lo stesso nome. Ma ora sto pensando se è anche possibile viceversa definendo una MyClassInstancesclasse per ciascuno MyClassin Java, che contiene solo istanze statiche e completamente inizializzate. Sarebbe cablato: D
tux21b

2
E un'altra idea: fornire un modo per modificare tali importazioni in Python consentirebbe di sostituire facilmente le implementazioni senza toccare tutti i file Python. Invece from framework.auth.user import User potrebbe essere meglio scrivere User = lookup('UserImplentation', 'framework.auth.user.User')(il secondo parametro potrebbe essere un valore predefinito) all'interno del framework. Quindi gli utenti del framework sarebbero in grado di sostituire / specializzare l' Userimplementazione senza toccare il framework.
tux21b,

14
Semplificazione eccessiva, risposta, nella vita reale, raramente hai bisogno solo di "un singleton", devi controllare l'ambito (potresti aver bisogno di un thread singleton locale, o un singleton di sessione e così via), questo mi fa pensare che il tipo di problemi risolti in Python non sono il tipo di problemi del mondo reale effettivamente risolti in un contesto aziendale
Luxspes,

3
In realtà DI è in grado di testare e disaccoppiare dipendenze di codice. Anche la funzione di importazione è simile alle importazioni statiche in Java, che mi permettono di importare una singola istanza di un oggetto.
Richard Warburton,

1
"Puoi ottenere una sorta di" singleton "gratuitamente, semplicemente importandolo da un modulo." Può essere facilmente eseguito in Java dichiarando un campo di istanza statico e impostandolo su un valore. Questo non è un sol
ggranum

45

IoC e DI sono super comuni nel codice Python maturo. Semplicemente non hai bisogno di un framework per implementare DI grazie alla digitazione duck.

Il miglior esempio è come si configura un'applicazione 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',
    }
}

Django Rest Framework utilizza DI pesantemente:

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

Lasciami ricordare ( fonte ):

"Iniezione delle dipendenze" è un termine di 25 dollari per un concetto da 5 cent. [...] Iniezione di dipendenza significa dare a un oggetto le sue variabili di istanza. [...].


8
+1. Ben messo. Essendo un programmatore di Python, ero completamente sconcertato da un'intera presentazione dell'intervista su framework DI in C #. Mi ci è voluto un po 'per capire che l'ho già fatto tutto il tempo nelle app Flask senza nemmeno pensarci perché non hai bisogno di un framework. Per qualcuno che non sa nulla oltre a C # / Java la domanda ha un senso. Per i programmatori di lingue dattiloscritte è naturale e come dici tu, "termine da 25 dollari per un concetto da 5 cent".
Samuel Harmer,

5
err ... questa non è iniezione di dipendenza poiché le istanze ( IsAuthenticated, ScopedRateThrottle) sono istanziate dalla classe. Non vengono passati al costruttore.
dopatraman

5
IsAuthenticatede ScopedRateThrottlenon sono istanze, queste sono classi. Vengono istanziati quando viene costruito un FooView (in realtà, quando FooView elabora una richiesta). Comunque, questo è solo un dettaglio di implementazione. IsAuthenticatede ScopedRateThrottlesono le dipendenze; vengono iniettati nel FooView. Non importa quando o come è fatto. Python non è Java, quindi ci sono diversi modi per implementarlo.
Max Malysh,

3
@MaxMalysh Sono d'accordo con dopatraman su questo. Questo non è nemmeno IoC poiché la classe stessa ha dipendenze "codificate" per una classe specifica. In IoC, la dipendenza dovrebbe essere fornita anziché codificata. Inoltre, in Dependency Injection, avrai un'entità responsabile della gestione dei cicli di vita di ciascun servizio e di iniettarli quando ciò è il caso. La soluzione fornita in nessuno di questi.
Ricardo Alves,

3
@alex No, non è necessario modificare il codice per utilizzare un altro renderer. È anche possibile utilizzare più di rendering simultaneamente: renderer_classes = (JSONRenderer, BrowsableAPIRenderer, XMLRenderer). Deridere è semplice come @unittest.patch('myapp.views.FooView.permission_classes'). Un bisogno disperato di "passare qualcosa" è una conseguenza del "modo Java di fare le cose" a causa del fatto che Java è un linguaggio compilato e tipicamente statico privo di forti capacità di metaprogrammazione.
Max Malysh,

35

Django fa grande uso dell'inversione del controllo. Ad esempio, il server di database è selezionato dal file di configurazione, quindi il framework fornisce le istanze appropriate del wrapper di database ai client del database.

La differenza è che Python ha tipi di prima classe. I tipi di dati, comprese le classi, sono essi stessi oggetti. Se vuoi che qualcosa utilizzi una determinata classe, è sufficiente nominare la classe. Per esempio:

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

Il codice successivo può quindi creare un'interfaccia del database scrivendo:

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

Invece delle funzioni di fabbrica del boilerplate di cui hanno bisogno Java e C ++, Python lo fa con una o due righe di codice ordinario. Questa è la forza della programmazione funzionale contro imperativa.


4
Quello che chiami codice è in realtà la parte del cablaggio. Quello sarebbe l'XML del tuo framework ioc. In realtà potrebbe essere scritto semplicemente come import psycopg2 as database_interface. Metti quella linea in un injections.pyet voilà.
extra il

29
Erm. Quello che fai lì è praticamente un libro di testo imperativo Daniel.
Shayne,

È sicuramente un codice imperativo, ma è un po 'funzionale perché usa un valore richiamabile.
Jeremy,

5
Ma non sono solo funzioni di prima classe? it.wikipedia.org/wiki/First-class_function Solo perché li hai e li usi non rende funzionale il tuo codice. Ci sono alcuni effetti collaterali che si verificano qui (come il cambiamento self.database_interface), che urla imperativo.
hjc1710,

15

Sembra che le persone non capiscano davvero cosa significhino l'iniezione di dipendenza e l'inversione del controllo.

La pratica di utilizzare l'inversione del controllo è quella di avere classi o funzioni che dipendono da altre classi o funzioni, ma invece di creare le istanze all'interno della classe del codice funzione è meglio riceverlo come parametro, quindi l'accoppiamento libero può essere archiviato. Ciò comporta numerosi vantaggi, in quanto maggiore testabilità e l'archiviazione del principio di sostituzione di Mosca.

Vedi, lavorando con interfacce e iniezioni, il tuo codice diventa più gestibile, dal momento che puoi cambiare facilmente il comportamento, perché non dovrai riscrivere una singola riga di codice (forse una o due righe sulla configurazione DI) del tuo classe per modificarne il comportamento, poiché le classi che implementano l'interfaccia che la tua classe sta aspettando possono variare indipendentemente fintanto che seguono l'interfaccia. Una delle migliori strategie per mantenere il codice disaccoppiato e facile da mantenere è seguire almeno i singoli principi di inversione di responsabilità, sostituzione e dipendenza.

A cosa serve una libreria DI se puoi istanziare un oggetto da solo all'interno di un pacchetto e importarlo per iniettarlo tu stesso? La risposta scelta è giusta, dal momento che java non ha sezioni procedurali (codice al di fuori delle classi), tutto ciò che va in noiosi xml di configurazione, quindi la necessità di una classe per istanziare e iniettare dipendenze su un modo di caricamento pigro in modo da non soffiare via la tua performance, mentre su Python devi solo codificare le iniezioni nelle sezioni "procedurali" (codice al di fuori delle classi) del tuo codice


ti manca ancora che un IoC / DI colleghi automaticamente gli oggetti. Non è molto in grado di farlo in fase di esecuzione (Java può farlo tramite la riflessione comunque), è che il framework se ne occupa e non è necessario farlo esplicitamente. Anche la presenza di sezioni procedurali è irrilevante, nulla impedisce di scrivere un'app interamente procedurale in Java, utilizzando le classi come semplici contenitori di subroutine e funzioni statiche, senza utilizzare affatto le funzionalità OOP.
zakmck,

@zakmck: la sezione "procedurale" di Python qui non riguarda proprio la scrittura di codice procedurale. Ciò che rende la sezione "procedurale" di Python diversa dai linguaggi statici è la capacità di inserire il codice procedurale in un corpo di classe, che viene eseguito durante il tempo di definizione della classe, di inserire le istruzioni di importazione all'interno dell'istruzione if e di creare un factory di classe semplicemente definendo le classi all'interno di un metodo di fabbrica. Queste sono cose che non puoi davvero fare nei linguaggi statici e che risolvono la maggior parte dei problemi che IOC / DI ha tentato di risolvere. La metaprogrammazione in Python spesso assomiglia al normale codice Python.
Sdraiati Ryan il

@LieRyan, puoi farlo con la riflessione o, se ne hai bisogno spesso o in fase di esecuzione, puoi chiamare il linguaggio statico da un'altra lingua come Groovy (che è progettato per giocare facilmente con Java), o persino Python stesso. Tuttavia, ciò ha poco a che fare con i framework IoC / DI, poiché il loro scopo è quello di eseguire la maggior parte del cablaggio degli oggetti procedurali per te, automaticamente, sfruttando solo le definizioni. Purtroppo, la maggior parte delle risposte con la presente manca questo punto.
zakmck,

12

Non uso Python da diversi anni, ma direi che ha più a che fare con il fatto che sia un linguaggio tipizzato dinamicamente che altro. Per un semplice esempio, in Java, se volessi provare che qualcosa è stato scritto in modo appropriato per standardizzare, potrei usare DI e passare qualsiasi PrintStream per catturare il testo che viene scritto e verificarlo. Quando lavoro in Ruby, tuttavia, posso sostituire dinamicamente il metodo 'put' su STDOUT per fare la verifica, lasciando DI completamente fuori dal quadro. Se l'unica ragione per cui sto creando un'astrazione è testare la classe che la sta utilizzando (pensa alle operazioni del file system o all'orologio in Java), DI / IoC crea complessità inutili nella soluzione.


3
Non smette mai di stupirmi del fatto che le persone disposte a cambiare il modo in cui un sistema funziona per verificarne il funzionamento. Ora è necessario verificare che i test non causino effetti collaterali.
Base il

2
parla della modifica del metodo messo solo nell'ambito dei test, è come il metodo simulato dell'oggetto iniettato.
dpa

2
@Basic è abbastanza normale nei test unitari , in realtà è consigliabile farlo in questi test in quanto non si desidera inquinare la copertura del test case con più di un blocco di codice (quello che viene testato). Sarebbe sbagliato farlo per i test di integrazione, forse è a questo che ti riferisci nel tuo commento?
samuelgrigolato,

1
Per me, la testabilità è una preoccupazione di prima classe. Se un design non è testabile, non è un buon design e non ho problemi a cambiarlo per renderlo più testabile. Dovrò riconvalidare che funziona ancora, ma va bene. La testabilità è un motivo perfettamente valido per modificare il codice IMO
Carlos Rodriguez il

10

In realtà, è abbastanza facile scrivere codice sufficientemente pulito e compatto con DI (mi chiedo, sarà / rimarrà pitonico allora, ma comunque :)), per esempio in realtà approfondisco questo modo di codificare:

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!

Sì, questo può essere visto come una semplice forma di parametrizzazione di funzioni / classi, ma fa il suo lavoro. Quindi, forse anche le batterie incluse in Python sono sufficienti qui.

PS Ho anche pubblicato un esempio più ampio di questo approccio ingenuo alla valutazione dinamica di una semplice logica booleana in Python .


3
Per casi semplici che potrebbero funzionare, ma immagina un semplice controller per blog web, che utilizza vari modelli (Posta, Commento, Utente). Se si desidera che l'utente inserisca il proprio modello Post (con un attributo viewcount aggiuntivo per tracciarlo) e il proprio modello utente con più informazioni sul profilo e così via, tutti i parametri potrebbero apparire confusi. Inoltre, l'utente potrebbe voler cambiare anche l'oggetto Request, per supportare la sessione del filesystem invece di una semplice sessione basata su cookie o qualcosa del genere ... Quindi, finirai con molti parametri a breve.
tux21b

1
@ tux21b Bene, c'è una "complessità essenziale" che gli utenti vogliono che l'applicazione applichi, ci sono soluzioni architettoniche (alcune delle quali non sono peggiori del resto in termini di sviluppo e possibilmente tempo di manutenzione, velocità di esecuzione, ecc. ) e esiste la capacità umana di comprendere l'API e l'architettura software. Se non esiste alcuna soluzione comprensibile all'uomo (non solo tra coloro che usano (qualsiasi forma di) DI) ... beh, chi ha detto che tutti i problemi sono risolvibili? E avere molti parametri assegnati in modo predefinito (ma scambiabili per scelta dell'utente) può effettivamente essere spesso frequente.
mlvljr,

9

IoC / DI è un concetto di design, ma sfortunatamente è spesso preso come un concetto che si applica a determinati linguaggi (o sistemi di battitura). Mi piacerebbe vedere i contenitori per iniezione di dipendenza diventare molto più popolari in Python. C'è Spring, ma questo è un super-framework e sembra essere una porta diretta dei concetti Java senza molta considerazione per "The Python Way".

Considerate le annotazioni in Python 3, ho deciso di avere una crepa in un contenitore di iniezione di dipendenza completo, ma semplice: https://github.com/zsims/dic . È basato su alcuni concetti di un contenitore di iniezione di dipendenze .NET (che IMO è fantastico se stai giocando in quello spazio), ma mutato con i concetti di Python.


6

Penso che a causa della natura dinamica di Python le persone non vedano spesso la necessità di un altro framework dinamico. Quando una classe eredita dal nuovo 'oggetto' di stile, puoi creare una nuova variabile in modo dinamico ( https://wiki.python.org/moin/NewClassVsClassicClass ).

cioè in pitone semplice:

#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()

Tuttavia dai un'occhiata a https://github.com/noodleflake/pyioc questo potrebbe essere quello che stai cercando.

vale a dire in pioioc

from libs.service_locator import ServiceLocator

#main.py
ServiceLocator.register(PostgresConnection)

#other.py
postgres_connection = ServiceLocator.resolve(PostgresConnection)
db_data = postgres_connection.fetchone()

2
Il fatto stesso che entrambe le versioni prendano la stessa quantità di codice aiuta molto a spiegare perché l'uso di un framework non è molto popolare.
extra

Nella other.pyriga 1, esiste una risoluzione automatica delle dipendenze, ma non viene considerata come un'iniezione di dipendenze.
andho,

I localizzatori di servizi sono di solito un anti-schema, solo dicendo.
PmanAce,

6

Appoggio la risposta di "Jörg W Mittag": "L'implementazione Python di DI / IoC è così leggera che svanisce completamente".

Per eseguire il backup di questa affermazione, dai un'occhiata al famoso esempio di Martin Fowler portato da Java a Python: Python: Design_Patterns: Inversion_of_Control

Come puoi vedere dal link sopra, un "Contenitore" in Python può essere scritto in 8 righe di codice:

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

42
Questo è molto inferiore ai contenitori DI più deboli. Dov'è la gestione della vita, la risoluzione ricorsiva delle dipendenze, la capacità di deridere o, in mancanza di tutto, la configurazione? Questo non è altro che una ricerca di tipo e cache che non è la stessa cosa di IoC.
Base il

2
Anni fa ho scritto un piccolo framework DI usando metaclassi come esercizio. Il tutto è un singolo file con zero importazioni e doctest che lo rendono autoesplicativo. Mostra che le funzionalità di base non sono così difficili da implementare in un modo che sia persino "pitonico", ma sinceramente penso sia triste che nessuna soluzione completa abbia ottenuto una trazione maggiore come quella di Spring in Java e che tutti stanno realizzando architetture di plug-in personalizzate.
Andrea Ratto,

2

Il mio 2 centesimi è che nella maggior parte delle applicazioni Python non ne hai bisogno e, anche se ne avevi bisogno, è probabile che molti odiatori di Java (e violinisti incompetenti che credono di essere sviluppatori) lo considerino qualcosa di brutto, solo perché è popolare in Java .

Un sistema IoC è effettivamente utile quando si hanno reti complesse di oggetti, in cui ogni oggetto può essere una dipendenza per molti altri e, a sua volta, essere esso stesso dipendente da altri oggetti. In tal caso, dovrai definire tutti questi oggetti una volta e disporre di un meccanismo per metterli insieme automaticamente, in base al maggior numero possibile di regole implicite. Se hai anche la configurazione che deve essere definita in modo semplice dall'utente / amministratore dell'applicazione, questo è un motivo in più per desiderare un sistema IoC in grado di leggere i suoi componenti da qualcosa come un semplice file XML (che sarebbe la configurazione).

La tipica applicazione Python è molto più semplice, solo un mucchio di script, senza un'architettura così complessa. Personalmente sono consapevole di cosa sia effettivamente un IoC (contrariamente a quelli che hanno scritto alcune risposte qui) e non ho mai sentito il bisogno di farlo nella mia esperienza Python limitata (inoltre non uso Spring ovunque, non quando i vantaggi dà non giustificare il suo sovraccarico di sviluppo).

Detto questo, ci sono situazioni Python in cui l'approccio IoC è effettivamente utile e, in effetti, ho letto qui che Django lo usa.

Lo stesso ragionamento sopra potrebbe essere applicato alla programmazione orientata agli aspetti nel mondo Java, con la differenza che il numero di casi in cui AOP è veramente utile è ancora più limitato.


Esiste un URL di riferimento alla fonte di informazioni in cui django utilizza IoC?
Sajuuk,

@Sajuuk, l'ho imparato su Django nel thread di questa domanda, quindi non lo so, dovresti chiedere agli altri autori della risposta.
zakmck,

Il primo alinea di questa risposta aggiunge 0 valore secondo me ... Penso di essere in grado di decidere quando il mio codice Python trarrebbe beneficio da IoC, e non mi interessa cosa lo sviluppatore pensa che sia male. Apprezzo il pragmatismo rispetto alle opinioni non fondate.
Mike de Klerk

@MikedeKlerk il mio suggerimento è che qualcosa che è sia sconosciuto (come dimostrano molte risposte con il presente documento) sia vittima di pregiudizio è improbabile che diventi popolare, non importa quanto siano obiettivi e ben informati alcuni come te. E ovviamente non sono sicuro che questo sia un motivo per cui non vedi molti usi IoC in Python, penso che il motivo principale sia che le app a bassa / media complessità non ne hanno bisogno.
zakmck

The typical Python application is much simpler, just a bunch of scripts, without such a complex architecture.- piuttosto un presupposto
hyankov


-1

Concordo con @Jorg sul fatto che DI / IoC è possibile, più facile e ancora più bello in Python. Ciò che manca sono i framework che lo supportano, ma ci sono alcune eccezioni. Per indicare un paio di esempi che mi vengono in mente:

  • I commenti di Django ti consentono di collegare la tua classe di commenti con la tua logica e i tuoi moduli personalizzati. [Ulteriori informazioni]

  • Django ti consente di utilizzare un oggetto profilo personalizzato da collegare al tuo modello utente. Questo non è completamente IoC ma è un buon approccio. Personalmente vorrei sostituire il modello utente del foro come fa il framework dei commenti. [Ulteriori informazioni]


-3

A mio avviso, cose come l'iniezione di dipendenza sono sintomi di un quadro rigido e troppo complesso. Quando il corpo principale del codice diventa troppo pesante per cambiare facilmente, ti ritrovi a doverne raccogliere piccole parti, definirne le interfacce e quindi consentire alle persone di cambiare comportamento attraverso gli oggetti che si collegano a quelle interfacce. Va bene e va bene, ma è meglio evitare quel tipo di complessità in primo luogo.

È anche il sintomo di un linguaggio tipicamente statico. Quando l'unico strumento che devi esprimere per astrazione è l'eredità, allora è praticamente quello che usi ovunque. Detto questo, C ++ è piuttosto simile ma non ha mai suscitato il fascino di Builders e Interfaces ovunque che gli sviluppatori Java abbiano fatto. È facile esagerare con il sogno di essere flessibile ed estensibile al costo di scrivere troppi codici generici con pochi vantaggi reali . Penso che sia una cosa culturale.

In genere penso che le persone di Python siano abituate a scegliere lo strumento giusto per il lavoro, che è un insieme coerente e semplice, piuttosto che lo strumento One True (With A Thousand Possible Plugins) che può fare qualsiasi cosa ma offre una serie sconcertante di possibili permutazioni di configurazione . Ci sono ancora parti intercambiabili ove necessario, ma senza la necessità del grande formalismo di definire interfacce fisse, a causa della flessibilità della tipizzazione anatra e della relativa semplicità del linguaggio.


4
Non è tanto il framework quanto il linguaggio stesso. Per creare il tipo di flessibilità di cui godono le lingue tipografiche, i linguaggi tipicamente statici richiedono strutture e regole molto sofisticate. DI è una di quelle regole. La gente di Python non ci pensa due volte. Le persone Java devono davvero lavorarci su.
S.Lott

6
@ S.Lott - Concordo pienamente con te, tranne per il fatto che le persone in C ++ sembrano cavarsela senza l'esplosione dei modelli di progettazione e architettura, nonostante lavori con restrizioni simili a quelle di Java. Penso che ciò implichi una differenza culturale in cui, dopo aver affrontato 2 possibili modi per fare qualcosa, le persone Java preferiscono estrarre un'altra interfaccia per facilitare il modello di strategia mentre le persone C ++ si immergono e aggiungono un bool e un'istruzione if ...
Kylotan,

3
@Finglas, quindi se ho una dozzina di classi che usano tutte la mia EmailSendere decido di sostituirla con una DesktopNotifier, devo andare a modificare 12 classi a mano. E pensi che sia più semplice e più pulito che scrivere su INotifierun'interfaccia e lasciare che il contenitore elabori i dettagli?
Base il

1
Sfortunatamente, un certo livello di complessità è una realtà che gli sviluppatori di software professionali devono affrontare. Vedo critiche ma nessuna soluzione in questa risposta. Qual è la soluzione "pythonic" per questo problema: sto scrivendo una libreria e voglio fornire un hook per la registrazione (qualcosa come PSR-3 LoggerInterface di PHP). So come utilizzare i livelli di registro, ma non mi interessa come il programma li riporta effettivamente. Qual è il modo pulito per consentire all'app client di inserire i dettagli dell'implementazione. Nota: altre parti dell'applicazione potrebbero avere implementazioni diverse di questa interfaccia.
Rob,

2
La mia domanda per te non è come si usa la libreria di registrazione standard, né si tratta di creare diverse istanze di una classe logger. La mia domanda è come si configura l'applicazione in modo che parti diverse dell'applicazione possano utilizzare implementazioni diverse e non preoccuparsi di quei dettagli (a condizione che sappiano come utilizzare l'interfaccia). Questo è un problema molto reale che DI ha risolto per più applicazioni PHP su cui ho lavorato. Sto cercando l'equivalente di Python. E suggerire "semplicemente non rendere la tua applicazione così complessa" non è la risposta che sto cercando.
Rob,

-5

A differenza della forte natura tipizzata in Java. Il comportamento di battitura delle anatre di Python semplifica il passaggio degli oggetti.

Gli sviluppatori Java si stanno concentrando sulla costruzione della struttura di classe e della relazione tra oggetti, mantenendo le cose flessibili. L'IoC è estremamente importante per raggiungere questo obiettivo.

Gli sviluppatori di Python si stanno concentrando sull'ottenere il lavoro svolto. Collegano le lezioni quando ne hanno bisogno. Non devono nemmeno preoccuparsi del tipo di classe. Finché può ciarlare, è un'anatra! Questa natura non lascia spazio all'IoC.


4
Hai ancora bisogno di trovare una cosa che caga.
andho,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.