Mengapa IoC / DI tidak umum di Python?


313

Dalam Java IoC / DI adalah praktik yang sangat umum yang banyak digunakan dalam aplikasi web, hampir semua kerangka kerja yang tersedia dan Java EE. Di sisi lain, ada juga banyak aplikasi web Python besar, tetapi selain Zope (yang saya dengar seharusnya benar-benar mengerikan untuk dikodekan) IoC tampaknya tidak terlalu umum di dunia Python. (Sebutkan beberapa contoh jika Anda berpikir saya salah).

Tentu saja ada beberapa klon kerangka Java IoC populer yang tersedia untuk Python, springpython misalnya. Tapi sepertinya tidak satu pun dari mereka yang terbiasa. Paling tidak, saya belum pernah menemukan aplikasi web berbasis Django atau sqlalchemy + <insert your favorite wsgi toolkit here>yang menggunakan sesuatu seperti itu.

Menurut pendapat saya IoC memiliki kelebihan yang masuk akal dan akan membuatnya mudah untuk menggantikan django-default-user-model misalnya, tetapi penggunaan yang luas dari kelas antarmuka dan IoC di Python terlihat sedikit aneh dan tidak »pythonic«. Tapi mungkin seseorang memiliki penjelasan yang lebih baik, mengapa IoC tidak banyak digunakan dalam Python.


2
Dugaan saya, alasan yang sama bahwa itu kurang populer di Ruby, built-in mixin dan kelas terbuka
Sam Saffron

3
Anda pernah mencoba springpython? bahkan tidak berfungsi seperti yang diiklankan. setidaknya di bagian atas. semua yang lain di sana tidak terlalu berguna kecuali Anda berasal dari java dan membutuhkan tingkat kenyamanan selama masa transisi.
Tom Willis

6
Harap berhati-hati untuk membedakan antara penggunaan DI, dan penggunaan kerangka kerja IOC. Yang pertama adalah pola desain, yang terakhir adalah kerangka kerja untuk membantu dalam penggunaan otomatis yang pertama.
Doug

Doug, saya yakin Anda bermaksud mengatakan DI adalah fitur kreasi yang diperoleh dengan menggunakan pola Dekorator.
njappboy

4
Saya ingin sekali melihat jawaban yang mengatasi masalah dunia nyata yang dipecahkan DI: manajemen seumur hidup, kemudahan pengujian, dll. Jika ada cara yang lebih Pythonic untuk mengatasi ini, saya semua tahu.
Josh Noe

Jawaban:


198

Saya tidak benar-benar berpikir bahwa DI / IIC itu tidak biasa dengan Python. Apa yang jarang, bagaimanapun, adalah DI / IOC kerangka / kontainer .

Pikirkan tentang hal ini: apa yang dilakukan wadah DI? Ini memungkinkan Anda

  1. menyatukan komponen independen menjadi aplikasi lengkap ...
  2. ... saat runtime.

Kami memiliki nama untuk "kabel bersama" dan "saat runtime":

  1. scripting
  2. dinamis

Jadi, wadah DI tidak lain adalah juru bahasa bahasa skrip yang dinamis. Sebenarnya, izinkan saya ulangi bahwa: Java / .NET DI container yang khas tidak lain adalah interpreter jelek untuk bahasa scripting dinamis yang sangat buruk dengan sintaks butt-ugly, terkadang berbasis XML,.

Ketika Anda memprogram dengan Python, mengapa Anda ingin menggunakan bahasa skrip yang jelek dan buruk saat Anda memiliki bahasa skrip yang indah dan cemerlang yang Anda inginkan? Sebenarnya, itu adalah pertanyaan yang lebih umum: ketika Anda memprogram dalam hampir semua bahasa, mengapa Anda ingin menggunakan bahasa scripting yang jelek dan buruk ketika Anda memiliki Jython dan IronPython yang Anda inginkan?

Jadi, untuk rekap: praktek DI / IoC sama pentingnya dengan Python seperti di Jawa, untuk alasan yang persis sama. Namun implementasi DI / IoC, dibangun ke dalam bahasa dan seringkali sangat ringan sehingga benar-benar hilang.

