IoC / DI neden Python'da yaygın değil?


312

Java'da IoC / DI , web uygulamalarında, neredeyse tüm mevcut çerçevelerde ve Java EE'de yaygın olarak kullanılan çok yaygın bir uygulamadır. Öte yandan, birçok büyük Python web uygulaması da var, ancak Zope'un yanı sıra (duyduğum kod için gerçekten korkunç olmalı) IoC'nin Python dünyasında çok yaygın olmadığı görülüyor. (Yanlış olduğumu düşünüyorsanız lütfen bazı örnekler verin).

Elbette Python, springpython için popüler Java IoC çerçevelerinin birkaç klonu vardır . Ancak bunların hiçbiri pratikte kullanılmıyor gibi görünüyor. En azından, böyle bir şey kullanan bir Django veya sqlalchemy + <insert your favorite wsgi toolkit here>tabanlı web uygulamasına hiç rastlamadım .

Bence IoC'nin makul avantajları var ve örneğin django-default-user-modelini değiştirmeyi kolaylaştıracaktı, ancak Python'daki arayüz sınıflarının ve IoC'nin yaygın kullanımı biraz tuhaf görünüyor ve »pythonic« değil. Ama belki birinin daha iyi bir açıklaması var, IoC neden Python'da yaygın olarak kullanılmıyor.


2
Tahminimce, Ruby'de daha az popüler olmasının aynı nedeni, yerleşik karışımlar ve açık sınıflar
Sam Saffron

3
hiç springpython denedin mi? reklamı yapılan gibi bile çalışmaz. en azından aop kısmında. Java'dan gelmediğiniz ve geçiş sırasında bir miktar rahatlığa ihtiyacınız olmadıkça, oradaki her şey çok yararlı değildir.
Tom Willis

6
Lütfen DI kullanımı ile IOC çerçevesinin kullanımı arasında ayrım yapmaya dikkat edin. Birincisi bir tasarım deseni, ikincisi birincisinin otomatik kullanımına yardımcı olan bir çerçevedir.
Doug

Doug, DI'nin Dekoratör kalıbı kullanılarak elde edilen yaratıcı özellik olduğunu söylemek istediğine inanıyorum.
njappboy

4
DI'nin çözdüğü gerçek dünya sorunlarına hitap eden bir cevap görmek isterim: Yaşam boyu yönetim, test stubbing kolaylığı, vb.
Josh Noe

Yanıtlar:


197

Aslında DI / IoC olduğunu sanmıyorum o Python nadir. Ne olduğunu nadir, ancak, DI / IoC olan çerçeveler / konteynerler .

Bir düşünün: DI konteyneri ne yapar? Yapmanıza izin verir

  1. bağımsız bileşenleri birlikte eksiksiz bir uygulamaya bağlayın ...
  2. ... işlem esnasında.

"Birlikte kablolama" ve "çalışma zamanında" için isimlerimiz var:

  1. betik
  2. dinamik

Dolayısıyla, bir DI kapsayıcısı dinamik bir kodlama dili için bir yorumlayıcıdan başka bir şey değildir. Aslında şunu ifade edeyim: tipik bir Java / .NET DI kapsayıcısı, popo çirkin, bazen XML tabanlı sözdizimi ile gerçekten kötü bir dinamik komut dosyası dili için berbat bir yorumlayıcıdan başka bir şey değildir.

Python'da program yaparken, emrinizde güzel, parlak bir betik diliniz olduğunda neden çirkin, kötü bir betik dili kullanmak istersiniz? Aslında, bu daha genel bir soru: hemen hemen her dilde programladığınızda, Jython ve IronPython'unuz olduğunda neden çirkin, kötü bir komut dosyası dili kullanmak istersiniz?

Özetlemek gerekirse: DI / IoC uygulaması Python'da Java'da olduğu gibi aynı nedenlerle önemlidir. Uygulama DI / IoC ait Ancak diline inşa edilmiştir ve tamamen kaybolur sık sık bu yüzden hafif.

(Bir benzetmenin kısa bir kenarı: montajda, bir alt program çağrısı oldukça büyük bir anlaşma - yerel değişkenlerinizi ve kayıtlarınızı belleğe kaydetmeniz, dönüş adresinizi bir yere kaydetmeniz, talimat işaretçisini aradığınız alt rutine değiştirmeniz, bittiğinde bir şekilde alt rutininize atlamasını sağlayın, argümanları callee'nin bulabileceği bir yere koyun, vb. IOW: montajda, "altyordam çağrısı" bir Tasarım Deseni ve daha önce gibi diller vardı Yerleşik alt program çağrıları olan Fortran, insanlar kendi "alt program çerçevelerini" inşa ediyorlardı. Alt program çerçevelerini kullanmamanız nedeniyle alt program çağrılarının Python'da "nadir" olduğunu söyleyebilir misiniz?)

