To pytanie nie dotyczy dyskusji, czy pożądany jest wzór singletonu , jest anty-wzorem, czy jakiejkolwiek wojny religijnej, ale do omówienia, w jaki sposób ten wzór najlepiej wdrożyć w Pythonie w najbardziej pythonowy sposób. W tym przypadku definiuję słowo „najbardziej python”, co oznacza, że jest ono zgodne z „zasadą najmniejszego zdziwienia” .
Mam wiele klas, które stałyby się singletonami (mój przypadek użycia dotyczy rejestratora, ale to nie jest ważne). Nie chcę zaśmiecać kilku klas z dodanym gumph, kiedy mogę po prostu odziedziczyć lub ozdobić.
Najlepsze metody:
Metoda 1: 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
Plusy
- Dekoratorzy są addytywni w sposób, który jest często bardziej intuicyjny niż wielokrotne dziedziczenie.
Cons
- Podczas gdy obiekty utworzone za pomocą MyClass () byłyby prawdziwymi obiektami singletonowymi, sam MyClass jest funkcją, a nie klasą, więc nie można wywoływać z niej metod klas. Również
m = MyClass(); n = MyClass(); o = type(n)();
wtedym == n && m != o && n != o
Metoda 2: Klasa podstawowa
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
Plusy
- To prawdziwa klasa
Cons
- Wielokrotne dziedziczenie - eugh!
__new__
można zastąpić podczas dziedziczenia z drugiej klasy podstawowej? Trzeba myśleć więcej niż to konieczne.
Metoda 3: Metaklasa
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
Plusy
- To prawdziwa klasa
- Auto-magicznie obejmuje dziedziczenie
- Używa
__metaclass__
do właściwego celu (i uświadomił mi o tym)
Cons
- Czy są jakieś?
Metoda 4: Dekorator zwraca klasę o tej samej nazwie
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
Plusy
- To prawdziwa klasa
- Auto-magicznie obejmuje dziedziczenie
Cons
- Czy nie ma narzutów związanych z tworzeniem każdej nowej klasy? Tutaj tworzymy dwie klasy dla każdej klasy, którą chcemy stworzyć singleton. Chociaż w moim przypadku jest to w porządku, martwię się, że to może się nie skalować. Oczywiście jest kwestia debaty, czy skalowanie tego wzorca nie jest zbyt łatwe ...
- Jaki jest sens tego
_sealed
atrybutu - Nie można wywoływać metod o tej samej nazwie w klasach podstawowych,
super()
ponieważ będą się powtarzać. Oznacza to, że nie możesz dostosowywać__new__
i nie możesz podklasować klasy, do której musisz zadzwonić__init__
.
Metoda 5: moduł
plik modułu singleton.py
Plusy
- Prosty jest lepszy niż złożony
Cons
foo.x
lub jeśli nalegaszFoo.x
zamiastFoo().x
); użyj atrybutów klas i metod static / class (Foo.x
).Odpowiedzi:
Użyj metaklasy
Poleciłbym Metodę 2 , ale lepiej jest użyć metaklasy niż klasy podstawowej. Oto przykładowa implementacja:
Lub w Python3
Jeśli chcesz uruchomić za
__init__
każdym razem, gdy klasa jest wywoływana, dodajdo
if
oświadczenia wSingleton.__call__
.Kilka słów o metaklasach. Metaklasa jest klasą klasy ; to znaczy klasa jest instancją jej metaklasy . Metaklasę obiektu można znaleźć w Pythonie za pomocą
type(obj)
. Normalne klasy nowego stylu są typutype
.Logger
w powyższym kodzie będzie typuclass 'your_module.Singleton'
, podobnie jak (jedyna) instancjaLogger
będzie typuclass 'your_module.Logger'
. Podczas rozmowy telefonicznej z rejestratoraLogger()
, Python najpierw pyta o metaklasąLogger
,Singleton
co robić, umożliwiając tworzenie instancji należy uprzedzać. Ten proces jest taki sam, jak Python pytający klasę, co robić, wywołując,__getattr__
gdy odwołujesz się do jednego z jego atrybutówmyclass.attribute
.Metaklasa zasadniczo decyduje, co oznacza definicja klasy i jak ją wdrożyć. Zobacz na przykład http://code.activestate.com/recipes/498149/ , który zasadniczo odtwarza style C
struct
w Pythonie przy użyciu metaklas. Wątek Jakie są (konkretne) przypadki użycia metaklas? podaje także kilka przykładów, na ogół wydają się one być związane z programowaniem deklaratywnym, zwłaszcza w przypadku ORM.W tej sytuacji, jeśli użyjesz metody nr 2 , a podklasa definiuje
__new__
metodę, będzie ona wykonywana przy każdym wywołaniuSubClassOfSingleton()
- ponieważ odpowiada za wywołanie metody zwracającej przechowywaną instancję. Metaklasa zostanie wywołana tylko raz , gdy zostanie utworzona jedyna instancja. Chcesz dostosować, co to znaczy nazywać klasę , zależnie od jej typu.Zasadniczo sensowne jest użycie metaklasy do wdrożenia singletonu. Singleton jest wyjątkowy, ponieważ jest tworzony tylko raz , a metaklasa to sposób, w jaki dostosowujesz tworzenie klasy . Korzystanie z metaklasy daje większą kontrolę na wypadek konieczności dostosowania definicji klas singletonów na inne sposoby.
Twoje singletony nie będą wymagały wielokrotnego dziedziczenia (ponieważ metaklasa nie jest klasą podstawową), ale w przypadku podklas utworzonej klasy, które używają wielokrotnego dziedziczenia, musisz upewnić się, że klasa singleton jest pierwszą / najbardziej lewą klasą z metaklasą, która redefiniuje
__call__
Jest to bardzo mało prawdopodobne, aby stanowił problem. Dict instancji nie znajduje się w przestrzeni nazw instancji, więc przypadkowo go nie zastąpi.Usłyszysz również, że wzorzec singletonu narusza „zasadę pojedynczej odpowiedzialności” - każda klasa powinna zrobić tylko jedną rzecz . W ten sposób nie musisz się martwić, że zepsujesz jedną rzecz, którą robi kod, jeśli musisz zmienić inną, ponieważ są one osobne i hermetyzowane. Implementacja metaklasy przechodzi ten test . Metaklasa jest odpowiedzialna za wymuszanie wzorca, a utworzona klasa i podklasy nie muszą mieć świadomości, że są singletonami . Metoda nr 1 kończy się niepowodzeniem tego testu, jak zauważyłeś w „MyClass sama jest funkcją, a nie klasą, więc nie można wywoływać z niej metod klas”.
Wersja kompatybilna z Python 2 i 3
Pisanie czegoś, co działa zarówno w Python2, jak i 3, wymaga użycia nieco bardziej skomplikowanego schematu. Ponieważ metaklasy są zwykle podklasami typu
type
, możliwe jest użycie jednej z nich, aby dynamicznie utworzyć pośrednią klasę bazową w czasie wykonywania z nią jako metaklasą, a następnie użyć jej jakoSingleton
klasy podstawowej publicznej klasy bazowej. Trudniej to wytłumaczyć niż zrobić, jak pokazano poniżej:Ironicznym aspektem tego podejścia jest to, że wykorzystuje podklasę do implementacji metaklasy. Jedną z możliwych zalet jest to, że w przeciwieństwie do czystej metaklasy
isinstance(inst, Singleton)
powróciTrue
.Korekty
W innym temacie zapewne już to zauważyłeś, ale implementacja klasy podstawowej w oryginalnym poście jest nieprawidłowa.
_instances
należy odwoływać się do klasy , należy jej użyćsuper()
lub rekursuje się i__new__
jest to metoda statyczna, do której należy przekazać klasę , a nie metoda klasy, ponieważ rzeczywista klasa nie została jeszcze utworzona nazywa się. Wszystkie te rzeczy będą prawdziwe także dla implementacji metaklasy.Dekorator powracający klasę
Początkowo pisałem komentarz, ale był za długi, więc dodam go tutaj. Metoda nr 4 jest lepsza niż inna wersja dekoratora, ale zawiera więcej kodu niż jest to potrzebne do singletona i nie jest tak jasne, co robi.
Główne problemy wynikają z tego, że klasa jest własną klasą podstawową. Po pierwsze, czy to nie dziwne, że klasa jest podklasą niemal identycznej klasy o tej samej nazwie, która istnieje tylko w jej
__class__
atrybucie? Oznacza to również, że nie można określić żadnych metod, które wywołać metodę o tej samej nazwie na ich klasy podstawowej zsuper()
ponieważ będą one recurse. Oznacza to, że twoja klasa nie może się dostosowywać__new__
i nie może wywodzić się z żadnych klas, które trzeba__init__
do nich wezwać.Kiedy stosować wzór singletonu
Twój przypadek użycia jest jednym z lepszych przykładów chęci skorzystania z singletonu. Mówisz w jednym z komentarzy: „Dla mnie logowanie zawsze wydawało się naturalnym kandydatem do Singletonów”. Masz absolutną rację .
Kiedy ludzie mówią, że singletony są złe, najczęstszym powodem jest ukryty stan wspólny . Podczas gdy w przypadku zmiennych globalnych i importu modułów najwyższego poziomu jawny jest stan współdzielony, inne przekazywane obiekty są generalnie tworzone. To dobra uwaga, z dwoma wyjątkami .
Pierwszym i wspomnianym w różnych miejscach jest to, że singletony są stałe . Używanie stałych globalnych, zwłaszcza wyliczeń, jest powszechnie akceptowane i uważane za rozsądne, ponieważ bez względu na wszystko, żaden z użytkowników nie może ich zepsuć dla żadnego innego użytkownika . Dotyczy to również stałego singletonu.
Drugi wyjątek, o którym mniej się wspomina, jest odwrotny - gdy singleton jest tylko ujściem danych , a nie źródłem danych (bezpośrednio lub pośrednio). Właśnie dlatego rejestratorzy czują się jak „naturalne” zastosowanie singletonów. Ponieważ różni użytkownicy nie zmieniają rejestratorów w sposób, w jaki dbają o nich inni użytkownicy, nie ma tak naprawdę wspólnego stanu . To neguje główny argument przeciwko wzorowi singletonów i czyni je rozsądnym wyborem ze względu na łatwość użycia do zadania.
Oto cytat z http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html :
źródło
__new__
w metaklasie ma miejsce, gdy klasa jest nowa - kiedy jest zdefiniowana, a nie kiedy instancja byłaby nowa. Wywołanie class (MyClass()
) to operacja, którą chcesz zastąpić, a nie definicja klasy. Jeśli naprawdę chcesz zrozumieć, jak działa Python, najlepszą rzeczą, jaką możesz zrobić (oprócz używania go), jest docs.python.org/reference/datamodel.html . Dobrym źródłem informacji o metaklasach jest eli.thegreenplace.net/2011/08/14/python-metaclasses-by-example . Dobrym artykułem na temat singletonów jest seria z blogu google, który zamieściłem w tej odpowiedzi.Moduły są importowane tylko raz, wszystko inne jest przesadne. Nie używaj singletonów i staraj się nie używać globałów.
źródło
s = some_global_variable; str = pickle.dumps(s); s1 = pickle.loads(str); print s is s1; # False
is
operator sprawdza równość wskaźnika. Byłbym raczej zaskoczony - do tego stopnia, że nazwałbym go błędem - gdybypickle.loads
zwrócił odwołanie do wcześniej istniejącego obiektu, a nie odwołanie do nowo utworzonego obiektu. Zatem testowanie, czys is s1
nie mówi nic o przydatności wykorzystania modułów jako singletonów.pickle.loads()
to robi, np. Dla przypadkówbool
iNoneType
.pickle.loads(pickle.dumps(False)) is False
plonyTrue
True
,False
iNone
, i nie ma nic wspólnego z pupę kodupickle.loads
. Można to również bezpiecznie robić tylko w przypadku obiektów tylko do odczytu. Gdybypickle.loads
zwrócić odwołanie do już istniejącego modyfikowalnego obiektu - takiego jak moduł - byłby to błąd. (I tak twierdzę, że przykład kodu dividebyzero niczego nie dowodzi.)Użyj modułu. Jest importowany tylko raz. Zdefiniuj w nim niektóre zmienne globalne - będą to „atrybuty” singletona. Dodaj kilka funkcji - „metody” singletona.
źródło
Prawdopodobnie nigdy nie potrzebujesz singletona w Pythonie. Wystarczy zdefiniować wszystkie dane i funkcje w module, aby uzyskać de facto singleton.
Jeśli naprawdę musisz mieć lekcję singletona, wybrałbym:
Używać:
gdzie mysingleton.py jest nazwą pliku, w którym zdefiniowano My_Singleton. Działa to, ponieważ po pierwszym zaimportowaniu pliku Python nie uruchamia ponownie kodu.
źródło
Oto jedna linijka dla Ciebie:
Oto jak go używasz:
Twój obiekt jest chętnie tworzony. To może być lub nie być to, czego chcesz.
źródło
type(wat)
lubwat.__class__
. Jeśli naprawdę chcesz to osiągnąć, lepiej zdefiniuj klasę i od razu ją utwórz, nie musisz się martwić dekoratorem.wat2 = type(wat)()
, ale to jest python, wszyscy zgadzamy się na dorosłych i tak dalej. Nie możesz zagwarantować , że będzie tylko jedna instancja, ale możesz zagwarantować, że jeśli ludzie zrobią drugą, będzie wyglądać brzydko i - jeśli są przyzwoitymi, uczciwymi ludźmi - jak znak ostrzegawczy. czego mi brakuje?Sprawdź pytanie Przepełnienie stosu Czy istnieje prosty, elegancki sposób definiowania singletonów w Pythonie? z kilkoma rozwiązaniami.
Zdecydowanie polecam oglądać rozmowy Alexa Martellego na temat wzorców projektowych w pythonie: część 1 i część 2 . W szczególności w części 1 mówi o singletonach / obiektach stanu wspólnego.
źródło
Oto moja własna implementacja singletonów. Wszystko, co musisz zrobić, to udekorować klasę; aby uzyskać singleton, musisz użyć
Instance
metody. Oto przykład:A oto kod:
źródło
SingletonList = Singleton(list).Instance(); print(SingletonList is type(SingletonList)())
powinien drukowaćTrue
w prawdziwym singletonie; z nadrukami koduFalse
Metoda 3 wydaje się być bardzo fajna, ale jeśli chcesz, aby twój program działał zarówno w Pythonie 2, jak i Pythonie 3 , nie działa. Nawet ochrona osobnych wariantów testami wersji Python kończy się niepowodzeniem, ponieważ wersja Python 3 daje błąd składniowy w Python 2.
Podziękowania dla Mike'a Watkinsa: http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/ . Jeśli chcesz, aby program działał zarówno w Pythonie 2, jak i Pythonie 3, musisz zrobić coś takiego:
Zakładam, że „obiekt” w przydziale musi zostać zastąpiony przez „BaseClass”, ale nie próbowałem tego (próbowałem kodu, jak pokazano).
źródło
class MyClass(metaclass=Singleton)
Cóż, poza tym, że zgadzasz się z ogólną sugestią Pythona dotyczącą posiadania globalnego poziomu na poziomie modułu, co powiesz na to:
Dane wyjściowe to:
źródło
_sealed
atrybutu? O ile widzę, to nic nie robi? Coś mnie dręczy w tym, co mówi, że nie powinno działać dobrze ... W tym tygodniu przeprowadzę kilka testów porównawczych.__init__
które będą wywoływane za każdym razem, gdy zostaną zainicjowane. Po prostu „Inicjalizacja w klasie. Metoda”. co do wcięcia - używałeś tabulatorów i spacji - naprawiłem większość z nich, ale wydaje się, że przegapiłem jedną, jeśli chcesz ją uzyskać (po prostu sprawdź dziennik edycji)Co powiesz na to:
Użyj go jako dekoratora w klasie, która powinna być singletonem. Lubię to:
Jest to podobne do
singleton = lambda c: c()
dekoratora w innej odpowiedzi. Podobnie jak inne rozwiązanie, jedyna instancja ma nazwę class (MySingleton
). Jednak dzięki temu rozwiązaniu możesz nadal „tworzyć” instancje (faktycznie uzyskać jedyną instancję) z klasy, wykonując toMySingleton()
. Zapobiega to również tworzeniu dodatkowych instancji przez wykonanietype(MySingleton)()
(co również zwraca tę samą instancję).źródło
type(MySingleton)()
,MySingleton.__init__()
zostaje wywołany, a obiekt zostaje zainicjowany wiele razy; możesz to naprawić pisząccls.__init__ = lambda self: pass
w swoimsingleton
. Również nadpisywaniecls.__call__
wydaje się bezcelowe, a nawet szkodliwe -__call__
zdefiniowane w tym kontekście jest używane podczas połączeniaMySingleton(any, list, of, arguments)
, a nie podczas połączeniatype(MySingleton)(any, list, of, arguments)
.__init__()
zostanie to ponownie wywołane podczas działaniatype(MySingleton)()
. Rozwiązanie, które proponujesz (dodajeszcls.__init__ = lambda self: pass
), powoduje błąd składniowy, ponieważ ostatnia część wyrażenia lambda musi być wyrażeniem, a nie wyrażeniem. Jednak dodawaniecls.__init__ = lambda self: None
działa, więc dodałem to do mojej odpowiedzi.__call__
. moim zamiarem było zrobienie obutype(MySingleton)()
iMySingleton()
zwrócenie instancji. Więc robi to, co chciałem. Możesz myśleć o MySingleton jako o typie singletonu lub instancji singletonu (lub obu).Wrzucę moją do ringu. To prosty dekorator.
Myślę, że korzyści w porównaniu z innymi rozwiązaniami:
YourClass
. Oznacza to, że nie musisz używać metaklasy w swojej klasie (pamiętaj, że powyższa metaklasa jest w fabryce, a nie w „prawdziwej” klasie).YourClass
, wygląda jak klasa (ponieważ tak jest) i używają jej normalnie. Nie trzeba dostosowywać dzwoniących do funkcji fabrycznych.YourClass()
tworzy instancję, jest nadal prawdziwą instancją,YourClass
którą wdrożyłeś, a nie jakimkolwiek proxy, więc nie ma z tego powodu żadnych skutków ubocznych.isinstance(instance, YourClass)
i podobne operacje nadal działają zgodnie z oczekiwaniami (choć ten bit wymaga abc, więc wyklucza Pythona <2.6).Przydarza mi się jedna wada: metody klasowe i metody statyczne prawdziwej klasy nie są przezroczyście wywoływalne przez klasę fabryczną, która je ukrywa. Używałem tego na tyle rzadko, że nigdy nie spotkałem się z tą potrzebą, ale można to łatwo naprawić, używając niestandardowej metaklasy w fabryce, która implementuje
__getattr__()
aby delegować dostęp do wszystkich atrybutów do prawdziwej klasy.Powiązany wzorzec, który faktycznie uważam za bardziej przydatny (nie to, że mówię, że tego rodzaju rzeczy są w ogóle bardzo często wymagane) to „unikalny” wzorzec, w którym utworzenie instancji klasy z tymi samymi argumentami powoduje odzyskanie tego samego wystąpienia. To znaczy „singleton na argumenty”. Powyższe dostosowuje się do tego dobrze i staje się jeszcze bardziej zwięzłe:
To powiedziawszy, zgadzam się z ogólną radą, że jeśli uważasz, że potrzebujesz jednej z tych rzeczy, naprawdę powinieneś się na chwilę zatrzymać i zadać sobie pytanie, czy naprawdę tego potrzebujesz. 99% czasu, YAGNI.
źródło
serial
komunikację obsługującą klasę i aby utworzyć instancję, którą chcesz wysłać port szeregowy jako argument, wówczas tradycyjne podejście nie będzie działaćźródło
Kod oparty na odpowiedzi Tolli .
Wyjaśnienie:
Utwórz nową klasę, dziedzicząc po danym
cls
(nie zmienia się,
cls
jeśli ktoś chce na przykładsingleton(list)
)Utwórz instancję. Przed zastąpieniem
__new__
jest to takie proste.__new__
przy użyciu metody zdefiniowanej przed chwilą.Funkcja zwraca
instance
tylko wtedy, gdy oczekuje tego rozmówca, w przeciwnym razie podnosiTypeError
.Warunek ten nie jest spełniony, gdy ktoś próbuje odziedziczyć klasę odznaczoną.
instance
jest już zainicjowany, więc funkcja zastępuje__init__
funkcję, która nic nie robi.Zobacz, jak działa online
źródło
Jest nieco podobny do odpowiedzi fab, ale nie dokładnie taki sam.
Umowa singleton nie wymaga, abyśmy byli w stanie wywołać konstruktora wiele razy. Jako że singleton powinien zostać utworzony raz i tylko raz, czy nie należy go postrzegać jako utworzonego tylko raz? „Fałszowanie” konstruktora prawdopodobnie pogarsza czytelność.
Więc moja propozycja jest taka:
Nie wyklucza to użycia konstruktora lub pola
instance
według kodu użytkownika:... jeśli wiesz na pewno, że
Elvis
jeszcze nie zostało utworzone i takKing
jest.Ale zachęca użytkowników do
the
uniwersalnego korzystania z tej metody:Aby to zakończyć, możesz również przesłonić
__delattr__()
zgłoszenie wyjątku, jeśli podjęta zostanie próba usunięciainstance
, i przesłonić__del__()
zgłoszenie wyjątku (chyba że wiemy, że program się kończy ...)Dalsze doskonalenia
Dziękuję tym, którzy pomogli w komentarzach i zmianach, z których więcej jest mile widziane. Podczas korzystania z Jython powinno to działać bardziej ogólnie i być bezpieczne dla wątków.
Uwaga:
__new__
__new__
musisz udekorować za pomocą @classmethod lub__new__
będzie to metoda instancji niezwiązanejthe
właściwość na poziomie klasy, ewentualnie zmieniając jej nazwę nainstance
źródło
__new
__ zamiast__init__
, ponieważ działa on wyłącznie na atrybuty klasy, co zapobiega krótkotrwałemu wystąpieniu. Różnica między tą a metodą 2 polega na tym, czy próba zainicjowania więcej niż raz zwraca pojedynczą instancję, czy wywołuje wyjątek. Myślę, że cieszę się, że albo spełniają wzór singletonu, jeden jest łatwiejszy w użyciu, a drugi jest bardziej wyraźny, że jest singletonem.__init__
zapobiega podklasom, ale chociaż to ułatwia, nie jest wymagane__init__
tak, aby mam nadzieję, że będzie to podklasa ...the
prawdopodobnie skorzystałby na byciu metodą klasową z podobnych powodówJeden liniowiec (nie jestem dumny, ale spełnia swoją rolę):
źródło
Jeśli nie potrzebujesz leniwej inicjalizacji instancji Singleton, poniższe czynności powinny być łatwe i bezpieczne dla wątków:
W ten sposób
A
jest singleton zainicjowany podczas importu modułu.źródło
Może nie rozumiem wzoru singletonu, ale moje rozwiązanie jest proste i pragmatyczne (pytoniczne?). Ten kod spełnia dwa cele
Foo
dostępna wszędzie (globalnie).Foo
Może istnieć tylko jedna instancja .To jest kod.
Wynik
źródło
Po dłuższym zmaganiu się z tym w końcu wymyśliłem następujące rzeczy, aby obiekt konfiguracyjny został załadowany tylko raz, gdy zostanie wywołany z oddzielnych modułów. Metaklasa pozwala na przechowywanie instancji klasy globalnej we wbudowanym dykcie, który obecnie wydaje się najładniejszym sposobem przechowywania odpowiedniego programu globalnego.
źródło
Nie pamiętam, gdzie znalazłem to rozwiązanie, ale uważam, że jest to najbardziej „eleganckie” z mojego punktu widzenia, nie znającego języka Python:
Dlaczego to lubię Bez dekoratorów, bez meta klas, bez wielokrotnego dziedziczenia ... a jeśli zdecydujesz, że nie chcesz, aby był to Singleton, po prostu usuń
__new__
metodę. Ponieważ jestem nowy w Pythonie (i ogólnie OOP), spodziewam się, że ktoś wyjaśni mi, dlaczego jest to okropne podejście?źródło
__new__
. Nie powtarzaj się .*args
i**kwargs
, a potem nic nie robi z nimi? Przekazać je wdict.__new__
ten sposób:dict.__new__(cls, *args, **kwargs)
.__init__
metody przy każdym wywołaniu klasy. Jeśli twoja__init__
metoda rzeczywiście coś zrobiła, zauważysz problem. Ilekroć to zrobiszSomeSingleton()
, stan twojego singletonu jest resetowany__init__
metodą.To jest mój preferowany sposób implementacji singletonów:
źródło
Ta odpowiedź prawdopodobnie nie jest tym, czego szukasz. Chciałem singletonu w tym sensie, że tylko ten obiekt miał swoją tożsamość, dla porównania. W moim przypadku był on używany jako wartość wartownika . Na które odpowiedź jest bardzo prosta, utwórz dowolny obiekt,
mything = object()
a ze względu na naturę pytona tylko ta rzecz będzie miała swoją tożsamość.źródło
eval
lubimportlib.reload
.To rozwiązanie powoduje zanieczyszczenie przestrzeni nazw na poziomie modułu (trzy definicje, a nie tylko jedna), ale uważam, że jest łatwe do naśladowania.
Chciałbym móc napisać coś takiego (leniwa inicjalizacja), ale niestety klasy nie są dostępne w treści ich własnych definicji.
Ponieważ nie jest to możliwe, możemy przełamać inicjalizację i instancję statyczną w
Chętna inicjalizacja:
Leniwa inicjalizacja:
Chętna inicjalizacja:
źródło