(Berikut adalah ringkasan singkat untuk analogi: dalam pertemuan, panggilan subrutin adalah masalah yang cukup besar - Anda harus menyimpan variabel lokal dan mendaftar ke memori, menyimpan alamat pengirim di suatu tempat, mengubah penunjuk instruksi ke subrutin yang Anda panggil, mengatur agar entah bagaimana melompat kembali ke subrutin Anda ketika sudah selesai, letakkan argumen di suatu tempat di mana callee dapat menemukan mereka, dan sebagainya.TKI: dalam pertemuan, "panggilan subrutin" adalah Pola Desain, dan sebelum ada bahasa seperti Fortran yang memiliki panggilan subrutin dibangun, orang-orang membangun "kerangka kerja subrutin" mereka sendiri. Apakah Anda mengatakan bahwa panggilan subrutin "tidak umum" dengan Python, hanya karena Anda tidak menggunakan kerangka kerja subrutin?)

BTW: untuk contoh seperti apa untuk mengambil DI kesimpulan logis, lihatlah Gilad Bracha 's Newspeak Pemrograman Bahasa dan tulisan-tulisannya tentang subjek:


58
Meskipun saya setuju. Komentar XML salah. Banyak (setidaknya modern) wadah IOC menggunakan konvensi (kode) lebih dari konfigurasi (XML).
Finglas

20
Tidak ada yang mencegah Anda menulis kabel secara eksplisit di Jawa, tetapi karena Anda memiliki lebih banyak dan lebih banyak layanan, dependensi menjadi lebih kompleks. Wadah DI seperti Make: Anda mendeklarasikan dependensi dan wadah menginisialisasi mereka dalam urutan yang benar. Guice adalah kerangka kerja Java DI di mana semuanya ditulis dalam kode Java. Dengan menulis secara deklaratif, sebuah wadah DI juga menambahkan dukungan untuk pemrosesan pos deklerasi sebelum inisialisasi (mis., Ganti placeholder properti dengan nilai aktual)
IttayD

133
"Namun penerapan DI / IoC, dibangun ke dalam bahasa dan seringkali sangat ringan sehingga benar-benar hilang." Tidak memilih karena ini jelas tidak benar. DI adalah pola di mana antarmuka dilewatkan ke konstruktor. Ini bukan bawaan di python.
Doug

146
downvote, kabel bersama-sama tidak ada hubungannya dengan scripting, DI adalah sebuah pola, dan itu tidak setara dengan scripting
Luxspes

38
Saya tidak setuju dengan ini. DI tidak menyelesaikan kekurangan skrip dinamis dalam bahasa statis. Ini memberikan kerangka kerja untuk mengkonfigurasi dan menyusun bagian aplikasi Anda. Saya pernah mendengar dev Ruby mengatakan bahwa DI tidak perlu dalam bahasa yang dinamis. Tapi dia menggunakan Rails ... Rails hanyalah sebuah wadah besar DI, yang menggunakan konvensi untuk mencari tahu bagian mana yang harus dikonfigurasi kapan. Dia tidak perlu DI karena Rails memecahkan masalah menemukan bagian untuknya.
Brian Genisio

51

Sebagian darinya adalah cara sistem modul bekerja dengan Python. Anda bisa mendapatkan semacam "singleton" secara gratis, hanya dengan mengimpornya dari modul. Tetapkan instance aktual dari suatu objek dalam sebuah modul, dan kemudian kode klien apa pun dapat mengimpornya dan benar-benar mendapatkan objek yang berfungsi, sepenuhnya dibangun / diisi.

Ini berbeda dengan Java, di mana Anda tidak mengimpor instance objek yang sebenarnya. Ini berarti Anda harus selalu instantiate sendiri, (atau menggunakan semacam pendekatan gaya IoC / DI). Anda dapat mengurangi kerumitan karena harus mem-instantiasi semuanya sendiri dengan memiliki metode pabrik statis (atau kelas pabrik aktual), tetapi kemudian Anda masih mengeluarkan overhead sumber daya untuk benar-benar membuat yang baru setiap kali.


2
Itu masuk akal. Jika saya ingin mengubah implementasi dengan Python, saya cukup mengimpor dari lokasi lain menggunakan nama yang sama. Tapi sekarang saya berpikir apakah mungkin juga sebaliknya dengan mendefinisikan MyClassInstanceskelas untuk masing-masing MyClassdi Jawa, yang hanya berisi contoh statis, diinisialisasi penuh. Itu akan ditransfer: D
tux21b

2
Dan ide lain: Menyediakan cara untuk mengubah impor seperti itu di python akan memungkinkan untuk mengganti implementasi dengan mudah tanpa menyentuh semua file python. Alih-alih from framework.auth.user import User mungkin lebih baik untuk menulis User = lookup('UserImplentation', 'framework.auth.user.User')(parameter ke-2 mungkin nilai default) di dalam kerangka kerja. Kemudian pengguna kerangka kerja akan dapat mengganti / mengkhususkan Userimplementasi tanpa menyentuh kerangka kerja.
tux21b