BTW: Bu mantıksal sonucuna DI almaya neye benzediğini bir örnek için, bir göz atın Gilad Bracha 'ın Dili Programlama tellalların konuyla ilgili ve onun yazıları:


58
Kabul ederken. XML yorumu yanlış. Birçok (en azından modern) IOC kapsayıcıları, yapılandırma (XML) üzerinden kural (kod) kullanır.
Finglas

20
Kablolamayı Java'da açıkça yazmanızı engelleyen hiçbir şey yoktur, ancak daha fazla hizmetiniz olduğu için bağımlılıklar daha karmaşık hale gelir. Bir DI kapsayıcısı Make gibidir: bağımlılıkları beyan edersiniz ve kap doğru sıralarla başlatır. Guice, her şeyin Java koduyla yazıldığı bir Java DI çerçevesidir.
Deklaratif olarak

133
"Bununla birlikte, DI / IoC uygulaması dile yerleştirilmiştir ve genellikle o kadar hafiftir ki tamamen yok olur." Aşağı oy, çünkü bu kategorik olarak doğru değil. DI, bir arayüzün kurucuya aktarıldığı bir modeldir. Python'da yerleşik değildir.
Doug

146
downvote, birlikte kablolama komut dosyası ile ilgisi yoktur, DI bir kalıp ve komut dosyası ile eşdeğer değildir
Luxspes

38
Buna katılmıyorum. DI, statik dillerde dinamik kodlama eksikliğini çözmez. Uygulamanızın parçalarını yapılandırmak ve oluşturmak için bir çerçeve sağlar. Bir zamanlar bir Ruby dev'in DI'nin dinamik dillerde gereksiz olduğunu söylediğini duydum. Ama Rails kullandı ... Rails sadece büyük bir DI konteyner türü, hangi zaman yapılandırmak için hangi parçaları bulmak için kural kullanır. DI'ye ihtiyacı yoktu çünkü Rails onun için parçaları bulma sorununu çözdü.
Brian Genisio

51

Bunun bir kısmı modül sisteminin Python'da çalışma şeklidir. Sadece bir modülden içe aktararak bir çeşit "singleton" ücretsiz alabilirsiniz. Modüldeki bir nesnenin gerçek bir örneğini tanımladığınızda, herhangi bir istemci kodu onu içe aktarabilir ve gerçekten çalışan, tamamen oluşturulmuş / doldurulmuş bir nesne alabilir.

Bu, nesnelerin gerçek örneklerini içe aktarmadığınız Java'nın tersidir. Bu, onları her zaman kendiniz başlatmanız gerektiği anlamına gelir (veya bir çeşit IoC / DI tarzı yaklaşım kullanın). Statik fabrika yöntemleri (veya gerçek fabrika sınıfları) kullanarak her şeyi kendiniz başlatmanın zorluğunu azaltabilirsiniz, ancak yine de her seferinde yenilerini yaratmanın kaynak yüküne maruz kalırsınız.


2
Mantıklı. Python'daki bir uygulamayı değiştirmek istersem, aynı adı kullanarak farklı bir konumdan içe aktarırım. Ama şimdi , sadece statik, tamamen başlatılmış örnekleri içeren Java'da MyClassInstancesher birine bir sınıf tanımlayarak bunun mümkün olup olmadığını düşünüyorum MyClass. Kablolu olurdu: D
tux21b 17:10

2
Ve başka bir fikir: Python'da bu tür ithalatları değiştirmenin bir yolunu sağlamak, tüm python dosyalarına dokunmadan uygulamaları kolayca değiştirmeyi mümkün kılacaktır. Bunun yerine çerçevenin içine from framework.auth.user import User yazmak User = lookup('UserImplentation', 'framework.auth.user.User')(2. parametre varsayılan bir değer olabilir) daha iyi olabilir. Daha sonra çerçevenin kullanıcıları çerçeveye Userdokunmadan uygulamayı değiştirebilir / özelleştirebilir .
tux21b 17:10

