Dalam " Pemrograman Python ", Mark Lutz menyebutkan "mixins". Saya dari latar belakang C / C ++ / C # dan saya belum pernah mendengar istilah sebelumnya. Apa itu mixin?
Membaca yang tersirat dari contoh ini (yang saya tautkan karena cukup panjang), saya anggap ini adalah kasus menggunakan multiple inheritance untuk memperluas kelas sebagai lawan dari subklasifikasi 'tepat'. Apakah ini benar?
Mengapa saya ingin melakukan itu daripada memasukkan fungsi baru ke dalam subkelas? Untuk itu, mengapa pendekatan mixin / multiple inheritance lebih baik daripada menggunakan komposisi?
Apa yang membedakan mixin dari multiple inheritance? Apakah ini hanya masalah semantik?
sumber
Parent
kelas danChild1
,Child2
,ChildN
subclass di dalam perpustakaan pihak ke-3, dan Anda ingin perilaku disesuaikan untuk seluruh keluarga. Idealnya Anda ingin menambahkan perilaku tersebut ke dalamParent
, dan berharap pengembang perpustakaan pihak ketiga akan menerima Permintaan Tarik Anda. Kalau tidak, Anda harus menerapkan sendiriclass NewBehaviorMixin
, dan kemudian menetapkan satu set penuh kelas pembungkus seperticlass NewParent(NewBehaviorMixin, Parent): pass
danclass NewChildN(NewBehaviorMixin, ChildN): pass
, dll. (PS: Apakah Anda tahu cara yang lebih baik?)Pertama, Anda harus perhatikan bahwa mixin hanya ada dalam bahasa multi-inheritance. Anda tidak dapat melakukan mixin di Java atau C #.
Pada dasarnya, mixin adalah tipe dasar yang berdiri sendiri yang menyediakan fungsionalitas terbatas dan resonansi polimorfik untuk kelas anak. Jika Anda berpikir dalam bahasa C #, pikirkan sebuah antarmuka yang tidak harus Anda terapkan karena sudah diterapkan; Anda baru saja mewarisi dan manfaat dari fungsinya.
Mixin biasanya memiliki cakupan yang sempit dan tidak dimaksudkan untuk diperpanjang.
[sunting - alasan mengapa:]
Saya kira saya harus membahas mengapa, karena Anda bertanya. Manfaat besarnya adalah Anda tidak harus melakukannya sendiri berulang kali. Dalam C #, tempat terbesar di mana mixin bisa mendapat manfaat mungkin dari pola Pembuangan . Setiap kali Anda menerapkan IDisposable, Anda hampir selalu ingin mengikuti pola yang sama, tetapi Anda akhirnya menulis dan menulis ulang kode dasar yang sama dengan variasi kecil. Jika ada mixin Pembuangan yang bisa diperpanjang, Anda bisa menghemat banyak pengetikan.
[edit 2 - untuk menjawab pertanyaan Anda yang lain]
Iya. Perbedaan antara mixin dan multiple inheritance standar hanyalah masalah semantik; kelas yang memiliki banyak pewarisan mungkin menggunakan mixin sebagai bagian dari pewarisan berganda itu.
Maksud dari mixin adalah untuk membuat tipe yang dapat "dicampur" ke tipe lain melalui pewarisan tanpa mempengaruhi tipe pewarisan sambil tetap menawarkan beberapa fungsi yang bermanfaat untuk tipe tersebut.
Sekali lagi, pikirkan sebuah antarmuka yang sudah diimplementasikan.
Saya pribadi tidak menggunakan mixin karena saya mengembangkannya terutama dalam bahasa yang tidak mendukung mereka, jadi saya mengalami waktu yang sangat sulit dengan contoh yang baik yang hanya akan memasok "ahah!" momen untukmu. Tapi saya akan coba lagi. Saya akan menggunakan contoh yang dibuat-buat - sebagian besar bahasa sudah menyediakan fitur dalam beberapa cara - tetapi itu akan, mudah-mudahan, menjelaskan bagaimana mixin seharusnya dibuat dan digunakan. Ini dia:
Misalkan Anda memiliki tipe yang Anda ingin dapat membuat serial ke dan dari XML. Anda ingin tipe menyediakan metode "ToXML" yang mengembalikan string yang berisi fragmen XML dengan nilai data dari tipe tersebut, dan "FromXML" yang memungkinkan tipe untuk merekonstruksi nilai datanya dari fragmen XML dalam string. Sekali lagi, ini adalah contoh yang dibuat-buat, jadi mungkin Anda menggunakan aliran file, atau kelas XML Writer dari pustaka runtime bahasa Anda ... apa pun. Intinya adalah Anda ingin membuat serial objek Anda menjadi XML dan mendapatkan objek baru kembali dari XML.
Poin penting lainnya dalam contoh ini adalah bahwa Anda ingin melakukan ini secara generik. Anda tidak ingin harus menerapkan metode "ToXML" dan "FromXML" untuk setiap jenis yang Anda ingin serialkan, Anda ingin beberapa cara umum untuk memastikan bahwa jenis Anda akan melakukan ini dan itu hanya berfungsi. Anda ingin menggunakan kembali kode.
Jika bahasa Anda mendukungnya, Anda dapat membuat mixin XmlSerializable untuk melakukan pekerjaan Anda untuk Anda. Jenis ini akan menerapkan metode ToXML dan FromXML. Itu akan, menggunakan beberapa mekanisme yang tidak penting untuk contoh, akan mampu mengumpulkan semua data yang diperlukan dari jenis apa pun yang dicampur dengan untuk membangun fragmen XML yang dikembalikan oleh ToXML dan itu akan sama-sama mampu mengembalikan data itu ketika FromXML adalah dipanggil.
Dan .. itu dia. Untuk menggunakannya, Anda akan memiliki tipe apa pun yang perlu diserialisasi ke XML dari XmlSerializable. Setiap kali Anda perlu membuat cerita bersambung atau membatalkan jenis itu, Anda cukup memanggil ToXML atau FromXML. Faktanya, karena XmlSerializable adalah tipe dan polimorfik yang lengkap, Anda dapat membuat serializer dokumen yang tidak tahu apa-apa tentang tipe asli Anda, hanya menerima, katakanlah, serangkaian tipe XmlSerializable.
Sekarang bayangkan menggunakan skenario ini untuk hal-hal lain, seperti membuat mixin yang memastikan bahwa setiap kelas yang mencampurnya dalam log setiap panggilan metode, atau mixin yang menyediakan transaksionalitas dengan tipe yang mencampurnya. Daftar ini dapat terus dan terus.
Jika Anda hanya menganggap mixin sebagai tipe basis kecil yang dirancang untuk menambahkan sejumlah kecil fungsionalitas ke tipe tanpa memengaruhi tipe itu, maka Anda berwarna emas.
Semoga. :)
sumber
Jawaban ini bertujuan untuk menjelaskan mixin dengan contoh-contoh yaitu:
mandiri : singkat, tanpa perlu tahu perpustakaan apa pun untuk memahami contoh.
dalam Python , bukan dalam bahasa lain.
Dapat dimengerti bahwa ada contoh-contoh dari bahasa lain seperti Ruby karena istilah ini jauh lebih umum dalam bahasa-bahasa itu, tetapi ini adalah utas Python .
Ini juga akan mempertimbangkan pertanyaan kontroversial:
Definisi
Saya belum melihat kutipan dari sumber "otoritatif" yang dengan jelas mengatakan apa itu mixin dalam Python.
Saya telah melihat 2 kemungkinan definisi mixin (jika mereka dianggap berbeda dari konsep serupa lainnya seperti kelas dasar abstrak), dan orang-orang tidak sepenuhnya setuju yang mana yang benar.
Konsensus dapat bervariasi di antara berbagai bahasa.
Definisi 1: tidak ada banyak warisan
Mixin adalah kelas sedemikian sehingga beberapa metode kelas menggunakan metode yang tidak didefinisikan dalam kelas.
Oleh karena itu kelas tidak dimaksudkan untuk dipakai, tetapi berfungsi sebagai kelas dasar. Kalau tidak, instance akan memiliki metode yang tidak dapat dipanggil tanpa memunculkan pengecualian.
Kendala yang ditambahkan beberapa sumber adalah bahwa kelas mungkin tidak berisi data, hanya metode, tetapi saya tidak melihat mengapa ini perlu. Namun dalam praktiknya, banyak mixin berguna tidak memiliki data apa pun, dan kelas dasar tanpa data lebih mudah digunakan.
Contoh klasik adalah penerapan semua operator pembanding hanya dari
<=
dan==
:Contoh khusus ini bisa dicapai melalui
functools.total_ordering()
dekorator, tetapi permainan di sini adalah untuk menemukan kembali roda:Definisi 2: pewarisan berganda
Mixin adalah pola desain di mana beberapa metode kelas dasar menggunakan metode yang tidak didefinisikan, dan metode itu dimaksudkan untuk diimplementasikan oleh kelas dasar lainnya , bukan oleh turunan seperti dalam Definisi 1.
Istilah class mixin mengacu pada kelas dasar yang dimaksudkan untuk digunakan dalam pola desain tersebut (TODO yang menggunakan metode, atau yang menerapkannya?)
Tidak mudah untuk memutuskan apakah kelas yang diberikan adalah mixin atau tidak: metode ini dapat diimplementasikan pada kelas turunan, dalam hal ini kita kembali ke Definisi 1. Anda harus mempertimbangkan niat penulis.
Pola ini menarik karena dimungkinkan untuk menggabungkan kembali fungsi dengan pilihan kelas dasar yang berbeda:
Kejadian Python resmi
Di dokumentasi resmi untuk koleksi.abc dokumentasi secara eksplisit menggunakan istilah Metode Mixin .
Ini menyatakan bahwa jika suatu kelas:
__next__
Iterator
maka kelas mendapat
__iter__
metode mixin gratis.Oleh karena itu setidaknya pada titik dokumentasi ini, mixin tidak memerlukan pewarisan berganda , dan koheren dengan Definisi 1.
Dokumentasi tentu saja dapat bertentangan pada titik yang berbeda, dan perpustakaan Python penting lainnya mungkin menggunakan definisi lain dalam dokumentasi mereka.
Halaman ini juga menggunakan istilah ini
Set mixin
, yang dengan jelas menunjukkan bahwa kelas menyukaiSet
danIterator
dapat disebut kelas Mixin.Dalam bahasa lain
Ruby: Jelas tidak memerlukan pewarisan berganda untuk mixin, seperti yang disebutkan dalam buku referensi utama seperti Pemrograman Ruby dan Bahasa pemrograman Ruby
C ++: Metode yang tidak diimplementasikan adalah metode virtual murni.
Definisi 1 bertepatan dengan definisi kelas abstrak (kelas yang memiliki metode virtual murni). Kelas itu tidak bisa dipakai.
Definisi 2 dimungkinkan dengan virtual inheritance: Multiple Inheritance dari dua kelas turunan
sumber
Saya menganggap mereka sebagai cara disiplin menggunakan multiple inheritance - karena pada akhirnya mixin hanyalah kelas python lain yang (mungkin) mengikuti konvensi tentang kelas yang disebut mixin.
Pemahaman saya tentang konvensi yang mengatur sesuatu yang Anda sebut Mixin adalah bahwa Mixin:
object
(dengan Python)Dengan cara itu membatasi kompleksitas potensial dari banyak warisan, dan membuatnya cukup mudah untuk melacak aliran program Anda dengan membatasi di mana Anda harus melihat (dibandingkan dengan warisan penuh beberapa). Mereka mirip dengan modul ruby .
Jika saya ingin menambahkan variabel instan (dengan lebih banyak fleksibilitas daripada yang diizinkan oleh pewarisan tunggal) maka saya cenderung memilih komposisi.
Karena itu, saya telah melihat kelas yang disebut XYZMixin yang memiliki variabel instan.
sumber
Mixins adalah konsep dalam Pemrograman di mana kelas menyediakan fungsionalitas tetapi tidak dimaksudkan untuk digunakan untuk instantiasi. Tujuan utama Mixin adalah untuk menyediakan fungsionalitas yang berdiri sendiri dan akan lebih baik jika mixin itu sendiri tidak memiliki warisan dengan mixin lain dan juga menghindari keadaan. Dalam bahasa seperti Ruby, ada beberapa dukungan bahasa langsung tetapi untuk Python, tidak ada. Namun, Anda bisa menggunakan pewarisan multi-kelas untuk menjalankan fungsi yang disediakan dengan Python.
Saya menonton video ini http://www.youtube.com/watch?v=v_uKI2NOLEM untuk memahami dasar-dasar mixin. Sangat berguna bagi seorang pemula untuk memahami dasar-dasar mixin dan bagaimana mereka bekerja dan masalah yang mungkin Anda hadapi dalam mengimplementasikannya.
Wikipedia masih yang terbaik: http://en.wikipedia.org/wiki/Mixin
sumber
Mixin adalah bentuk terbatas dari pewarisan berganda. Dalam beberapa bahasa, mekanisme untuk menambahkan mixin ke kelas sedikit berbeda (dalam hal sintaksis) dari pada inheritance.
Dalam konteks Python khususnya, mixin adalah kelas induk yang menyediakan fungsionalitas untuk subkelas tetapi tidak dimaksudkan untuk dipakai sendiri.
Apa yang mungkin menyebabkan Anda mengatakan, "itu hanyalah pewarisan berganda, bukan benar-benar mixin" adalah jika kelas yang mungkin bingung untuk mixin sebenarnya dapat dipakai dan digunakan - jadi memang itu adalah perbedaan semantik, dan sangat nyata.
Contoh Beberapa Warisan
Contoh ini, dari dokumentasi , adalah OrderedCounter:
Ini subkelas dari
Counter
danOrderedDict
daricollections
modul.Keduanya
Counter
danOrderedDict
dimaksudkan untuk dipakai dan digunakan sendiri. Namun, dengan mensubklasifikasikan keduanya, kita dapat memiliki penghitung yang dipesan dan menggunakan kembali kode di setiap objek.Ini adalah cara yang ampuh untuk menggunakan kembali kode, tetapi juga bisa menimbulkan masalah. Jika ternyata ada bug di salah satu objek, memperbaikinya tanpa perawatan bisa membuat bug di subkelas.
Contoh dari Mixin
Mixin biasanya dipromosikan sebagai cara untuk mendapatkan kembali penggunaan kode tanpa potensi masalah penggandaan yang dapat dimiliki beberapa pewarisan kooperatif, seperti OrderedCounter. Saat Anda menggunakan mixin, Anda menggunakan fungsionalitas yang tidak terlalu erat dengan data.
Berbeda dengan contoh di atas, mixin tidak dimaksudkan untuk digunakan sendiri. Ini menyediakan fungsionalitas baru atau berbeda.
Misalnya, perpustakaan standar memiliki beberapa mixin di
socketserver
perpustakaan .Dalam hal ini, metode mixin menimpa metode dalam
UDPServer
definisi objek untuk memungkinkan konkurensi.Metode yang diganti tampaknya
process_request
dan juga menyediakan metode lainprocess_request_thread
,. Ini dia dari kode sumber :Sebuah Contoh Yang Dibuat
Ini adalah mixin yang sebagian besar untuk tujuan demonstrasi - sebagian besar objek akan berkembang melampaui manfaat dari repr ini:
dan penggunaannya adalah:
Dan penggunaan:
sumber
Saya pikir ada beberapa penjelasan yang bagus di sini, tetapi saya ingin memberikan perspektif lain.
Di Scala, Anda dapat melakukan mixin seperti yang telah dijelaskan di sini, tetapi yang sangat menarik adalah bahwa mixin sebenarnya 'menyatu' bersama-sama untuk membuat kelas jenis baru untuk diwarisi. Intinya, Anda tidak mewarisi dari beberapa kelas / mixin, melainkan menghasilkan jenis kelas baru dengan semua properti mixin untuk diwarisi. Ini masuk akal karena Scala didasarkan pada JVM di mana multiple-inheritance saat ini tidak didukung (pada Java 8). Jenis kelas mixin, omong-omong, adalah tipe khusus yang disebut Trait in Scala.
Ini mengisyaratkan cara kelas didefinisikan: kelas NewClass memperluas FirstMixin dengan SecondMixin dengan ThirdMixin ...
Saya tidak yakin apakah juru bahasa CPython melakukan hal yang sama (komposisi kelas mixin) tapi saya tidak akan terkejut. Juga, berasal dari latar belakang C ++, saya tidak akan memanggil ABC atau 'antarmuka' yang setara dengan mixin - ini adalah konsep yang sama tetapi berbeda dalam penggunaan dan implementasi.
sumber
Saya akan menyarankan agar mix-in tidak dimasukkan dalam kode Python baru, jika Anda dapat menemukan cara lain di sekitarnya (seperti komposisi-bukan-dari-warisan, atau hanya metode patch-monyet ke dalam kelas Anda sendiri) yang tidak lebih upaya.
Di kelas gaya lama Anda bisa menggunakan mix-in sebagai cara meraih beberapa metode dari kelas lain. Tapi di dunia gaya baru segalanya, bahkan campuran, diwarisi dari
object
. Itu berarti bahwa setiap penggunaan pewarisan berganda secara alami menimbulkan masalah MRO .Ada beberapa cara untuk membuat multi-inheritance MRO bekerja di Python, terutama fungsi super (), tetapi itu berarti Anda harus melakukan seluruh hierarki kelas menggunakan super (), dan jauh lebih sulit untuk memahami aliran kontrol.
sumber
Mungkin beberapa contoh akan membantu.
Jika Anda membangun kelas dan Anda ingin itu bertindak seperti kamus, Anda dapat mendefinisikan semua
__ __
metode yang diperlukan. Tapi itu agak menyebalkan. Sebagai alternatif, Anda bisa mendefinisikan beberapa saja, dan mewarisi (selain warisan lainnya) dariUserDict.DictMixin
(dipindahkan kecollections.DictMixin
dalam py3k). Ini akan memiliki efek mendefinisikan semua api kamus secara otomatis.Contoh kedua: toolkit GUI wxPython memungkinkan Anda membuat kontrol daftar dengan banyak kolom (seperti, misalnya, tampilan file di Windows Explorer). Secara default, daftar ini cukup mendasar. Anda dapat menambahkan fungsionalitas tambahan, seperti kemampuan untuk mengurutkan daftar dengan kolom tertentu dengan mengklik pada header kolom, dengan mewarisi dari ListCtrl dan menambahkan mixin yang sesuai.
sumber
Ini bukan contoh Python tetapi dalam bahasa pemrograman D istilah
mixin
ini digunakan untuk merujuk ke konstruksi yang digunakan dengan cara yang sama; menambahkan setumpuk barang ke kelas.Dalam D (yang omong-omong tidak melakukan MI) ini dilakukan dengan memasukkan templat (pikirkan makro yang sadar dan aman secara sintaksis dan Anda akan dekat) ke dalam cakupan. Ini memungkinkan satu baris kode di kelas, struct, fungsi, modul atau apa pun untuk diperluas ke sejumlah deklarasi.
sumber
OP menyebutkan bahwa dia tidak pernah mendengar mixin dalam C ++, mungkin itu karena mereka disebut Curiously Recurring Template Pattern (CRTP) dalam C ++. @Ciro Santilli juga menyebutkan bahwa mixin diimplementasikan melalui kelas dasar abstrak dalam C ++. Sementara kelas dasar abstrak dapat digunakan untuk mengimplementasikan mixin, itu adalah kerja keras karena fungsi fungsi virtual pada saat run-time dapat dicapai dengan menggunakan template pada waktu kompilasi tanpa overhead dari pencarian tabel virtual pada saat run-time.
Pola CRTP dijelaskan secara rinci di sini
Saya telah mengonversi contoh python dalam jawaban @Ciro Santilli menjadi C ++ menggunakan kelas templat di bawah ini:
EDIT: Menambahkan konstruktor yang dilindungi di ComparableMixin sehingga hanya bisa diwarisi dan tidak dipakai. Diperbarui contoh untuk menunjukkan bagaimana konstruktor yang dilindungi akan menyebabkan kesalahan kompilasi ketika objek ComparableMixin dibuat.
sumber
Mungkin contoh dari ruby dapat membantu:
Anda dapat memasukkan mixin
Comparable
dan mendefinisikan satu fungsi"<=>(other)"
, mixin menyediakan semua fungsi tersebut:Ini dilakukan dengan memohon
<=>(other)
dan memberikan kembali hasil yang tepat."instance <=> other"
mengembalikan 0 jika kedua objek sama, kurang dari 0 jikainstance
lebih besar dariother
dan lebih dari 0 jikaother
lebih besar.sumber
__lt__
sebagai basis dan bukan__cmp__
, yang terakhir sebenarnya sudah usang dan tidak disarankan untuk digunakan. Bagi saya tampaknya sederhana untuk menggunakan mixin bukan cukup rumit dekorator (bagian dari functools ) - meskipun satu ini mungkin dapat bereaksi lebih dinamis di mana perbandingan disediakan ...mixin memberikan cara untuk menambahkan fungsionalitas dalam kelas, yaitu Anda dapat berinteraksi dengan metode yang didefinisikan dalam modul dengan memasukkan modul di dalam kelas yang diinginkan. Meskipun ruby tidak mendukung multiple inheritance tetapi memberikan mixin sebagai alternatif untuk mencapai itu.
di sini adalah contoh yang menjelaskan bagaimana pewarisan berganda dicapai menggunakan mixin.
sumber
Saya hanya menggunakan python mixin untuk mengimplementasikan unit testing untuk python milters. Biasanya, seorang milter berbicara dengan MTA, membuat unit test sulit. Campuran tes mengesampingkan metode yang berbicara dengan MTA, dan menciptakan lingkungan simulasi yang didorong oleh kasus uji.
Jadi, Anda mengambil aplikasi milter yang tidak dimodifikasi, seperti spfmilter, dan mixin TestBase, seperti ini:
Kemudian, gunakan TestMilter dalam kasus uji untuk aplikasi yang lebih ringan:
http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup
sumber
Saya pikir tanggapan sebelumnya didefinisikan dengan sangat baik apa itu MixIns . Namun, untuk lebih memahami mereka, mungkin berguna untuk membandingkan MixIns dengan Kelas dan Antarmuka Abstrak dari perspektif kode / implementasi:
1. Kelas Abstrak
Kelas yang perlu mengandung satu atau lebih metode abstrak
Kelas Abstrak dapat berisi status (variabel instan) dan metode non-abstrak
2. Antarmuka
3. MixIns
Dalam misalnya Python ini hanya konvensi, karena semua hal di atas didefinisikan sebagai
class
es. Namun, fitur umum dari kedua Kelas Abstrak, Antarmuka dan MixIns adalah bahwa mereka tidak boleh ada sendiri, yaitu tidak boleh dipakai.sumber
Saya membaca bahwa Anda memiliki latar belakang ac #. Jadi titik awal yang baik mungkin implementasi mixin untuk .NET.
Anda mungkin ingin memeriksa proyek codeplex di http://remix.codeplex.com/
Tonton tautan Simposium lang.net untuk mendapatkan ikhtisar. Masih ada lagi yang muncul pada dokumentasi pada halaman codeplex.
salam Stefan
sumber