Dalam sebagian besar bahasa OO yang terkenal, ekspresi seperti SomeClass(arg1, arg2)
akan mengalokasikan instance baru, menginisialisasi atribut instance, dan kemudian mengembalikannya.
Dalam sebagian besar bahasa OO yang terkenal, bagian "inisialisasi atribut instance" dapat dikustomisasi untuk setiap kelas dengan mendefinisikan konstruktor , yang pada dasarnya hanya blok kode yang beroperasi pada instance baru (menggunakan argumen yang disediakan untuk ekspresi konstruktor ) untuk mengatur kondisi awal apa pun yang diinginkan. Dalam Python, ini sesuai dengan metode kelas __init__
.
Python __new__
tidak lebih dan tidak kurang dari kustomisasi per kelas yang sama dari bagian "alokasikan contoh baru". Ini tentu saja memungkinkan Anda untuk melakukan hal-hal yang tidak biasa seperti mengembalikan contoh yang ada daripada mengalokasikan yang baru. Jadi dengan Python, kita seharusnya tidak benar-benar menganggap bagian ini melibatkan alokasi; semua yang kami butuhkan adalah yang __new__
datang dengan contoh yang cocok dari suatu tempat.
Tapi itu masih hanya setengah dari pekerjaan, dan tidak ada cara bagi sistem Python untuk mengetahui bahwa kadang-kadang Anda ingin menjalankan setengah pekerjaan lainnya ( __init__
) sesudahnya dan kadang-kadang tidak. Jika Anda menginginkan perilaku itu, Anda harus mengatakannya secara eksplisit.
Seringkali, Anda dapat melakukan refactor sehingga Anda hanya perlu __new__
, atau Anda tidak perlu __new__
, atau sehingga __init__
berperilaku berbeda pada objek yang sudah diinisialisasi. Tetapi jika Anda benar-benar ingin, Python benar-benar memungkinkan Anda untuk mendefinisikan kembali "pekerjaan", jadi itu SomeClass(arg1, arg2)
tidak selalu memanggil __new__
diikuti __init__
. Untuk melakukan ini, Anda perlu membuat metaclass, dan menentukan __call__
metodenya.
Metaclass hanyalah kelas dari suatu kelas. Dan metode kelas __call__
mengontrol apa yang terjadi ketika Anda memanggil instance kelas. Jadi metaclass ' __call__
metode kontrol apa yang terjadi ketika Anda menelepon kelas; yaitu memungkinkan Anda untuk mendefinisikan ulang mekanisme pembuatan instance dari awal hingga selesai . Ini adalah tingkat di mana Anda dapat paling elegan menerapkan proses pembuatan instance yang sepenuhnya tidak standar seperti pola tunggal. Bahkan, dengan kurang dari 10 baris kode Anda dapat menerapkan Singleton
metaclass yang kemudian bahkan tidak mengharuskan Anda untuk futz dengan __new__
sama sekali , dan dapat mengubah setiap kelas lain-normal menjadi tunggal dengan hanya menambahkan __metaclass__ = Singleton
!
class Singleton(type):
def __init__(self, *args, **kwargs):
super(Singleton, self).__init__(*args, **kwargs)
self.__instance = None
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super(Singleton, self).__call__(*args, **kwargs)
return self.__instance
Namun ini mungkin sihir yang lebih dalam daripada yang sebenarnya diperlukan untuk situasi ini!