14
Aşırı basitleştirmek, cevaplamak, gerçek hayatta, nadiren sadece bir "tekil" gerekir, kapsamı kontrol etmeniz gerekir (yerel bir iş parçacığına veya bir oturum tekiline ihtiyacınız olabilir), bu bana bu tür sorunların olduğunu düşündürüyor çözüldü Python aslında bir kurumsal ortamda çözülmüş gerçek dünya sorunları tür değildir
Luxspes

3
Aslında DI, kod bağımlılıklarını test edip çözmekle ilgilidir. Ayrıca içe aktarma özelliği, bir nesnenin tek bir örneğini içe aktarmama izin veren Java'daki statik içe aktarma işlemine benzer.
Richard Warburton

1
"Sadece bir modülden içe aktararak bir çeşit" singleton "elde edebilirsiniz." Java, statik bir örnek alanı bildirip bir değere ayarlayarak kolayca yapılabilir. Bu bir sol değil
ggranum

45

IoC ve DI, olgun Python kodunda süper yaygındır. Ördek yazımı sayesinde DI'yi uygulamak için bir çerçeveye ihtiyacınız yok.

En iyi örnek, Django uygulamasını şu şekilde kullanarak nasıl ayarlayacağınızdır 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 DI'yi yoğun olarak kullanıyor:

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

Hatırlatmama izin ver ( kaynak ):

"Bağımlılık Enjeksiyonu" 5 sentlik bir kavram için 25 dolarlık bir terimdir. [...] Bağımlılık enjeksiyonu, bir nesneye örnek değişkenlerini vermek anlamına gelir. [...].


8
+1. İyi koy. Bir Python programcısı olarak tamamen C # DI çerçeveleri üzerinde röportaj sunumu ile şaşırttı. Flask uygulamalarında bunu düşünmeden bile yaptım zaten fark etmem bir süre aldı çünkü bir çerçeveye ihtiyacınız yok. C # / Java'nın ötesinde hiçbir şey bilmeyen birine soru mantıklı geliyor. Ördek tipi dil programcıları için bu sadece doğaldır ve dediğiniz gibi, "5 sentlik bir kavram için 25 dolarlık terim".
Samuel Harmer

5
err ... örnekler ( IsAuthenticated, ScopedRateThrottle) sınıf tarafından başlatıldığı için bu bağımlılık enjeksiyonu değildir . Yapıcıya aktarılmazlar.
dopatraman

5
IsAuthenticatedve ScopedRateThrottleörnekler değil, bunlar sınıflar. Bir FooView oluşturulduğunda (aslında, FooView bir isteği işlediğinde) bunlar örneklenir. Her neyse, bu sadece bir uygulama detayı. IsAuthenticatedve ScopedRateThrottlebağımlılıklar; içine enjekte edilir FooView. Bunun ne zaman veya nasıl yapıldığı önemli değil . Python Java değildir, bu yüzden bunu uygulamanın farklı yolları vardır.
Max Malysh

3
@MaxMalysh Bu konuda dopatraman ile hemfikirim. Sınıfın kendisinin belirli bir sınıfa "sabit kodlanmış" bağımlılıkları olduğundan, bu IoC bile değildir. IoC'de bağımlılık kaydı kodlanmış yerine sağlanmalıdır. Bunun da ötesinde, Bağımlılık Enjeksiyonu'nda, her hizmetin yaşam döngülerini yönetmekle sorumlu bir kuruluşunuz olacak ve bu durumda onları enjekte edeceksiniz. Çözüm bunların hiçbirinde sağlanmadı.
Ricardo Alves

3
@alex Hayır, başka bir oluşturucu kullanmak için kodunuzu değiştirmeniz gerekmez. Hatta aynı anda birden fazla oluşturuculara kullanabilirsiniz: renderer_classes = (JSONRenderer, BrowsableAPIRenderer, XMLRenderer). Alay etmek kadar basit @unittest.patch('myapp.views.FooView.permission_classes'). "Bir şeyleri geçmek" için umutsuz bir ihtiyaç, Java'nın güçlü metaprogram oluşturma yetenekleri olmayan derlenmiş ve statik olarak yazılmış bir dil olması nedeniyle "bir şeyler yapmanın Java yolu" nun bir sonucudur.
Max Malysh

35

Django, kontrolün ters çevrilmesini büyük ölçüde kullanır. Örneğin, veritabanı sunucusu yapılandırma dosyası tarafından seçilir, ardından çerçeve veritabanı istemcilerine uygun veritabanı sarma örnekleri sağlar.