14
Menyederhanakan, menjawab, dalam kehidupan nyata, Anda jarang membutuhkan "singleton", Anda perlu mengontrol ruang lingkup (Anda mungkin perlu utas singleton lokal, atau sesi singleton, dan sebagainya), ini membuat saya berpikir bahwa jenis masalah diselesaikan dengan Python bukan jenis masalah dunia nyata yang benar-benar diselesaikan dalam pengaturan perusahaan
Luxspes

3
Sebenarnya DI adalah tentang kemampuan untuk menguji dan memisahkan dependensi kode. Juga fitur impor mirip dengan impor statis di Jawa, yang memungkinkan saya mengimpor satu instance objek.
Richard Warburton

1
"Anda bisa mendapatkan semacam" singleton "secara gratis, hanya dengan mengimpornya dari sebuah modul." Dapat dengan mudah dilakukan di Java dengan mendeklarasikan bidang instance statis dan menyetelnya ke nilai. Ini bukan sol
ggranum

45

IoC dan DI adalah super umum dalam kode Python matang. Anda hanya tidak perlu kerangka kerja untuk menerapkan DI berkat mengetik bebek.

Contoh terbaik adalah bagaimana Anda mengatur aplikasi Django menggunakan 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 sangat memanfaatkan DI:

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

Biarkan saya ingatkan ( sumber ):

"Dependency Injection" adalah istilah 25 dolar untuk konsep 5 sen. [...] Ketergantungan injeksi berarti memberikan objek variabel instan. [...]


8
+1. Baik. Menjadi seorang programmer Python saya benar-benar bingung oleh seluruh presentasi wawancara tentang kerangka kerja DI di C #. Butuh waktu beberapa saat untuk menyadari bahwa saya sudah melakukannya sepanjang waktu di aplikasi Flask tanpa memikirkannya karena Anda tidak memerlukan kerangka kerja. Bagi seseorang yang tidak tahu apa-apa selain C # / Java, pertanyaannya masuk akal. Bagi pemrogram bahasa yang diketik bebek itu wajar dan seperti yang Anda katakan, "istilah 25 dolar untuk konsep 5 sen".
Samuel Harmer

5
err ... ini bukan injeksi ketergantungan karena instance ( IsAuthenticated, ScopedRateThrottle) dipakai oleh kelas. Mereka tidak diteruskan ke konstruktor.
dopatraman

5
IsAuthenticateddan ScopedRateThrottlebukan contoh, ini adalah kelas. Mereka dipakai saat FooView dibangun (sebenarnya, ketika FooView memproses permintaan). Bagaimanapun, ini hanyalah detail implementasi.IsAuthenticateddan ScopedRateThrottleapakah dependensinya; mereka disuntikkan ke dalam FooView. Tidak masalah kapan atau bagaimana hal ini dilakukan. Python bukan Java, jadi ada berbagai cara untuk mengimplementasikannya.
Max Malysh

3
@ Maxmalysh Saya setuju dengan dopatraman yang satu ini. Ini bahkan bukan IoC karena kelas itu sendiri memiliki "hardcoded" dependensi ke kelas tertentu. Di IoC, dependensi harus diberikan alih-alih hardcoded. Selain itu, dalam Injeksi Ketergantungan, Anda akan memiliki entitas yang bertanggung jawab mengelola siklus hidup setiap layanan dan menyuntikkan mereka ketika itu terjadi. Solusi yang diberikan tidak semuanya.
Ricardo Alves

3
@ alex Tidak, Anda tidak perlu mengubah kode Anda untuk menggunakan renderer lain. Anda bahkan dapat menggunakan beberapa penyaji secara bersamaan: renderer_classes = (JSONRenderer, BrowsableAPIRenderer, XMLRenderer). Mengejek sesederhana itu @unittest.patch('myapp.views.FooView.permission_classes'). Kebutuhan putus asa untuk "lulus sesuatu" adalah konsekuensi dari "cara Jawa melakukan sesuatu" karena Jawa menjadi bahasa yang dikompilasi dan diketik secara statis tanpa kemampuan metaprogramming yang kuat.
Max Malysh

35

Django memanfaatkan inversi kontrol. Sebagai contoh, server database dipilih oleh file konfigurasi, maka kerangka kerja menyediakan contoh pembungkus database yang sesuai untuk klien database.

Perbedaannya adalah bahwa Python memiliki tipe kelas satu. Tipe data, termasuk kelas, adalah objek itu sendiri. Jika Anda ingin sesuatu menggunakan kelas tertentu, cukup beri nama kelas tersebut. Sebagai contoh:

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

