Singleton

A weblaboron olvastam ma egy cikket inf3rno tollából, amely az ősosztályként megvalósított singleton problémáját járja körül PHP-ban. (Egyke tervezési minta, de én nem szeretem az ilyeneket lefordítani, mert nagyon suta tud lenni, szerintem.) Pythonban sem egyértelmű a dolog, a klasszikus "legyen privát a konstruktor, és egy metódus adja vissza a példányt" megoldás nem működik, mert pythonban a konstruktor mindig publikus. Ennek ellenére nem az okoz nehézséget, hogy hogyan valósítsuk meg a singletont, hanem hogy a lehetőségek közül melyiket válasszuk :)

Nézzünk néhány példát, a teljesség igénye nélkül! Nem kell megijedni, ha kezdőbb olvasók nem teljesen értik a példákat, megértésükhöz szükséges a python nyelv bizonyos szintű ismerete.

1. Singleton ősosztály

A legelső megvalósítás, ami leginkább hasonlít a klasszikusra, illetve a fenti cikkben megvalósítottra, az egy ősosztály, amelyből leszármaztatott osztályaink is singletonok lesznek.

class Singleton(object):

    __instance = None

    def __new__(klass):
        if type(klass.__instance) != klass:
            klass.__instance = object.__new__(klass)
        return klass.__instance

    @classmethod
    def getInstance(klass):
        return klass()

A getInstance metódust csak a rend kedvéért csináltam, maga a "konstruktor" adja vissza az egyetlen létező példányt, a getInstance csak őt hívja.

>>> class MySingleton(Singleton):
...   def setA(self, a):
...     self.a = a
...
>>> ms1 = MySingleton()
>>> ms2 = MySingleton()
>>> ms3 = MySingleton.getInstance()
>>> ms1 is ms2 is ms3
True
>>> ms1.setA(5)
>>> ms2.a += 10
>>> ms3.a
15

Működni látszik :)

2. Singleton Metaclass

A python a metaprogramozás kedvelőinek is nyújt csemegéket, ilyenek például a metaclassok, azaz az "osztály generátor osztályok". Ezekről majd kicsit később talán bővebben is lesz szó, de most lássunk egy metaclass alapú singleton megvalósítást:

class SingletonMeta(type):

    def __init__(klass, name, bases, dict):
        super(SingletonMeta, klass).__init__(name, bases, dict)
        klass.__instance = None

    def __call__(klass, *args, **kwargs):
        if klass.__instance is None:
            klass.__instance = super(SingletonMeta, klass).__call__(*args, **kwargs)
        return klass.__instance

    def getInstance(klass):
        return klass()

Lássunk példát a használatára:

>>> class MySingleton2(object):
...   __metaclass__ = SingletonMeta
...   def setA(self, a):
...     self.a = a
...
>>> ms1 = MySingleton2()
>>> ms2 = MySingleton2()
>>> ms1 is ms2
True

A singleton tulajdonság továbböröklődik a gyermekosztály felé is:

>>> class A(MySingleton2):
...   def getA(self):
...     return self.a
...
>>> a1 = A.getInstance()
>>> a2 = A()
>>> a1 is a2
True
>>> a1.setA(42)
>>> a2.getA()
42

3. Assimilate! - A Borg

Vannak fejlesztők, akik nem szeretik a singleton mintát bizonyos célokra, és szeretnek különálló - de azonos tudattal rendelkező - objektumokat használni. A python számukra is nyújt megoldást, ez pedig a Borg minta.

class Borg(object):

    __shared_state = {}

    def __init__(self):
        self.__dict__ = self.__shared_state

Szintén leszármazhatunk belőle - bár ezt a két extra sort akár be is írhatjuk a saját Borg-ősnek szánt osztályunkba. A Borg objektumok különálló objektumok lesznek, csak a "tudatuk", azaz a belső állapotuk lesz közös. (Hirtelen nem jut eszembe olyan eset, ahol ez jobb, mint a hagyományos singleton minta, de már láttam rá példát.)

>>> class B(Borg):
...   def setB(self, b):
...     self.b = b
...
>>> b1 = B()
>>> b2 = B()
>>> b1 is b2
False
>>> b1.setB(42)
>>> b1.b
42
>>> b1.b is b2.b
True

4. Singleton dekorátor