Fark, Python'un birinci sınıf tiplere sahip olmasıdır. Sınıflar da dahil olmak üzere veri türleri kendileri nesnedir. Belirli bir sınıfı kullanmak için bir şey istiyorsanız, sadece sınıfı adlandırın. Örneğin:

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

Daha sonra kod yazarak bir veritabanı arayüzü oluşturabilir:

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

Java ve C ++ 'ın ihtiyaç duyduğu kazan plakası fabrika işlevleri yerine, Python bunu bir veya iki sıradan kodla yapar. Bu, işlevsel ve zorunlu programlamanın gücüdür.


4
Ne kodu kodu aslında kablo parçasıdır. Bu, ioc çerçevenizin XML'si olacaktır. Aslında basitçe yazılabilirdi import psycopg2 as database_interface. Bu satırı bir injections.pyet voilà'ya koyun .
spektrumlar

29
Erm. Ne yapıyorsun hemen hemen ders kitabı zorunlu Daniel.
Shayne

Kesinlikle zorunlu bir koddur, ancak bir değer olarak çağrılabilir kullandığından işlevseldir.
Jeremy

5
Bu sadece Birinci Sınıf Fonksiyonlar değil mi? tr.wikipedia.org/wiki/First-class_function Bunlara sahip olmanız ve kullanmanız kodunuzu İşlevsel kılmaz. Burada (değişmek gibi self.database_interface) zorunlu olan çığlık atan birkaç yan etki var .
hjc1710

15

İnsanların Bağımlılık enjeksiyonunun ve kontrolün ters çevrilmesinin artık ne anlama geldiğini gerçekten görmediğini görüyor.

Denetimi tersine çevirme kullanımı, başka sınıflara veya işlevlere bağlı sınıflara veya işleve sahip olmaktır, ancak işlev kodu sınıfında örnekleri oluşturmak yerine, parametre olarak almak daha iyidir, bu nedenle gevşek bağlantı elde edilebilir. Bu, daha fazla test edilebilirlik ve liskov ikame ilkesine ulaşmak için birçok faydaya sahiptir.

Görüyorsunuz, arayüzler ve enjeksiyonlarla çalışarak, davranışınızı kolayca değiştirebileceğiniz için kodunuz daha anlaşılır hale gelir, çünkü tek bir kod satırını (belki DI yapılandırmasında bir veya iki satır) yeniden yazmak zorunda kalmazsınız. sınıfını, sınıfınızın beklediği arabirimi uygulayan sınıflar, arabirimi izledikleri sürece bağımsız olarak değişebilir. Kodun ayrıştırılmasını ve bakımı kolay tutulması için en iyi stratejilerden biri, en azından tek sorumluluk, ikame ve bağımlılık tersine çevirme ilkelerini takip etmektir.

Bir nesneyi bir paketin içinde kendiniz başlatabilir ve kendiniz enjekte etmek için içe aktarabilirseniz iyi bir DI kütüphanesi nedir? Seçilen cevap doğrudur, çünkü java'nın prosedürel bölümleri (sınıfların dışındaki kodlar) olmadığı için, sıkıcı konfigürasyon xml'lerine giren her şey, bu nedenle tembel bir yük modası üzerinde bağımlılıkları başlatmak ve enjekte etmek için bir sınıfa ihtiyaç vardır, böylece uçup gitmezsiniz. performansınız, python üzerinde ise sadece kodunuzun "prosedürel" (sınıflar dışında kod) bölümlerindeki enjeksiyonları kodlarsınız


bir IoC / DI'nin nesneleri otomatik olarak birbirine bağladığını hala özlüyorsunuz. Çalışma zamanında bunu yapmak çok fazla değil (Java bunu zaten yansıma yoluyla yapabilir), çerçeve bununla ilgilenir ve açıkça yapmanıza gerek yoktur. Prosedürel bölümlere sahip olmak da önemsizdir, hiçbir şey OOP özelliklerini kullanmadan sınıfları yalnızca statik alt rutin ve işlev kapları olarak kullanarak Java'da tamamen prosedürel bir uygulama yazmayı engellemez.
zakmck

@zakmck: Python'un "prosedürel" bölümü burada prosedürel kod yazmakla ilgili değil. Python'un "yordamsal" bölümünü statik dillerden farklı kılan şey, yordam kodunu sınıf tanımlama süresinde çalışan bir sınıf gövdesine koyma ve if-ifadesinin içine içe aktarma ifadeleri koyma ve yalnızca sınıfları tanımlayarak sınıf fabrikası oluşturma becerisidir. bir fabrika yöntemi içinde. Bunlar statik dillerde gerçekten yapamayacağınız ve IOC / DI'nin çözmeye çalıştığı sorunların çoğunu çözen şeylerdir. Python'da meta programlama genellikle normal Python koduna benzer.
Yalan Ryan

