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.
Jawaban:
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
Kami memiliki nama untuk "kabel bersama" dan "saat runtime":
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:
sumber
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.
sumber
MyClassInstances
kelas untuk masing-masingMyClass
di Jawa, yang hanya berisi contoh statis, diinisialisasi penuh. Itu akan ditransfer: Dfrom framework.auth.user import User
mungkin lebih baik untuk menulisUser = lookup('UserImplentation', 'framework.auth.user.User')
(parameter ke-2 mungkin nilai default) di dalam kerangka kerja. Kemudian pengguna kerangka kerja akan dapat mengganti / mengkhususkanUser
implementasi tanpa menyentuh kerangka kerja.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
:Django Rest Framework sangat memanfaatkan DI:
Biarkan saya ingatkan ( sumber ):
sumber
IsAuthenticated
,ScopedRateThrottle
) dipakai oleh kelas. Mereka tidak diteruskan ke konstruktor.IsAuthenticated
danScopedRateThrottle
bukan contoh, ini adalah kelas. Mereka dipakai saat FooView dibangun (sebenarnya, ketika FooView memproses permintaan). Bagaimanapun, ini hanyalah detail implementasi.IsAuthenticated
danScopedRateThrottle
apakah dependensinya; mereka disuntikkan ke dalamFooView
. Tidak masalah kapan atau bagaimana hal ini dilakukan. Python bukan Java, jadi ada berbagai cara untuk mengimplementasikannya.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.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:
Kemudian kode dapat membuat antarmuka database dengan menulis:
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.
sumber
import psycopg2 as database_interface
. Masukkan baris itu diinjections.py
et voilà.self.database_interface
), yang meneriakkan keharusan.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
sumber
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.
sumber
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:
_
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 .
sumber
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.
sumber
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:
Namun lihatlah https://github.com/noodleflake/pyioc ini mungkin yang Anda cari.
yaitu Dalam pyioc
sumber
other.py
baris 1, ada resolusi ketergantungan otomatis, tetapi tidak akan menghitungnya sebagai injeksi ketergantungan.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:
sumber
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.
sumber
The typical Python application is much simpler, just a bunch of scripts, without such a complex architecture.
- Asumsi yang cukupjadwal pertandingan pytest semua berdasarkan pada DI ( sumber )
sumber
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]
sumber
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.
sumber
EmailSender
dan memutuskan untuk menggantinya denganDesktopNotifier
, saya harus pergi dan mengedit 12 kelas dengan tangan. Dan Anda pikir itu lebih sederhana dan lebih bersih yang hanya menulis keINotifier
antarmuka dan membiarkan wadah mengerjakan detailnya?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.
sumber