Kemudian kode dapat membuat antarmuka database dengan menulis:

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

Alih-alih fungsi pabrik boilerplate yang dibutuhkan Java dan C ++, Python melakukannya dengan satu atau dua baris kode biasa. Ini adalah kekuatan pemrograman fungsional versus imperatif.


4
Apa yang Anda sebut kode sebenarnya adalah bagian kabel. Itu akan menjadi XML kerangka kerja ioc Anda. Itu sebenarnya bisa ditulis hanya sebagai import psycopg2 as database_interface. Masukkan baris itu di injections.pyet voilà.
spektrum

29
Erm Apa yang Anda lakukan di sana adalah cukup banyak buku ajar Daniel.
Shayne

Ini jelas merupakan kode yang sangat penting, tetapi agak fungsional karena menggunakan nilai yang bisa dipanggil.
Jeremy

5
Bukankah itu hanya Fungsi Kelas Satu? en.wikipedia.org/wiki/First-class_function Hanya karena Anda memiliki dan menggunakannya tidak membuat kode Anda Fungsional. Ada beberapa efek samping yang terjadi di sini (seperti perubahan self.database_interface), yang meneriakkan keharusan.
hjc1710

15

Terlihat bahwa orang benar-benar tidak mendapatkan apa yang dimaksud dengan injeksi Ketergantungan dan inversi kendali.

Praktik menggunakan inversi kontrol adalah memiliki kelas atau fungsi yang bergantung pada kelas atau fungsi lain, tetapi alih-alih membuat instance di dalam kelas kode fungsi, lebih baik menerimanya sebagai parameter, sehingga sambungan longgar dapat diarsipkan. Itu memiliki banyak manfaat karena lebih mudah diuji dan untuk mengarsipkan prinsip substitusi liskov.

Anda tahu, dengan bekerja dengan antarmuka dan injeksi, kode Anda menjadi lebih dapat dikelola, karena Anda dapat mengubah perilaku dengan mudah, karena Anda tidak perlu menulis ulang satu baris kode (mungkin satu atau dua baris pada konfigurasi DI) dari Anda kelas untuk mengubah perilakunya, karena kelas yang mengimplementasikan antarmuka yang ditunggu oleh kelas Anda dapat bervariasi secara independen selama mereka mengikuti antarmuka. Salah satu strategi terbaik untuk menjaga kode dipisahkan dan mudah dipelihara adalah dengan mengikuti setidaknya prinsip responsabilitas tunggal, substitusi dan ketergantungan.

Apa yang baik untuk perpustakaan DI jika Anda dapat membuat instance objek sendiri di dalam sebuah paket dan mengimpornya untuk menyuntikkannya sendiri? Jawaban yang dipilih benar, karena java tidak memiliki bagian prosedural (kode di luar kelas), semua itu masuk ke konfigurasi xml membosankan, maka kebutuhan kelas untuk instantiate dan menyuntikkan dependensi pada mode pemuatan yang malas sehingga Anda tidak terhanyut. kinerja Anda, sementara di python Anda hanya kode injeksi pada bagian "prosedural" (kode di luar kelas) dari kode Anda


Anda masih merindukan bahwa IoC / DI menyatukan objek secara otomatis. Tidak banyak yang bisa dilakukan saat runtime (Java tetap bisa melakukannya melalui refleksi), itu kerangka kerja yang mengurusnya dan Anda tidak perlu melakukannya secara eksplisit. Memiliki bagian prosedural juga tidak relevan, tidak ada yang mencegah seseorang untuk menulis aplikasi yang sepenuhnya prosedural di Jawa, dengan menggunakan kelas sebagai wadah subrutin dan fungsi statis, tanpa menggunakan fitur OOP sama sekali.
zakmck

@ zakmck: bagian "prosedural" dari Python di sini bukan tentang menulis kode prosedural. Apa yang membuat bagian "prosedural" dari Python berbeda dari bahasa statis adalah kemampuan untuk menempatkan kode prosedural dalam badan kelas, yang berjalan selama waktu definisi kelas, dan menempatkan pernyataan impor di dalam if-statement, dan untuk membuat pabrik kelas hanya dengan mendefinisikan kelas di dalam metode pabrik. Ini adalah hal-hal yang tidak dapat Anda lakukan dalam bahasa statis, dan yang memecahkan sebagian besar masalah yang coba diselesaikan oleh IOC / DI. Metaprogramming dalam Python sering terlihat seperti kode Python biasa.
Lie Ryan