@LieRyan, bunu yansıma ile yapabilir veya sık sık veya çalışma zamanında ihtiyacınız varsa, statik dili Groovy (Java ile kolayca oynamak için tasarlanan) veya hatta Python'un kendisi gibi başka bir dilden çağırabilirsiniz. Bununla birlikte, bunun IoC / DI çerçeveleri ile çok az ilgisi vardır, amaçları için prosedürel nesne kablolarının çoğunu sizin için otomatik olarak yalnızca tanımlardan yararlanarak yapmaktır. Ne yazık ki, bu vesileyle cevapların çoğu bu noktayı kaçırıyor.
zakmck

12

Birkaç yıl boyunca Python kullanmadım, ancak dinamik olarak yazılmış bir dil olmaktan başka her şeyden daha çok şey olduğunu söyleyebilirim. Basit bir örnek olarak, Java'da, bir şeyin uygun şekilde standart olarak yazıldığını test etmek istersem, DI'yi kullanabilir ve yazılan metni yakalamak ve doğrulamak için herhangi bir PrintStream'i geçebilirim. Ancak Ruby'de çalışırken, doğrulamak için STDOUT'ta 'koyar' yöntemini dinamik olarak değiştirebilirim, DI'yi tamamen resim dışında bırakabilirim. Bir soyutlama oluşturmamın tek nedeni, onu kullanan sınıfı test etmekse (Dosya sistemi işlemlerini veya Java'da saati düşünün) o zaman DI / IoC çözümde gereksiz karmaşıklık yaratır.


3
Bir sistemin çalıştığını test etmek için nasıl çalıştığını değiştirmek isteyen insanların beni şaşırtması asla bitmez. Şimdi testlerinizin yan etkilere neden olmadığını test etmeniz gerekiyor.
Temel

2
koyar yöntemini sadece testler kapsamında değiştirmekten bahsediyor, enjekte edilen nesnenin sahte yöntemi gibi.
dpa

2
@Birim testlerinde oldukça normal olan , test testinin kapsamını birden fazla kod bloğuyla (test edilen kod) kirletmek istemediğiniz için aslında bu testlerde yapılması tavsiye edilir. Entegrasyon testleri için bunu yapmak yanlış olur, belki de yorumunuzda bahsettiğiniz şey budur?
samuelgrigolato

1
Benim için test edilebilirlik birinci sınıf bir konudur. Bir tasarım test edilemezse, iyi bir tasarım değildir ve daha test edilebilir hale getirmek için tasarımı değiştirmekte sorun yaşamıyorum. Hala işe yaradığını tekrar doğrulamam gerekecek, ama sorun değil. Ahit edilebilirlik IMO kodunu değiştirmek için mükemmel geçerli bir nedendir
Carlos Rodriguez

10

Aslında, DI ile yeterince temiz ve kompakt bir kod yazmak oldukça kolaydır (acaba, o zaman / sonra pythonic olacak , ama yine de :)), örneğin ben aslında bu kodlama yolu perefer:

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!

Evet, bu sadece fonksiyonları / sınıfları parametreleştirmenin basit bir biçimi olarak görülebilir, ancak işini yapar. Yani, belki de Python'un varsayılan dahil pilleri burada da yeterlidir.

PS Python'da basit boole mantığını dinamik olarak değerlendirirken bu naif yaklaşımın daha büyük bir örneğini de yayınladım .


3
Çalışabilecek basit durumlar için, ancak çeşitli modeller (Yazı, Yorum, Kullanıcı) kullanan basit bir web blog denetleyicisi hayal edin. Kullanıcının kendi Post modelini (bunu izlemek için ek bir viewcount özniteliğiyle) ve daha fazla profil bilgisi ve benzeri kendi Kullanıcı modelini enjekte etmesini istiyorsanız, tüm parametreler kafa karıştırıcı görünebilir. Ayrıca, kullanıcı, basit çerez tabanlı oturum veya bunun gibi bir şey yerine dosya sistemi oturumunu desteklemek için Request nesnesini de değiştirmek isteyebilir ... Yani, kısa süre içinde çok sayıda parametre ile karşılaşacaksınız.
tux21b

