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:
Apakah pewarisan berganda diperlukan atau tidak untuk mengkarakterisasi mixin?
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 ==
:
class ComparableMixin(object):
"""This class has methods which use `<=` and `==`,
but this class does NOT implement those methods."""
def __ne__(self, other):
return not (self == other)
def __lt__(self, other):
return self <= other and (self != other)
def __gt__(self, other):
return not self <= other
def __ge__(self, other):
return self == other or self > other
class Integer(ComparableMixin):
def __init__(self, i):
self.i = i
def __le__(self, other):
return self.i <= other.i
def __eq__(self, other):
return self.i == other.i
assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)
# It is possible to instantiate a mixin:
o = ComparableMixin()
# but one of its methods raise an exception:
#o != o
Contoh khusus ini bisa dicapai melalui functools.total_ordering()
dekorator, tetapi permainan di sini adalah untuk menemukan kembali roda:
import functools
@functools.total_ordering
class Integer(object):
def __init__(self, i):
self.i = i
def __le__(self, other):
return self.i <= other.i
def __eq__(self, other):
return self.i == other.i
assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)
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:
class HasMethod1(object):
def method(self):
return 1
class HasMethod2(object):
def method(self):
return 2
class UsesMethod10(object):
def usesMethod(self):
return self.method() + 10
class UsesMethod20(object):
def usesMethod(self):
return self.method() + 20
class C1_10(HasMethod1, UsesMethod10): pass
class C1_20(HasMethod1, UsesMethod20): pass
class C2_10(HasMethod2, UsesMethod10): pass
class C2_20(HasMethod2, UsesMethod20): pass
assert C1_10().usesMethod() == 11
assert C1_20().usesMethod() == 21
assert C2_10().usesMethod() == 12
assert C2_20().usesMethod() == 22
# Nothing prevents implementing the method
# on the base class like in Definition 1:
class C3_10(UsesMethod10):
def method(self):
return 3
assert C3_10().usesMethod() == 13
Kejadian Python resmi
Di dokumentasi resmi untuk koleksi.abc dokumentasi secara eksplisit menggunakan istilah Metode Mixin .
Ini menyatakan bahwa jika suatu kelas:
- mengimplementasikan
__next__
- mewarisi dari satu kelas
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 menyukai Set
dan Iterator
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