@ LieRyan, Anda dapat melakukan itu dengan refleksi, atau, jika Anda sering membutuhkannya atau saat runtime, Anda dapat memanggil bahasa statis dari bahasa lain seperti Groovy (yang dirancang untuk mudah bermain dengan Java), atau bahkan Python sendiri. Namun, itu tidak ada hubungannya dengan kerangka kerja IoC / DI, karena tujuannya adalah untuk melakukan sebagian besar objek prosedural kabel untuk Anda, secara otomatis, memanfaatkan definisi saja. Sedihnya, sebagian besar jawaban dengan ini melewatkan poin ini.
zakmck

12

Belum pernah menggunakan Python dalam beberapa tahun, tapi saya akan mengatakan bahwa itu lebih berkaitan dengan itu menjadi bahasa yang diketik secara dinamis daripada yang lain. Sebagai contoh sederhana, di Jawa, jika saya ingin menguji bahwa sesuatu menulis ke standar dengan tepat, saya dapat menggunakan DI dan meneruskan PrintStream apa pun untuk menangkap teks yang sedang ditulis dan memverifikasinya. Ketika saya bekerja di Ruby, bagaimanapun, saya dapat secara dinamis mengganti metode 'menempatkan' pada STDOUT untuk melakukan verifikasi, meninggalkan DI sepenuhnya keluar dari gambar. Jika satu-satunya alasan saya membuat abstraksi adalah untuk menguji kelas yang menggunakannya (pikirkan operasi sistem file atau jam di Jawa) maka DI / IoC menciptakan kompleksitas yang tidak perlu dalam solusi.


3
Tidak pernah berhenti membuat saya takjub bahwa orang-orang mau mengubah cara suatu sistem bekerja untuk menguji apakah itu berhasil. Sekarang Anda perlu menguji bahwa tes Anda tidak menimbulkan efek samping.
Dasar

2
ia berbicara tentang mengubah metode menempatkan hanya dalam lingkup tes, itu seperti metode tiruan dari objek yang disuntikkan.
dpa

2
@Basic itu cukup normal dalam unit test , sebenarnya disarankan untuk melakukan itu dalam tes ini karena Anda tidak ingin mencemari cakupan test case Anda dengan lebih dari satu blok kode (yang sedang diuji). Akan salah untuk melakukan itu untuk tes integrasi, mungkin itu yang Anda maksudkan pada komentar Anda?
samuelgrigolato

1
Bagi saya, testability adalah perhatian kelas satu. Jika suatu desain tidak dapat diuji, itu bukan desain yang baik, dan saya tidak punya masalah mengubah desain untuk membuatnya lebih dapat diuji. Saya harus memvalidasi ulang bahwa itu masih berfungsi, tapi tidak apa-apa. Testabilitas adalah alasan yang sah untuk mengubah kode IMO
Carlos Rodriguez

10

Sebenarnya, cukup mudah untuk menulis kode yang cukup bersih dan ringkas dengan DI (saya ingin tahu, apakah akan / tetap pythonic , tapi tetap :)), misalnya saya benar-benar perefer cara pengkodean ini:

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!

Ya, ini dapat dilihat hanya sebagai bentuk sederhana dari fungsi / kelas parameterisasi, tetapi berfungsi dengan baik. Jadi, mungkin baterai yang disertakan secara default Python sudah cukup di sini juga.

PS Saya juga memposting contoh yang lebih besar dari pendekatan naif ini di Dynamically mengevaluasi logika boolean sederhana dengan Python .


3
Untuk kasus sederhana yang mungkin berhasil, tetapi bayangkan pengontrol blog web sederhana, yang menggunakan berbagai model (Posting, Komentar, Pengguna). Jika Anda ingin pengguna menyuntikkan model Post-nya sendiri (dengan atribut viewcount tambahan untuk melacaknya), dan model Pengguna-nya sendiri dengan lebih banyak informasi profil dan sebagainya, semua parameter mungkin terlihat membingungkan. Selain itu, pengguna mungkin ingin mengubah objek Permintaan juga, untuk mendukung sesi sistem file, bukan sesi berdasarkan cookie sederhana atau sesuatu seperti itu ... Jadi, Anda akan berakhir dengan banyak parameter segera.
tux21b