1
@ tux21b Kullanıcılar uygulamanın uygulamak istediği "temel karmaşıklık" var, mimari çözümler var (bazıları geliştirme ve bakım süresi, yürütme hızı, vb. açısından geri kalanlardan daha kötü değil) . ) ve API ve yazılım mimarisini anlama yeteneği vardır. İnsan tarafından anlaşılabilir bir çözüm yoksa (sadece DI (herhangi bir şekilde) kullanan kişiler arasında değil) ... peki, tüm problemlerin çözülebileceğini kim söyledi? Varsayılan olarak atanmış (ancak kullanıcının tercihine göre değiştirilebilen) parametrelerin olması aslında sık sık yeterli olabilir.
18:10 tarihinde mlvljr

9

IoC / DI bir tasarım konseptidir, ancak maalesef genellikle belirli diller (veya yazım sistemleri) için geçerli bir kavram olarak kabul edilir. Bağımlılık enjeksiyon kaplarının Python'da çok daha popüler hale geldiğini görmek isterim. Bahar var, ama bu bir süper çerçeve ve "Python Way" i dikkate almadan Java kavramlarının doğrudan bir limanı gibi görünüyor.

Python 3'teki Ek Açıklamalar verildiğinde, tam özellikli, ancak basit bir bağımlılık enjeksiyon kabında bir çatlamaya karar verdim: https://github.com/zsims/dic . Bir .NET bağımlılık enjeksiyon kapsayıcısından (o alanda oynuyorsanız IMO'nun harika olduğu) bazı kavramlara dayanmaktadır, ancak Python kavramlarıyla mutasyona uğramıştır.


6

Python'un dinamik doğası nedeniyle insanların sıklıkla başka bir dinamik çerçeveye ihtiyaç duymadığını düşünüyorum. Bir sınıf yeni stil 'nesnesinden' miras alındığında dinamik olarak yeni bir değişken oluşturabilirsiniz ( https://wiki.python.org/moin/NewClassVsClassicClass ).

yani düz python'da:

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

Ancak https://github.com/noodleflake/pyioc adresine bakın, aradığınız şey bu olabilir.

yani pyioc'ta

from libs.service_locator import ServiceLocator

#main.py
ServiceLocator.register(PostgresConnection)

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

2
Her iki versiyonun da aynı miktarda kod alması, bir çerçevenin kullanılmasının neden çok popüler olmadığını açıklamak için uzun bir yol kat ediyor.
spektrumlar

Gelen other.pyhat 1, otomatik bir bağımlılık çözünürlüğü yoktur fakat yine de bir bağımlılık enjeksiyon olarak sayar olmaz.
andho

Hizmet konum belirleyiciler genellikle sadece bir anti-kalıptır.
PmanAce

6

"Jörg W Mittag" cevabını geri verdim: "DI / IoC'nin Python uygulaması o kadar hafif ki tamamen yok oluyor".

Bu ifadeyi yedeklemek için Java'dan Python'a taşınan ünlü Martin Fowler örneğine bir göz atın: Python: Design_Patterns: Inversion_of_Control

Yukarıdaki bağlantıdan da görebileceğiniz gibi, Python'da bir "Kapsayıcı" 8 kod satırına yazılabilir:

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
Bu, en zayıf DI kaplarından bile çok kısadır. Yaşam boyu yönetim, özyinelemeli bağımlılık çözünürlüğü, alay etme yeteneği veya - tüm bunlarda başarısız olma - yapılandırma nerede? Bu, IoC ile aynı şey olmayan bir tür arama ve önbellekten başka bir şey değildir .
Temel

2
Yıllar önce metasınıfları egzersiz olarak kullanarak küçük bir DI çerçevesi yazdım . Her şey sıfır ithalatı ve kendi kendini açıklayan doctests ile tek bir dosyadır. Temel özelliklerin bile "pitonik" bir şekilde uygulanması zor olmadığını gösteriyor, ancak içtenlikle, Spring'in Java'da olduğu gibi tam bir çözümün büyük bir çekişe sahip olmamış olması ve herkesin özel eklenti mimarileri yapması üzücü.
Andrea Ratto

2

Benim 2 sentim, çoğu Python uygulamasında buna ihtiyaç duymamanız ve ihtiyacınız olsa bile, birçok Java şapkacısının (ve geliştirici olduğuna inanan beceriksiz kemancıların) bunu sadece Java'da popüler olduğu için kötü bir şey olarak görmesidir. .