Hagyományos osztályainkat is felruházhatjuk (kvázi utólag) singleton tulajdonsággal. Van hogy az osztályt mások készítették, mi csak felhasználnánk, esetleg OOP nézeteinkbe nem illeszkedik, hogy a Fold az egy Singleton és nem pedig csak egy Bolygo (persze pythonban mindkettő lehet egyszerre, mert van többszörös öröklődés). Vagy csak mért így egyszerűbb.

def singleton(klass):
    instances = {}
    def getInstance():
        if klass not in instances:
            instances[klass] = klass()
        return instances[klass]
    return getInstance

A dekorátor kódja a legegyszerűbb talán az eddigiek közül, ehhez elég "csak" azt tudni, hogy mi az a dekorátor :)

Példa a felhasználásra:

>>> @singleton
... class C(object):
...   def setC(self, c):
...     self.c = c
...
>>> c1 = C()
>>> c2 = C()
>>> c1 is c2
True
>>> ImpSingleton = singleton(ImportaltOsztaly)
>>> i1 = ImpSingleton()
>>> i2 = ImpSingleton()
>>> i1 is i2
True

Egyelőre ennyi, hazaértemkor gondoltam hipp-hopp összeírom a gondolataimat a témával kapcsolatban, és az előbb szóltak - jogosan -, hogy kb. 2 órája ezt a postot írom. Mégegyszer hangsúlyozom, nem kell megijedni, ha nem érthető minden elsőre, másodikra se biztos, hogy az lesz, de ha a tervek szerint írogatok ide, akkor pár hónap múlva visszalapozva mindennek egyértelműnek kell majd lennie - majd igyekszem :)

A fent megvalósított osztályok letölthetőek innen: singleton.py

27júl.

5 Comment for Singleton

  1. Gábor says:

    Szia, én is olvastam a weblaboron. És egy szót sem értettem. Ez azért van mert nem értek az oophez. Tudnál valami magyar könyvet ajánlani amit ha elolvasnék, már érteném mikről van itt szó? Köszi.

    • RePa says:

      En szakmai nyomtatott konyveket nemnagyon szoktam olvasni, OOP-t az egyetemen tanultunk, de igazan hasznalat - mondjuk munka - kozben erti meg a dolgokat, hogy mit hogyan, es miert erdemes csinalni. Az OOP alapok utan pedig erdemes megnezegetni a tervezesi mintakat (design patterns), amikhez szerintem nem kell szo szerint ragaszkodni - mintak, es nem szabvanyok vagy szabalyok - de otletet meriteni beloluk mindenkepp erdemes. Azt pedig, hogy objektum orientalt python programozast milyen konyvbol tudnal tanulni, arrol vegkepp fogalmam nincs, de nagyon sok nyilt forrasu python project van, aminek a kodjabol nagyon sokat lehet tanulni, illetve majd igyekszem kezdobb cikkeket is irni.

      Remeljuk olyasvalaki is olvassa majd ezt, aki tud konyvet ajanlani :)

    • AntiText says:

      Most éppen az alábbiakat olvasom és használhatónak tűnnek:

      1. Gérard Swinnen: Tanuljunk meg programozni Python nyelven. bz2-be tömöritve elérhető itt: http://python.free-h.net/spip.php?article4

      A http://pythonlib.pergamen.hu/ lapon és a http://python.free-h.net lapon sok egyéb mellet:

      1. Bevezetés a Pythonba példákkal elérhető itt: http://python.free-h.net/spip.php?article3

      2. Illetve ezt is érdemes olvasgatni: http://pythonlib.pergamen.hu/download/tut.pdf

  2. Gábor says:

    Köszi és oop ügyileg tudnál ajánlani valamit ami ehhez az egészhez szükséges?

    • RePa says:

      Sajnos en nem vagyok valami nagy konyvolvaso, az egytemen tanultakon kivul leginkabb blogpostokbol, illetve opensource projectek nezegetesevel tanultam meg, amit tudok.

      Remelem vannak masok, akik tudnak jo szakirodalmat ajanlani (slink?), illetve ha mar az OOP alapjaival tisztaban vagy, akkor erdemes atfutni a tervezesi mintakat (design patterns), amikrol szinten bizonyara van sok jo konyv, de attekinteshez jo a wikipedia cikk is.

Szólj hozzá