1
@ tux21b Nah, ada "kompleksitas esensial" yang diinginkan pengguna untuk mengimplementasikan aplikasi, ada solusi arsitektural untuk itu (beberapa di antaranya tidak lebih buruk dari yang lain dalam hal pengembangan dan mungkin waktu pemeliharaan, kecepatan eksekutif, dll. ), dan ada kemampuan manusia untuk memahami API dan arsitektur perangkat lunak. Jika tidak ada solusi yang dapat dipahami manusia sama sekali (tidak hanya di antara mereka yang menggunakan (bentuk apa pun) DI) ... yah, siapa yang mengatakan bahwa semua masalah dapat dipecahkan? Dan memiliki banyak parameter yang ditetapkan secara default (tetapi swappable berdasarkan pilihan pengguna) sebenarnya cukup memadai.
mlvljr

9

IoC / DI adalah konsep desain, tetapi sayangnya sering diambil sebagai konsep yang berlaku untuk bahasa tertentu (atau sistem pengetikan). Saya ingin melihat wadah injeksi ketergantungan menjadi jauh lebih populer di Python. Ada Spring, tapi itu super-framework dan tampaknya menjadi port langsung dari konsep Java tanpa banyak pertimbangan untuk "The Python Way."

Diberikan Penjelasan dalam Python 3, saya memutuskan untuk memiliki celah pada wadah injeksi fitur lengkap, namun sederhana, ketergantungan: https://github.com/zsims/dic . Ini didasarkan pada beberapa konsep dari wadah injeksi .NET dependensi (yang IMO fantastis jika Anda pernah bermain di ruang itu), tetapi bermutasi dengan konsep Python.


6