Bir IoC sistemi aslında, her bir nesnenin diğerlerine bağımlı olabileceği ve kendisi de diğer nesnelere bağımlı olabileceği karmaşık nesne ağlarınız olduğunda yararlıdır. Böyle bir durumda, tüm bu nesneleri bir kez tanımlamak ve bunları mümkün olduğunca fazla örtük kurala dayalı olarak otomatik olarak bir araya getirmek için bir mekanizmaya sahip olmak istersiniz. Uygulama kullanıcısı / yöneticisi tarafından basit bir şekilde tanımlanacak konfigürasyonunuz varsa, bileşenlerini basit bir XML dosyası (konfigürasyon olacaktır) gibi bir şeyden okuyabilen bir IoC sistemini istemenin ek bir nedeni de budur.

Tipik Python uygulaması, bu kadar karmaşık bir mimari olmadan çok daha basit, sadece bir dizi komut dosyasıdır. Şahsen bir IoC'nin gerçekte ne olduğunu biliyorum (burada belirli cevaplar yazanların aksine) ve sınırlı Python deneyimimde buna hiç ihtiyaç duymadım (ayrıca her yerde Spring kullanmıyorum, avantajlar olduğunda verir onun geliştirme yükü haklı değil).

Bununla birlikte, IoC yaklaşımının gerçekten yararlı olduğu Python durumları var ve aslında burada Django'nun kullandığını okudum.

Yukarıdaki aynı mantık, Java dünyasındaki Aspect Oriented Programming'e de uygulanabilir, ancak AOP'nin gerçekten değerli olduğu vaka sayısının daha da sınırlı olması farkı.


Django'nun IoC'yi kullandığı bilgi kaynağı için bir referans URL var mı?
Sajuuk

@Sajuuk, Django hakkında bu sorunun konusunu öğrendim, bu yüzden bilmiyorum, diğer cevap yazarlarına sormalısın.
18:35

Bu cevabın ilk alinea bence 0 katıyor ... Bence python kodum IoC'den ne zaman faydalanacağına karar verebiliyorum ve geliştiricinin neyin kötü olduğunu düşündüğü umrumda değil. Ben pragmatizmi temelsiz görüşler üzerinde değerlendiriyorum.
Mike de Klerk

@MikedeKlerk benim önerim, hem bilinmeyen (burada birçok yanıtın kanıtladığı gibi) hem de önyargı kurbanı olan bir şeyin, sizin gibi birkaç objektif ve iyi bilgilendirilmiş olursa olsun, popüler olma olasılığı düşük olmasıdır. Ve elbette bunun Python'da çok sayıda IoC kullanımını görmemenizin bir nedeni olduğundan emin değilim, bence asıl neden düşük / orta compexity uygulamalarının bunlara ihtiyacı yok.
zakmck

The typical Python application is much simpler, just a bunch of scripts, without such a complex architecture.- oldukça varsayım
hyankov


-1

@Jorg ile DI / IoC'nin Python'da mümkün, daha kolay ve daha güzel olduğu konusunda hemfikirim. Eksik olan, onu destekleyen çerçeveler, ancak birkaç istisna var. Aklıma gelen birkaç örneği işaret etmek için:

  • Django yorumları, kendi Yorum sınıfınızı özel mantık ve formlarınızla ilişkilendirmenizi sağlar. [Daha fazla bilgi]

  • Django, Kullanıcı modelinize eklemek için özel bir Profil nesnesi kullanmanıza izin verir. Bu tamamen IoC değil, iyi bir yaklaşım. Şahsen ben yorum çerçevesi gibi Kullanıcı modeli delik değiştirmek istiyorum. [Daha fazla bilgi]


-3

Bence, bağımlılık enjeksiyonu gibi şeyler katı ve aşırı karmaşık bir çerçevenin belirtileridir. Kodun ana gövdesi kolayca değiştirilemeyecek kadar ağır hale geldiğinde, küçük parçalarını seçmek, onlar için arayüzler tanımlamak ve daha sonra insanların bu arayüzlere takılan nesneler aracılığıyla davranışlarını değiştirmesine izin vermek zorunda kalırsınız. Her şey yolunda ve iyi, ama ilk etapta bu tür karmaşıklıklardan kaçınmak daha iyidir.

Aynı zamanda statik olarak yazılmış bir dilin belirtisidir. Soyutlamayı ifade etmeniz gereken tek araç kalıtım ise, o zaman hemen hemen her yerde kullandığınız şey budur. Bunu söyledikten sonra, C ++ oldukça benzerdir, ancak Java geliştiricilerinin yaptığı her yerde Builders ve Interfaces ile olan ilgiyi asla yakalayamadı. Çok az jenerik kod az gerçek fayda ile yazmanın pahasına esnek ve genişletilebilir olma hayaliyle aşırı coşkulu olmak kolaydır . Bence bu kültürel bir şey.

