Pertanyaan ini bukan untuk diskusi tentang apakah pola desain tunggal diinginkan atau tidak , merupakan anti-pola, atau untuk perang agama apa pun, tetapi untuk membahas bagaimana pola ini paling baik diimplementasikan dengan Python sedemikian rupa sehingga paling pythonic. Dalam contoh ini saya mendefinisikan 'paling pythonic' berarti bahwa ia mengikuti 'prinsip paling tidak heran' .
Saya memiliki beberapa kelas yang akan menjadi lajang (use-case saya adalah untuk seorang logger, tetapi ini tidak penting). Saya tidak ingin mengacaukan beberapa kelas dengan gumph tambahan ketika saya bisa mewarisi atau menghias.
Metode terbaik:
Metode 1: Seorang dekorator
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
Pro
- Dekorator bersifat aditif dengan cara yang seringkali lebih intuitif daripada pewarisan berganda.
Cons
- Sementara objek yang dibuat menggunakan MyClass () akan menjadi objek singleton sejati, MyClass sendiri adalah fungsi, bukan kelas, jadi Anda tidak dapat memanggil metode kelas dari itu. Juga untuk
m = MyClass(); n = MyClass(); o = type(n)();
saat itum == n && m != o && n != o
Metode 2: Kelas dasar
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
Pro
- Kelas yang benar
Cons
- Warisan berganda - eugh!
__new__
dapat ditimpa selama pewarisan dari kelas dasar kedua? Kita harus berpikir lebih dari yang diperlukan.
Metode 3: Metaclass
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
Pro
- Kelas yang benar
- Secara otomatis mencakup warisan
- Menggunakan
__metaclass__
untuk tujuan yang tepat (dan membuat saya menyadarinya)
Cons
- Apakah ada?
Metode 4: dekorator mengembalikan kelas dengan nama yang sama
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
Pro
- Kelas yang benar
- Secara otomatis mencakup warisan
Cons
- Apakah tidak ada overhead untuk membuat setiap kelas baru? Di sini kita membuat dua kelas untuk setiap kelas yang ingin kita buat sendiri. Meskipun ini baik-baik saja dalam kasus saya, saya khawatir ini mungkin tidak skala. Tentu saja ada masalah perdebatan, apakah terlalu mudah untuk mengubah skala pola ini ...
- Apa gunanya
_sealed
atribut - Tidak dapat memanggil metode dengan nama yang sama pada kelas dasar menggunakan
super()
karena mereka akan berulang. Ini berarti Anda tidak dapat mengkustomisasi__new__
dan tidak dapat mensubkelas kelas yang perlu Anda panggil__init__
.
Metode 5: modul
file modul singleton.py
Pro
- Sederhana lebih baik daripada kompleks
Cons
foo.x
atau jika Anda bersikerasFoo.x
bukanFoo().x
); gunakan atribut kelas dan metode statis / kelas (Foo.x
).Jawaban:
Gunakan Metaclass
Saya akan merekomendasikan Metode # 2 , tetapi Anda lebih baik menggunakan metaclass daripada kelas dasar. Berikut ini contoh implementasi:
Atau dalam Python3
Jika Anda ingin menjalankan
__init__
setiap kali kelas dipanggil, tambahkanpada
if
pernyataan dalamSingleton.__call__
.Beberapa kata tentang metaclasses. Metaclass adalah kelas suatu kelas ; yaitu, kelas adalah turunan dari metaclassnya . Anda menemukan metaclass dari objek dengan Python
type(obj)
. Kelas gaya baru normal adalah tipetype
.Logger
dalam kode di atas akan bertipeclass 'your_module.Singleton'
, sama seperti (hanya) turunanLogger
bertipeclass 'your_module.Logger'
. Ketika Anda menelepon logger denganLogger()
, Python pertama meminta metaclass dariLogger
,Singleton
, apa yang harus dilakukan, sehingga contoh penciptaan untuk pra-empted. Proses ini sama dengan Python yang meminta kelas apa yang harus dilakukan dengan memanggil__getattr__
ketika Anda mereferensikan salah satu atributnya dengan melakukanmyclass.attribute
.Metaclass pada dasarnya memutuskan apa arti suatu kelas dan bagaimana mengimplementasikannya. Lihat misalnya http://code.activestate.com/recipes/498149/ , yang pada dasarnya menciptakan ulang gaya-C
struct
di Python menggunakan metaclasses. Utas Apa sajakah case penggunaan (konkret) untuk metaclasses? juga memberikan beberapa contoh, mereka umumnya tampaknya terkait dengan pemrograman deklaratif, terutama seperti yang digunakan dalam ORM.Dalam situasi ini, jika Anda menggunakan Metode # 2 Anda , dan subkelas mendefinisikan
__new__
metode, itu akan dieksekusi setiap kali Anda meneleponSubClassOfSingleton()
- karena bertanggung jawab untuk memanggil metode yang mengembalikan instance yang disimpan. Dengan metaclass, itu hanya akan dipanggil sekali , ketika satu-satunya instance dibuat. Anda ingin menyesuaikan apa artinya memanggil kelas , yang ditentukan oleh jenisnya.Secara umum, masuk akal untuk menggunakan metaclass untuk mengimplementasikan singleton. Singleton adalah spesial karena dibuat hanya sekali , dan metaclass adalah cara Anda menyesuaikan penciptaan kelas . Menggunakan metaclass memberi Anda lebih banyak kontrol jika Anda perlu menyesuaikan definisi kelas singleton dengan cara lain.
Singletons Anda tidak memerlukan pewarisan berganda (karena metaclass bukan kelas dasar), tetapi untuk subclass dari kelas yang dibuat yang menggunakan pewarisan berganda, Anda perlu memastikan bahwa kelas singleton adalah yang pertama / paling kiri dengan metaclass yang mendefinisikan ulang
__call__
Ini sangat tidak mungkin menjadi masalah. Dict instance tidak ada dalam namespace instance sehingga tidak akan sengaja menimpanya.Anda juga akan mendengar bahwa pola tunggal melanggar "Prinsip Tanggung Jawab Tunggal" - setiap kelas hanya boleh melakukan satu hal . Dengan begitu Anda tidak perlu khawatir mengacaukan satu hal yang dilakukan kode jika Anda perlu mengubah yang lain, karena mereka terpisah dan dienkapsulasi. Implementasi metaclass melewati tes ini . Metaclass bertanggung jawab untuk menegakkan pola dan kelas dan subclass yang dibuat tidak perlu menyadari bahwa mereka adalah lajang . Metode # 1 gagal tes ini, seperti yang Anda catat dengan "MyClass itu sendiri adalah fungsi, bukan kelas, jadi Anda tidak bisa memanggil metode kelas dari itu."
Versi Kompatibel Python 2 dan 3
Menulis sesuatu yang berfungsi baik di Python2 dan 3 membutuhkan menggunakan skema yang sedikit lebih rumit. Sejak metaclasses biasanya subclass dari jenis
type
, itu mungkin untuk menggunakan satu untuk secara dinamis membuat kelas dasar perantara pada waktu berjalan dengan sebagai metaclass dan kemudian menggunakan bahwa sebagai baseclass dari masyarakatSingleton
kelas dasar. Lebih sulit untuk dijelaskan daripada melakukannya, seperti digambarkan selanjutnya:Aspek ironis dari pendekatan ini adalah menggunakan subclass untuk mengimplementasikan metaclass. Satu keuntungan yang mungkin adalah bahwa, tidak seperti metaclass murni,
isinstance(inst, Singleton)
akan kembaliTrue
.Koreksi
Pada topik lain, Anda mungkin sudah memperhatikan ini, tetapi implementasi kelas dasar dalam posting asli Anda salah.
_instances
perlu direferensikan di kelas , Anda perlu menggunakansuper()
atau Anda berulang , dan__new__
sebenarnya merupakan metode statis yang Anda harus lulus kelas , bukan metode kelas, karena kelas yang sebenarnya belum dibuat saat itu disebut. Semua hal ini akan berlaku juga untuk implementasi metaclass.Penghias Mengembalikan Kelas A
Saya awalnya menulis komentar tetapi terlalu lama, jadi saya akan menambahkan ini di sini. Metode # 4 lebih baik daripada versi dekorator lainnya, tetapi lebih banyak kode daripada yang dibutuhkan untuk seorang singleton, dan tidak jelas apa fungsinya.
Masalah utama berasal dari kelas adalah kelas dasar itu sendiri. Pertama, bukankah aneh memiliki kelas menjadi subkelas dari kelas yang hampir identik dengan nama yang sama yang hanya ada di
__class__
atributnya? Ini juga berarti bahwa Anda tidak dapat menentukan metode yang memanggil metode dengan nama yang sama di kelas dasar mereka dengansuper()
karena mereka akan recurse. Ini berarti kelas Anda tidak dapat dikustomisasi__new__
, dan tidak dapat berasal dari kelas apa pun yang perlu__init__
dipanggil.Kapan harus menggunakan pola singleton
Case use Anda adalah salah satu contoh yang lebih baik dari keinginan untuk menggunakan singleton. Anda mengatakan dalam salah satu komentar, "Bagi saya penebangan selalu tampak sebagai calon alami untuk Singletons." Anda benar sekali .
Ketika orang mengatakan lajang itu buruk, alasan paling umum adalah mereka adalah negara bagian implisit . Sementara dengan variabel global dan impor modul tingkat atas adalah keadaan bersama eksplisit , objek lain yang diedarkan pada umumnya dipakai. Ini adalah poin yang bagus, dengan dua pengecualian .
Yang pertama, dan yang disebutkan di berbagai tempat, adalah ketika lajang konstan . Penggunaan konstanta global, terutama enum, diterima secara luas, dan dianggap waras karena bagaimanapun juga, tidak ada pengguna yang dapat mengacaukannya untuk pengguna lain mana pun . Ini sama benarnya dengan singleton yang konstan.
Pengecualian kedua, yang disebutkan lebih sedikit, adalah kebalikannya - ketika singleton hanya merupakan data sink , bukan sumber data (langsung atau tidak langsung). Inilah sebabnya mengapa penebang merasa seperti penggunaan "alami" untuk lajang. Karena berbagai pengguna tidak mengubah penebang dengan cara yang dipedulikan oleh pengguna lain, sebenarnya tidak ada status bersama . Ini meniadakan argumen utama terhadap pola tunggal, dan menjadikannya pilihan yang masuk akal karena mudah digunakan untuk tugas tersebut.
Berikut ini kutipan dari http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html :
sumber
__new__
dalam metaclass adalah ketika kelas baru - ketika sudah ditentukan, bukan saat instance akan baru. Memanggil kelas (MyClass()
) adalah operasi yang ingin Anda timpa, bukan definisi kelas. Jika Anda benar-benar ingin memahami cara kerja Python, hal terbaik yang dapat Anda lakukan (selain tetap menggunakannya) adalah membaca docs.python.org/reference/datamodel.html . Referensi yang baik tentang metaclasses adalah eli.thegreenplace.net/2011/08/08/14/python-metaclasses-by-example . Artikel bagus tentang lajang adalah seri dari blog google yang saya tautkan dalam jawaban ini.Modul hanya diimpor sekali, yang lainnya terlalu banyak berpikir. Jangan gunakan lajang dan cobalah untuk tidak menggunakan global.
sumber
s = some_global_variable; str = pickle.dumps(s); s1 = pickle.loads(str); print s is s1; # False
is
operator menguji kesetaraan pointer. Saya akan agak terkejut --- sampai menyebutnya bug --- jikapickle.loads
mengembalikan referensi ke objek yang sudah ada daripada referensi ke yang baru dibuat. Jadi, menguji apakahs is s1
tidak memberi tahu Anda tentang kesesuaian menggunakan modul sebagai lajang.pickle.loads()
sudah melakukannya, misalnya untuk instancebool
danNoneType
.pickle.loads(pickle.dumps(False)) is False
hasilTrue
True
,False
danNone
, dan tidak ada hubungannya dengan kode di belakangpickle.loads
. Juga, aman untuk dilakukan hanya untuk objek read-only. Jikapickle.loads
ingin mengembalikan referensi ke objek yang sudah dimodifikasi yang sudah ada - seperti modul - itu akan menjadi bug. (Dan saya berdiri dengan implikasi saya bahwa contoh kode dividebyzero tidak membuktikan apa-apa.)Gunakan modul. Hanya diimpor sekali. Tentukan beberapa variabel global di dalamnya - mereka akan menjadi 'atribut' tunggal. Tambahkan beberapa fungsi - 'metode' tunggal.
sumber
Anda mungkin tidak pernah membutuhkan singleton dalam Python. Cukup tentukan semua data dan fungsi Anda dalam sebuah modul dan Anda memiliki singleton de-facto.
Jika Anda benar-benar harus memiliki kelas tunggal maka saya akan pergi dengan:
Menggunakan:
di mana mysingleton.py adalah nama file Anda yang didefinisikan My_Singleton. Ini berfungsi karena setelah pertama kali file diimpor, Python tidak menjalankan kembali kode.
sumber
Ini satu kalimat untuk Anda:
Begini cara Anda menggunakannya:
Objek Anda akan instantiated dengan penuh semangat. Ini mungkin atau mungkin bukan yang Anda inginkan.
sumber
type(wat)
atauwat.__class__
. Jika Anda benar-benar ingin mencapai ini, lebih baik menentukan kelas dan instantiate segera, tidak perlu mengacaukan dekorator.wat2 = type(wat)()
, tapi ini python, kita semua menyetujui orang dewasa dan semua itu. Anda tidak dapat menjamin bahwa hanya akan ada satu contoh, tetapi Anda dapat menjamin bahwa jika orang membuat yang kedua, itu akan terlihat jelek dan — jika mereka orang yang sopan dan terhormat — seperti tanda peringatan bagi mereka. Apa yang saya lewatkan?Lihat pertanyaan Stack Overflow Apakah ada cara sederhana dan elegan untuk mendefinisikan lajang di Python? dengan beberapa solusi.
Saya sangat merekomendasikan untuk menonton pembicaraan Alex Martelli tentang pola desain dengan python: bagian 1 dan bagian 2 . Secara khusus, di bagian 1 ia berbicara tentang lajang / objek negara bersama.
sumber
Inilah implementasi lajang saya sendiri. Yang harus Anda lakukan adalah menghias kelas; untuk mendapatkan singleton, Anda kemudian harus menggunakan
Instance
metode ini. Ini sebuah contoh:Dan inilah kodenya:
sumber
SingletonList = Singleton(list).Instance(); print(SingletonList is type(SingletonList)())
harus mencetakTrue
dalam singleton sejati; dengan cetakan kode AndaFalse
Metode 3 tampaknya sangat rapi, tetapi jika Anda ingin program Anda berjalan di Python 2 dan Python 3 , itu tidak berfungsi. Bahkan melindungi varian yang terpisah dengan tes untuk versi Python gagal, karena versi Python 3 memberikan kesalahan sintaksis dalam Python 2.
Terima kasih kepada Mike Watkins: http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/ . Jika Anda ingin program bekerja di Python 2 dan Python 3, Anda perlu melakukan sesuatu seperti:
Saya menganggap bahwa 'objek' dalam penugasan perlu diganti dengan 'BaseClass', tetapi saya belum mencobanya (saya telah mencoba kode seperti yang diilustrasikan).
sumber
class MyClass(metaclass=Singleton)
Nah, selain setuju dengan saran Pythonic umum tentang memiliki tingkat modul global, bagaimana dengan ini:
Output adalah:
sumber
_sealed
atribut? Sejauh yang saya lihat ini tidak melakukan apa-apa? Ada sesuatu yang menggangguku tentang hal ini yang mengatakan itu seharusnya tidak berkinerja baik ... Aku akan menjalankan beberapa tes komparatif minggu ini.__init__
untuk dipanggil setiap kali diinisialisasi. Hanya 'Menjadi diinisialisasi di class.method' sederhana. Adapun lekukan - Anda menggunakan tab dan spasi - Saya memperbaiki sebagian besar, tetapi tampaknya telah melewatkan satu jika Anda ingin mendapatkannya (cukup periksa edit log)Bagaimana dengan ini:
Gunakan itu sebagai dekorator di kelas yang seharusnya menjadi singleton. Seperti ini:
Ini mirip dengan
singleton = lambda c: c()
dekorator di jawaban lain. Seperti solusi lainnya, satu-satunya contoh memiliki nama kelas (MySingleton
). Namun, dengan solusi ini Anda masih dapat "membuat" instance (benar-benar mendapatkan satu-satunya instance) dari kelas, dengan melakukanMySingleton()
. Ini juga mencegah Anda membuat instance tambahan dengan melakukantype(MySingleton)()
(itu juga mengembalikan instance yang sama).sumber
type(MySingleton)()
,MySingleton.__init__()
dipanggil dan objek akan diinisialisasi beberapa kali; Anda dapat memperbaikinya dengan menuliscls.__init__ = lambda self: pass
di blog Andasingleton
. Juga, mengesampingkancls.__call__
tampaknya tidak ada gunanya, dan bahkan berbahaya -__call__
didefinisikan dalam konteks ini digunakan saat Anda meneleponMySingleton(any, list, of, arguments)
, bukan saat Anda menelepontype(MySingleton)(any, list, of, arguments)
.__init__()
dipanggil lagi ketika melakukantype(MySingleton)()
. Solusi yang Anda usulkan (tambahkancls.__init__ = lambda self: pass
) memberikan kesalahan sintaksis, karena bagian terakhir dari ekspresi lambda harus berupa ekspresi, bukan pernyataan. Namun, menambahkancls.__init__ = lambda self: None
karya, jadi saya menambahkan itu ke jawaban saya.__call__
. niat saya adalah untuk membuat keduanyatype(MySingleton)()
danMySingleton()
mengembalikan contoh. Jadi itu adalah melakukan apa yang saya inginkan. Anda dapat menganggap MySingleton sebagai tipe dari singleton atau instance dari singleton (atau keduanya).Saya akan melemparkan milik saya ke atas ring. Ini dekorator sederhana.
Manfaat yang menurut saya memiliki lebih dari beberapa solusi lain:
YourClass
. Ini termasuk tidak perlu menggunakan metaclass untuk kelas Anda (perhatikan bahwa metaclass di atas ada di pabrik, bukan kelas "nyata").YourClass
, sepertinya kelas (karena itu), dan mereka menggunakannya secara normal. Tidak perlu menyesuaikan penelepon ke fungsi pabrik.YourClass()
Instantiate apa yang masih menjadi contoh nyata dariYourClass
Anda diimplementasikan, bukan proxy dalam bentuk apa pun, sehingga tidak ada kemungkinan efek samping yang dihasilkan dari itu.isinstance(instance, YourClass)
dan operasi serupa masih bekerja seperti yang diharapkan (meskipun bit ini memang memerlukan abc sehingga menghalangi Python <2.6).Satu kelemahan terjadi pada saya: metode dan metode statis dari kelas nyata tidak dapat dipanggil secara transparan melalui kelas pabrik menyembunyikannya. Saya sudah menggunakan ini cukup jarang sehingga saya tidak pernah bertemu dengan kebutuhan itu, tetapi akan mudah diperbaiki dengan menggunakan metaclass khusus pada pabrik yang mengimplementasikan
__getattr__()
untuk mendelegasikan akses atribut all-ish ke kelas nyata.Pola terkait yang sebenarnya saya temukan lebih berguna (bukan berarti saya mengatakan hal-hal semacam ini sangat sering diperlukan) adalah pola "Unik" di mana instantiasi kelas dengan argumen yang sama menghasilkan kembali contoh yang sama. Yaitu "tunggal per argumen". Di atas beradaptasi dengan baik ini dan menjadi lebih ringkas:
Semua yang dikatakan, saya setuju dengan saran umum bahwa jika Anda berpikir Anda membutuhkan salah satu dari hal-hal ini, Anda mungkin harus berhenti sejenak dan bertanya pada diri sendiri apakah Anda benar-benar melakukannya. 99% dari waktu, YAGNI.
sumber
serial
komunikasi penanganan kelas , dan untuk membuat contoh Anda ingin mengirim port serial sebagai argumen, maka dengan pendekatan tradisional tidak akan berfungsisumber
Kode berdasarkan jawaban Tolli .
Penjelasan:
Buat kelas baru, mewarisi dari yang diberikan
cls
(itu tidak berubah
cls
jika seseorang ingin misalnyasingleton(list)
)Buat contoh. Sebelum mengganti
__new__
itu sangat mudah.__new__
menggunakan metode yang ditentukan saat yang lalu.Fungsi kembali
instance
hanya ketika itu yang diinginkan penelepon, jika tidak memunculkanTypeError
.Kondisi ini tidak terpenuhi ketika seseorang mencoba untuk mewarisi dari kelas yang didekorasi.
instance
sudah diinisialisasi, jadi fungsi menggantikan__init__
dengan fungsi tidak melakukan apa-apa.Lihat bekerja online
sumber
Ini sedikit mirip dengan jawaban oleh fab tetapi tidak persis sama.
The kontrak tunggal tidak mengharuskan kami dapat memanggil konstruktor beberapa kali. Sebagai seorang singleton harus diciptakan hanya sekali dan sekali saja, tidakkah harus dilihat diciptakan hanya sekali? "Memalsukan" konstruktor bisa dibilang merusak keterbacaan.
Jadi saran saya hanyalah ini:
Ini tidak mengesampingkan penggunaan konstruktor atau bidang
instance
dengan kode pengguna:... jika Anda tahu pasti bahwa
Elvis
itu belum dibuat, dan ituKing
telah.Tapi itu mendorong pengguna untuk menggunakan
the
metode ini secara universal:Untuk menyelesaikan ini, Anda juga dapat mengganti
__delattr__()
untuk menaikkan Pengecualian jika ada upaya untuk menghapusinstance
, dan menimpa__del__()
sehingga menimbulkan Pengecualian (kecuali kami tahu program ini berakhir ...)Perbaikan lebih lanjut
Terima kasih saya kepada mereka yang telah membantu dengan komentar dan pengeditan, yang lebih banyak lagi kami sambut. Sementara saya menggunakan Jython, ini seharusnya bekerja lebih umum, dan aman untuk thread.
Catatan:
__new__
__new__
Anda harus mendekorasi dengan @classmethod atau__new__
akan menjadi metode instan yang tidak terikatthe
properti tingkat kelas, mungkin mengubah nama menjadiinstance
sumber
__new
__ daripada__init__
, karena itu murni bertindak pada atribut kelas dan ini mencegah dari sana sebentar menjadi contoh kedua. Perbedaannya antara ini dan metode 2, adalah apakah mencoba menginisialisasi lebih dari satu kali mengembalikan instance tunggal atau menimbulkan pengecualian. Saya pikir saya senang bahwa baik memenuhi pola singleton, satu lebih mudah digunakan, sementara yang lain lebih eksplisit bahwa itu adalah singleton.__init__
mencegah subclassing, tetapi sementara ini membuat segalanya lebih mudah, itu tidak diperlukan__init__
agar mudah-mudahan ini subclassable ...the
mungkin bisa mendapat manfaat dari menjadi metode kelas karena alasan yang samaOne liner (saya tidak bangga, tetapi berhasil):
sumber
Jika Anda tidak perlu inisialisasi malas dari instance Singleton, maka yang berikut harus mudah dan aman:
Cara ini
A
adalah singleton yang diinisialisasi pada modul import.sumber
Mungkin saya salah paham tentang pola tunggal tetapi solusi saya sederhana dan pragmatis (pythonic?). Kode ini memenuhi dua tujuan
Foo
diakses di mana saja (global).Foo
bisa ada.Ini kodenya.
Keluaran
sumber
Setelah berjuang dengan ini selama beberapa waktu saya akhirnya datang dengan yang berikut, sehingga objek konfigurasi hanya akan dimuat sekali, ketika dipanggil dari modul yang terpisah. Metaclass memungkinkan instance kelas global untuk disimpan dalam dict bawaan, yang saat ini tampaknya menjadi cara paling rapi untuk menyimpan program global yang tepat.
sumber
Saya tidak ingat di mana saya menemukan solusi ini, tetapi saya menemukan ini sebagai yang paling 'elegan' dari sudut pandang non-Python-expert saya:
Kenapa saya suka ini? Tidak ada dekorator, tidak ada kelas meta, tidak ada pewarisan berganda ... dan jika Anda memutuskan Anda tidak ingin menjadi Singleton lagi, hapus saja
__new__
metodenya. Karena saya baru mengenal Python (dan OOP secara umum), saya berharap seseorang akan meluruskan mengapa ini merupakan pendekatan yang mengerikan?sumber
__new__
. Jangan ulangi dirimu sendiri .*args
dan**kwargs
, dan kemudian tidak melakukan apa pun dengan mereka? Lulus mereka ke dalamdict.__new__
cara ini:dict.__new__(cls, *args, **kwargs)
.__init__
metode setiap kali kelas dipanggil. Jika__init__
metode Anda benar-benar melakukan sesuatu, Anda akan melihat masalahnya. Setiap kali Anda melakukannyaSomeSingleton()
, status singleton Anda diatur ulang oleh__init__
metode.Ini adalah cara yang saya pilih untuk menerapkan lajang:
sumber
Jawaban ini kemungkinan bukan yang Anda cari. Saya ingin seorang singleton dalam arti bahwa hanya objek itu yang memiliki identitas, sebagai perbandingan. Dalam kasus saya itu sedang digunakan sebagai Nilai Sentinel . Yang jawabannya sangat sederhana, buat objek apa pun
mything = object()
dan berdasarkan sifat python, hanya benda itu yang akan memiliki identitasnya.sumber
eval
atauimportlib.reload
.Solusi ini menyebabkan beberapa polusi namespace pada level modul (tiga definisi bukan hanya satu), tetapi saya merasa mudah untuk mengikuti.
Saya ingin dapat menulis sesuatu seperti ini (inisialisasi malas), tetapi sayangnya kelas tidak tersedia dalam definisi tubuh mereka sendiri.
Karena itu tidak mungkin, kami dapat memecah inisialisasi dan contoh statis di
Inisialisasi yang bersemangat:
Inisialisasi malas:
Inisialisasi yang bersemangat:
sumber