Saya pikir karena sifat dinamis dari python, orang tidak sering melihat perlunya kerangka kerja dinamis lainnya. Ketika sebuah kelas mewarisi dari 'objek' gaya baru, Anda dapat membuat variabel baru secara dinamis ( https://wiki.python.org/moin/NewClassVsClassicClass ).

yaitu Dalam python biasa:

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

Namun lihatlah https://github.com/noodleflake/pyioc ini mungkin yang Anda cari.

yaitu Dalam pyioc

from libs.service_locator import ServiceLocator

#main.py
ServiceLocator.register(PostgresConnection)

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

2
Kenyataan bahwa kedua versi mengambil jumlah kode yang sama jauh menjelaskan mengapa menggunakan kerangka kerja tidak terlalu populer.
spektrum

Pada other.pybaris 1, ada resolusi ketergantungan otomatis, tetapi tidak akan menghitungnya sebagai injeksi ketergantungan.
andho

Penunjuk lokasi layanan biasanya anti-pola, hanya mengatakan.
PmanAce

6

Saya kembali "Jörg W Mittag" menjawab: "Implementasi Python DI / IoC sangat ringan sehingga benar-benar hilang".

Untuk mencadangkan pernyataan ini, lihat contoh terkenal Martin Fowler yang diangkut dari Jawa ke Python: Python: Design_Patterns: Inversion_of_Control

Seperti yang Anda lihat dari tautan di atas, "Wadah" dengan Python dapat ditulis dalam 8 baris kode:

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
Ini jauh dari wadah DI yang paling lemah sekalipun. Di mana manajemen seumur hidup, resolusi ketergantungan rekursif, kemampuan untuk mengejek, atau - gagal semua itu - konfigurasi? Ini tidak lebih dari pencarian tipe dan cache yang tidak sama dengan IoC.
Dasar

2
Bertahun-tahun yang lalu saya menulis kerangka DI kecil menggunakan metaclasses sebagai latihan. Semuanya adalah satu file dengan nol impor dan dokumen yang membuatnya cukup jelas. Ini menunjukkan bahwa fitur dasar tidak terlalu sulit untuk diimplementasikan dengan cara yang bahkan "pythonic", tetapi saya dengan tulus berpikir itu menyedihkan bahwa tidak ada solusi lengkap yang mendapatkan daya tarik utama seperti Spring di Jawa dan semua orang melakukan arsitektur plugin kustom.
Andrea Ratto

2

2 sen saya adalah bahwa dalam sebagian besar aplikasi Python Anda tidak memerlukannya dan, bahkan jika Anda membutuhkannya, kemungkinan besar banyak pembenci Java (dan pemain biola yang tidak kompeten yang percaya sebagai pengembang) menganggapnya sebagai sesuatu yang buruk, hanya karena itu populer di Jawa .

Sistem IoC sebenarnya berguna ketika Anda memiliki jaringan objek yang kompleks, di mana setiap objek mungkin menjadi ketergantungan bagi beberapa orang lain dan, pada gilirannya, menjadi dirinya sendiri tergantung pada objek lain. Dalam kasus seperti itu, Anda harus mendefinisikan semua objek ini sekali dan memiliki mekanisme untuk menyatukannya secara otomatis, berdasarkan sebanyak mungkin aturan implisit. Jika Anda juga memiliki konfigurasi yang harus didefinisikan secara sederhana oleh pengguna aplikasi / administrator, itu adalah alasan tambahan untuk menginginkan sistem IoC yang dapat membaca komponennya dari sesuatu seperti file XML sederhana (yang akan menjadi konfigurasi).

Aplikasi khas Python jauh lebih sederhana, hanya sekelompok skrip, tanpa arsitektur yang rumit. Secara pribadi saya mengetahui apa sebenarnya IoC (bertentangan dengan orang-orang yang menulis jawaban tertentu di sini) dan saya tidak pernah merasa perlu untuk itu dalam pengalaman Python terbatas saya (juga saya tidak menggunakan Spring di mana-mana, bukan ketika keuntungannya itu memberi tidak membenarkan biaya pengembangannya).

Yang mengatakan, ada situasi Python di mana pendekatan IoC sebenarnya berguna dan, pada kenyataannya, saya baca di sini bahwa Django menggunakannya.

Alasan yang sama di atas dapat diterapkan untuk Pemrograman Berorientasi Aspek di dunia Jawa, dengan perbedaan bahwa jumlah kasus di mana AOP benar-benar berharga bahkan lebih terbatas.


Apakah ada URL referensi ke sumber informasi di mana Django menggunakan IOC?
Sajuuk

@ Sajuuk, saya sudah tahu tentang Django di utas pertanyaan ini, jadi saya tidak tahu, Anda harus bertanya kepada penulis jawaban lain.
zakmck

Alinea pertama dari jawaban ini menambah nilai 0 menurut saya ... Saya pikir saya mampu memutuskan kapan kode python saya akan mendapat manfaat dari IoC, dan saya tidak peduli dengan apa yang dipikirkan pengembang apa yang buruk. Saya menghargai pragmatisme atas pendapat yang tidak berdasar.
Mike de Klerk

@MikedeKlerk saran saya adalah bahwa sesuatu yang keduanya tidak diketahui (seperti banyak jawaban dengan ini buktikan) dan korban prasangka tidak mungkin menjadi populer, tidak peduli seberapa objektif dan terinformasi dengan baik beberapa orang seperti Anda. Dan tentu saja saya tidak yakin ini adalah alasan mengapa Anda tidak melihat banyak penggunaan IoC di Python, saya pikir alasan utamanya adalah aplikasi compexity rendah / sedang tidak membutuhkannya.
zakmck

The typical Python application is much simpler, just a bunch of scripts, without such a complex architecture.- Asumsi yang cukup
hyankov


-1

Saya setuju dengan @Jorg dalam hal DI / IoC mungkin, lebih mudah dan bahkan lebih indah dengan Python. Apa yang hilang adalah kerangka kerja yang mendukungnya, tetapi ada beberapa pengecualian. Untuk menunjukkan beberapa contoh yang muncul di pikiran saya:

  • Komentar Django memungkinkan Anda mentransfer kelas Komentar Anda sendiri dengan logika dan formulir kustom Anda. [Info lebih lanjut]

  • Django memungkinkan Anda menggunakan objek Profil khusus untuk melampirkan ke model Pengguna Anda. Ini bukan sepenuhnya IOC tetapi merupakan pendekatan yang baik. Secara pribadi saya ingin mengganti model lubang Pengguna sebagai kerangka komentar tidak. [Info lebih lanjut]


-3

Menurut pendapat saya, hal-hal seperti injeksi ketergantungan adalah gejala dari kerangka kerja yang kaku dan terlalu rumit. Ketika bagian utama kode menjadi terlalu berat untuk diubah dengan mudah, Anda harus memilih bagian kecilnya, mendefinisikan antarmuka untuk mereka, dan kemudian memungkinkan orang untuk mengubah perilaku melalui objek yang dihubungkan ke antarmuka tersebut. Itu semua baik dan bagus, tetapi lebih baik untuk menghindari kompleksitas semacam itu sejak awal.

Ini juga merupakan gejala dari bahasa yang diketik secara statis. Ketika satu-satunya alat yang Anda miliki untuk mengekspresikan abstraksi adalah pewarisan, maka itulah yang Anda gunakan di mana-mana. Karena itu, C + + sangat mirip tetapi tidak pernah mengambil daya tarik dengan Builder dan Antarmuka di mana pun yang dilakukan pengembang Java. Sangat mudah untuk menjadi terlalu bersemangat dengan impian menjadi fleksibel dan dapat diperpanjang dengan biaya menulis kode generik yang terlalu banyak dengan sedikit manfaat nyata . Saya pikir ini hal budaya.

Biasanya saya pikir orang Python terbiasa memilih alat yang tepat untuk pekerjaan itu, yang merupakan keseluruhan yang koheren dan sederhana, daripada Alat Satu Sejati (Dengan Seribu Plugin Kemungkinan) yang dapat melakukan apa pun selain menawarkan berbagai kemungkinan konfigurasi permutasi yang membingungkan. . Masih ada bagian yang dapat dipertukarkan di mana diperlukan, tetapi tanpa perlu formalisme besar mendefinisikan antarmuka tetap, karena fleksibilitas mengetik bebek dan kesederhanaan relatif bahasa.


4
Kerangka kerjanya tidak sebanyak bahasa itu sendiri. Untuk menciptakan fleksibilitas yang dinikmati oleh bahasa pengetik bebek, bahasa yang diketik secara statis memerlukan kerangka kerja dan aturan yang sangat canggih. DI adalah salah satu dari aturan itu. Orang python tidak berpikir dua kali. Orang Jawa harus benar-benar bekerja keras.
S.Lott

6
@ S.Lott - Saya sepenuhnya setuju dengan Anda, kecuali bahwa orang-orang C ++ tampaknya bertahan tanpa ledakan desain dan pola arsitektur, meskipun bekerja dengan pembatasan yang sama dengan yang ada di Jawa. Saya pikir itu menyiratkan perbedaan budaya di mana, ketika dihadapkan dengan 2 cara yang mungkin untuk melakukan sesuatu, orang Jawa lebih suka untuk mengekstrak antarmuka lain untuk memfasilitasi pola Strategi sedangkan C ++ orang masuk dan menambahkan bool dan pernyataan if ...
Kylotan

3
@Finglas jadi jika saya memiliki selusin kelas semua menggunakan saya EmailSenderdan memutuskan untuk menggantinya dengan DesktopNotifier, saya harus pergi dan mengedit 12 kelas dengan tangan. Dan Anda pikir itu lebih sederhana dan lebih bersih yang hanya menulis ke INotifierantarmuka dan membiarkan wadah mengerjakan detailnya?
Dasar

1
Sayangnya, tingkat kerumitan tertentu adalah kenyataan yang harus dihadapi pengembang perangkat lunak profesional. Saya melihat kritik tetapi tidak ada solusi dalam jawaban ini. Apa solusi "pythonic" untuk masalah ini: Saya menulis perpustakaan dan saya ingin memberikan hook untuk logging (sesuatu seperti PHP PSR-3 LoggerInterface). Saya tahu cara menggunakan level log, tapi saya tidak peduli bagaimana sebenarnya program melaporkannya. Apa cara bersih untuk memungkinkan aplikasi klien menyuntikkan detail implementasi itu. Catatan: bagian lain dari aplikasi mungkin memiliki implementasi yang berbeda dari antarmuka ini.
Rob

2
Pertanyaan saya untuk Anda bukanlah bagaimana Anda menggunakan pustaka logging standar, juga tentang membuat instance berbeda dari kelas logger. Pertanyaan saya adalah bagaimana Anda mengkonfigurasi aplikasi Anda sehingga bagian-bagian berbeda dari aplikasi Anda dapat menggunakan implementasi yang berbeda, dan tidak peduli dengan detail tersebut (asalkan mereka tahu cara menggunakan antarmuka). Ini adalah masalah yang sangat nyata yang telah dipecahkan DI untuk beberapa aplikasi PHP yang telah saya kerjakan. Saya mencari yang setara dengan python. Dan menyarankan "jangan membuat aplikasi Anda serumit itu" bukanlah jawaban yang saya cari.
Rob

-5

Berbeda dengan alam yang diketik kuat di Jawa. Perilaku mengetik bebek Python membuatnya sangat mudah untuk melewati objek di sekitar.

Pengembang Java fokus pada membangun strcuture kelas dan hubungan antar objek, sambil menjaga hal-hal tetap fleksibel. IOC sangat penting untuk mencapai ini.

Pengembang Python fokus untuk menyelesaikan pekerjaan. Mereka baru saja menyiapkan kelas saat mereka membutuhkannya. Mereka bahkan tidak perlu khawatir tentang jenis kelasnya. Selama bisa dukun, itu bebek! Sifat ini tidak memberikan ruang bagi IoC.


4
Anda masih perlu menemukan sesuatu yang dukun.
andho
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.