Tipik olarak Python insanları, her şey yapabilen ancak olası yapılandırma permütasyonlarının şaşırtıcı bir dizisini sunan One True Tool (Bin Olası Eklentiyle) yerine, tutarlı ve basit bir bütün olan iş için doğru aracı seçmeye alışkın olduğunu düşünüyorum . Gerektiğinde hala değiştirilebilir parçalar vardır, ancak ördek yazmanın esnekliği ve dilin göreceli sadeliği nedeniyle sabit arayüzleri tanımlamanın büyük biçimciliğine gerek yoktur.


4
Dilin kendisi kadar çerçeve değil. Ördek yazma dillerinin hoşlandığı türden bir esneklik oluşturmak için, statik olarak yazılan diller çok karmaşık çerçevelere ve kurallara ihtiyaç duyar. DI bu kurallardan biridir. Python millet iki kez düşünmüyor. Java millet gerçekten üzerinde çalışmak zorunda.
S.Lott

6
@ S.Lott - Java ile benzer kısıtlamalarla çalışmasına rağmen, C ++ çalışanlarının tasarım ve mimari kalıpların patlaması olmadan geçinmeleri dışında tamamen katılıyorum. Sanırım bu, bir şey yapmanın 2 olası yoluyla karşı karşıya kaldığında, Java halkının Strateji modelini kolaylaştırmak için başka bir arayüz çıkarmayı tercih ederken, C ++ insanlarının hemen daldığı ve bir bool ve if ifadesi eklediği ...
Kylotan

3
@Finglas bu yüzden eğer bir düzine dersim varsa benim kullanarak EmailSenderve yerine a ile karar vermek DesktopNotifier, gitmek ve 12 sınıf elle düzenlemek zorunda. Ve sadece bir INotifierarayüze yazmanın ve konteynerin ayrıntıları çözmesine izin vermenin daha basit ve daha temiz olduğunu mu düşünüyorsunuz ?
Temel

1
Ne yazık ki, belirli bir karmaşıklık düzeyi, profesyonel yazılım geliştiricilerinin karşılaşması gereken bir gerçektir. Eleştiriler görüyorum ama bu cevapta çözüm yok. Bu sorun için "pythonic" çözüm nedir: Bir kütüphane yazıyorum ve günlüğü (PHP PSR-3 LoggerInterface gibi bir şey) için bir kanca sağlamak istiyorum. Günlük düzeylerini nasıl kullanacağımı biliyorum, ancak programın gerçekte bunları nasıl rapor ettiği umurumda değil. İstemci uygulamasının bu uygulama ayrıntısını enjekte etmesine izin vermenin temiz yolu nedir ? Not: Uygulamanın diğer bölümleri bu arabirimin farklı uygulamalarına sahip olabilir.
Rob

2
Benim için sorum, standart günlük kitaplığını nasıl kullanacağınız veya bir günlükçü sınıfının farklı örneklerini oluşturmakla ilgili değil. Benim sorum, uygulamanızın farklı bölümlerinin farklı uygulamalar kullanabilmesi ve bu ayrıntılarla ilgilenmemesi için (arayüzün nasıl kullanılacağını bilmeleri koşuluyla) uygulamanızı nasıl yapılandırdığınızdır. Bu, DI'nin üzerinde çalıştığım birden fazla PHP uygulaması için çözdüğü çok gerçek bir sorundur. Python eşdeğerini arıyorum. Ve "sadece uygulamanızı bu kadar karmaşık yapmayın" demek, aradığım cevap değildir.
Rob

-5

Java güçlü yazılan doğanın aksine. Python'un ördek yazma davranışı, nesneleri etrafta geçirmeyi çok kolaylaştırır.

Java geliştiricileri, sınıf esnekliğini ve nesneler arasındaki ilişkiyi oluşturmaya odaklanırken, işleri esnek tutarlar. IoC bunu başarmak için son derece önemlidir.

Python geliştiricileri işi bitirmeye odaklanıyor. Sadece ihtiyaç duyduklarında sınıfları bağlarlar. Sınıfın türü hakkında endişelenmelerine bile gerek yok. Sürdürebildiği sürece, bu bir ördek! Bu doğa IoC'ye yer bırakmıyor.


4
Hâlâ becerikli olan bir şey bulmalısın.
andho
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.