Walaupun kelebihan dan kekurangan corak reka bentuk singleton bukanlah fokus artikel ini, artikel ini akan meneroka bagaimana untuk melaksanakan singleton dalam Python dengan cara yang terbaik. Di sini, "kebanyakan Pythonic" bermaksud mengikuti "prinsip paling tidak mengejutkan".
def singleton(class_): instances = {} def getinstance(*args, **kwargs): if class_ not in instances: instances[class_] = class_(*args, **kwargs) return instances[class_] return getinstance @singleton class MyClass(BaseClass): pass
Kelebihan:
Kelemahan:
class Singleton(object): _instance = None def __new__(class_, *args, **kwargs): if not isinstance(class_._instance, class_): class_._instance = object.__new__(class_, *args, **kwargs) return class_._instance class MyClass(Singleton, BaseClass): pass
Kelebihan:
Kelemahan:
class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] # Python2 class MyClass(BaseClass): __metaclass__ = Singleton # Python3 class MyClass(BaseClass, metaclass=Singleton): pass
Kelebihan:
Kelemahan:
def singleton(class_): class class_w(class_): _instance = None def __new__(class_, *args, **kwargs): if class_w._instance is None: class_w._instance = super(class_w, class_).__new__(class_, *args, **kwargs) class_w._instance._sealed = False return class_w._instance def __init__(self, *args, **kwargs): if self._sealed: return super(class_w, self).__init__(*args, **kwargs) self._sealed = True class_w.__name__ = class_.__name__ return class_w @singleton class MyClass(BaseClass): pass
Kelebihan:
Keburukan:
Singleton module singleton.py.
Kebaikan:
Kelemahan:
Saya syorkan menggunakan Kaedah 2, tetapi lebih baik menggunakan metaclass berbanding kelas asas. Berikut ialah contoh pelaksanaan:
class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] class Logger(object): __metaclass__ = Singleton
Atau dalam Python3:
class Logger(metaclass=Singleton): pass
Jika anda mahu __init__ dijalankan setiap kali kelas dipanggil, tambah kod berikut pada Singleton.__call__ In pernyataan if:
def singleton(class_): instances = {} def getinstance(*args, **kwargs): if class_ not in instances: instances[class_] = class_(*args, **kwargs) return instances[class_] return getinstance @singleton class MyClass(BaseClass): pass
Metaclass ialah kelas kelas, iaitu kelas ialah instance daripada metaclassnya. Metaclass objek dalam Python boleh didapati melalui type(obj). Kelas baharu biasa adalah jenis jenis. Logger di atas akan menjadi kelas jenis 'your_module.Singleton' sama seperti contoh (sahaja) Logger akan menjadi kelas jenis 'your_module.Logger' . Apabila logger dipanggil menggunakan Logger(), Python terlebih dahulu bertanya kepada Singleton metaclass Logger apa yang patut dilakukannya, membenarkan penciptaan instance preemptive. Proses ini serupa dengan cara Python meminta kelas apa yang harus dilakukan dengan atributnya dengan memanggil __getattr__, dan anda merujuk atributnya dengan melakukan myclass.attribute.
Metaclasses pada asasnya menentukan maksud kelas panggilan dan cara melaksanakan makna tersebut. Lihat mis. http://code.activestate.com/recipes/498149/ yang menggunakan metaclass untuk mencipta semula struktur gaya C dalam Python. Thread Perbincangan [Apakah kes penggunaan khusus untuk metaclass? ](https://codereview.stackexchange.com/questions/82786/what-are-some-concrete-use-cases-for-metaclasses) juga menyediakan beberapa contoh, yang umumnya berkaitan dengan pengaturcaraan deklaratif, terutamanya dalam ORM yang digunakan dalam .
Dalam kes ini, jika anda menggunakan Kaedah 2 anda dan subkelas mentakrifkan kaedah __baru__, ia akan dilaksanakan setiap kali SubClassOfSingleton() dipanggil, kerana Ia bertanggungjawab untuk memanggil kaedah yang kembalikan kejadian yang disimpan. Dengan metaclass, ia hanya dilaksanakan sekali, apabila contoh unik dibuat. Anda perlu menyesuaikan definisi kelas panggilan, yang ditentukan oleh jenisnya.
Secara umum, masuk akal untuk menggunakan metaclass untuk melaksanakan singleton. Singleton adalah istimewa kerana contohnya dibuat sekali sahaja, manakala metaclass ialah pelaksanaan tersuai bagi kelas yang dicipta yang menjadikannya berkelakuan berbeza daripada kelas biasa. Menggunakan metaclass memberi anda lebih kawalan apabila anda sebaliknya perlu menyesuaikan definisi kelas tunggal anda.
Tunggal anda tidak memerlukan warisan berbilang (kerana metaclass bukan kelas asas), tetapi untuk warisan mencipta subkelas kelas, anda perlu memastikan tunggal kelas ialah yang pertama/ Metaclass paling kiri mentakrifkan semula __call__. Ini tidak mungkin menjadi masalah. Kamus contoh tiada dalam ruang nama contoh, jadi ia tidak boleh ditimpa secara tidak sengaja.
Anda juga akan mendengar bahawa corak tunggal melanggar "prinsip tanggungjawab tunggal", yang bermaksud bahawa setiap kelas hanya perlu melakukan satu perkara. Dengan cara ini, anda tidak perlu risau tentang memecahkan satu perkara yang dilakukan oleh kod apabila anda perlu menukar kod lain kerana ia bebas dan dikapsulkan. Pelaksanaan metaclass melepasi ujian ini. Metaclasses bertanggungjawab untuk menguatkuasakan corak, mencipta kelas dan subkelas yang tidak perlu sedar bahawa mereka adalah tunggal. Kaedah 1 gagal dalam ujian ini, seperti yang anda nyatakan dengan "MyClass itu sendiri ialah fungsi, bukan kelas, jadi kaedah kelas tidak boleh dipanggil".
Menulis kod dalam Python 2 dan 3 memerlukan skema yang lebih rumit. Memandangkan metaclass biasanya merupakan subclass bagi kelas jenis, anda boleh menggunakan metaclass untuk mencipta kelas asas perantara secara dinamik dengannya sebagai metaclass pada masa jalanan, dan kemudian menggunakan kelas asas itu sebagai kelas asas untuk kelas asas singleton awam. Ini lebih mudah diucapkan daripada dilakukan, seperti berikut:
def singleton(class_): instances = {} def getinstance(*args, **kwargs): if class_ not in instances: instances[class_] = class_(*args, **kwargs) return instances[class_] return getinstance @singleton class MyClass(BaseClass): pass
Satu ironi pendekatan ini ialah ia menggunakan subkelas untuk melaksanakan metaclass. Satu kelebihan yang mungkin ialah, tidak seperti metaclass tulen, isinstance(inst, Singleton) akan mengembalikan True.
Berkenaan topik lain, anda mungkin perasan, tetapi pelaksanaan kelas asas dalam siaran asal anda adalah salah. Untuk merujuk _instances dalam kelas, anda perlu menggunakan super(), atau kaedah statik kaedah kelas, kerana kelas sebenar belum lagi dibuat pada masa panggilan. Semua ini berlaku untuk pelaksanaan metaclass juga.
class Singleton(object): _instance = None def __new__(class_, *args, **kwargs): if not isinstance(class_._instance, class_): class_._instance = object.__new__(class_, *args, **kwargs) return class_._instance class MyClass(Singleton, BaseClass): pass
Atas ialah kandungan terperinci Apakah cara terbaik untuk melaksanakan singleton dalam Python?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!