පයිතන් හි සිංගල්ටන් එකක් නිර්මාණය කිරීම


985

මෙම ප්‍රශ්නය සිංගල්ටන් සැලසුම් රටාව සුදුසු ද නැද්ද යන්න සාකච්ඡා කිරීම සඳහා නොවේ, රටා විරෝධී හෝ ඕනෑම ආගමික යුද්ධයක් සඳහා නොව, මෙම රටාව පයිතන්හි වඩාත්ම පයිතොනික් ආකාරයෙන් ක්‍රියාත්මක කරන්නේ කෙසේද යන්න සාකච්ඡා කිරීම සඳහා ය. මෙම අවස්ථාවෙහිදී මම 'බොහෝ පයිතොනික්' යන්න අර්ථ දක්වන්නේ එය 'අවම විශ්මය ජනක මූලධර්මය' අනුගමනය කරන බවයි .

මට තනි පන්ති බවට පත්වන පන්ති කිහිපයක් තිබේ (මගේ භාවිත අවස්ථාව ලොගර් සඳහා ය, නමුත් මෙය වැදගත් නොවේ). මට සරලවම උරුම කර ගැනීමට හෝ අලංකාර කිරීමට හැකි වූ විට පන්ති කිහිපයක් එකතු කරන ලද ගැම්ප් සමඟ පැටලීමට මා කැමති නැත.

හොඳම ක්‍රම:


ක්රමය 1: සැරසිලි කරුවෙක්

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

වාසි

  • සැරසිලි කරන්නන් බහු උරුමයට වඩා බොහෝ විට බුද්ධිමත් ආකාරයකින් ආකලන වේ.

අවාසි

  • MyClass () භාවිතයෙන් නිර්මාණය කරන ලද වස්තූන් සත්‍ය සිංගල්ටන් වස්තූන් වන අතර, MyClass යනු aa ශ්‍රිතයක් මිස පන්තියක් නොවේ, එබැවින් ඔබට එයින් පන්ති ක්‍රම ඇමතිය නොහැක. එසේම ඒ සඳහා m = MyClass(); n = MyClass(); o = type(n)();එවකටm == n && m != o && n != o

ක්රමය 2: මූලික පන්තියක්

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

වාසි

  • එය සැබෑ පන්තියකි

අවාසි

  • බහු උරුමය - ඉග්! __new__දෙවන පාදක පන්තියක උරුමය අතරතුර නැවත ලිවිය හැකිද? යමෙකුට අවශ්‍ය ප්‍රමාණයට වඩා සිතිය යුතුය.

ක්රමය 3: මෙටාක්ලාස්

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

වාසි

  • එය සැබෑ පන්තියකි
  • ස්වයංක්‍රීයව ඉන්ද්‍රජාලිකව උරුමය ආවරණය කරයි
  • __metaclass__එහි නිසි අරමුණ සඳහා භාවිතා කරයි (සහ ඒ පිළිබඳව මා දැනුවත් කළේය)

අවාසි

  • එහි තව තියනවද?

ක්රමය 4: සැරසිලි කරුවා එකම නමින් පන්තියක් නැවත ලබා දෙයි

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

වාසි

  • එය සැබෑ පන්තියකි
  • ස්වයංක්‍රීයව ඉන්ද්‍රජාලිකව උරුමය ආවරණය කරයි

අවාසි

  • සෑම නව පංතියක්ම නිර්මාණය කිරීම සඳහා පොදු කාර්යයක් නැද්ද? මෙන්න අපි තනි පන්තියක් සෑදීමට කැමති සෑම පන්තියක් සඳහාම පන්ති දෙකක් නිර්මාණය කරමු. මගේ කාරණයේදී මෙය හොඳ වුවත්, මෙය පරිමාණයෙන් සිදු නොවනු ඇතැයි මම සිතමි. ඇත්ත වශයෙන්ම මෙම රටාව පරිමාණය කිරීම පහසු නොවන්නේද යන්න පිළිබඳව විවාදයක් තිබේ ...
  • _sealedගුණාංගයේ කාරණය කුමක්ද?
  • එකම පන්තියේ ක්‍රම භාවිතා කරමින් මූලික පංතිවල ඇමතුම් ලබා ගත නොහැක super(). මෙයින් අදහස් කරන්නේ ඔබට අභිරුචිකරණය __new__කළ නොහැකි අතර ඔබට ඇමතිය යුතු පන්තියක් උපවර්ග කළ නොහැකි බවයි __init__.

ක්රමය 5: මොඩියුලයක්

මොඩියුල ගොනුවක් singleton.py

වාසි

  • සරල දේට වඩා සංකීර්ණයි

අවාසි


13
තවත් ක්‍රම තුනක්: ඒ වෙනුවට මොඩියුලයක් භාවිතා කරන්න (බොහෝ විට - පොදුවේ, මම සිතන්නේ - මෙය පයිතන් සඳහා වඩාත් සුදුසු රටාවක් වන නමුත් එය ඔබ එය කරන්නේ කුමක් ද යන්න මත රඳා පවතී); තනි අවස්ථාවක් කර ඒ වෙනුවට ගනුදෙනු කරන්න ( foo.xහෝ ඔබ Foo.xඒ වෙනුවට අවධාරනය කරන්නේ නම් Foo().x); පන්ති ලක්ෂණ සහ ස්ථිතික / පන්ති ක්‍රම භාවිතා කරන්න ( Foo.x).
ක්‍රිස් මෝගන්

10
H ක්‍රිස්මෝර්ගන්: ඔබ පන්ති / ස්ථිතික ක්‍රම පමණක් භාවිතා කිරීමට යන්නේ නම්, පංතියක් සෑදීමට කරදර නොවන්න.
කැට් ප්ලස් ප්ලස්

2
At කැට්: බලපෑම සමාන ය, කෙසේ වෙතත් ගෝලීය විචල්‍යයක් නිර්මාණය කිරීමට හේතු ඕනෑම දෙයක් ගැන විය හැකිය. යමෙක් සිංගල්ටන් එකක් නිර්මාණය කරන්නේ ඇයි? ඔබට ඇසිය යුතු නම් ඔබ මෙහි නොසිටිය යුතුය. මෙම පැහැදිලිකම වඩාත් පයිතොනික් පමණක් නොව නඩත්තු කිරීම වඩාත් සරල කරයි. ඔව්, සිංගල්ටන් යනු ග්ලෝබල් සඳහා සින්ටැක්ටික් සීනි, නමුත් පංති යනු අපිරිසිදු දේවල් සමූහයක් සඳහා සින්ටැක්ටික් සීනි වන අතර ඒවා නොමැතිව ඔබ සැමවිටම වඩා හොඳ යැයි කිසිවෙකු ඔබට කියනු ඇතැයි මම නොසිතමි.
theheadofabroom

15
Ig බිග්ඒල්: ඔබ ඒවා ක්‍රියාත්මක කළත් සිංගල්ටන් පයිතොනික් නොවේ . ඒවා දෝෂ සහිත මෝස්තරයක ලකුණකි.
කැට් ප්ලස් ප්ලස්

9
සං sign ා-විරෝධී මනෝභාවය යනු භාණ්ඩ නිකායේ වැඩසටහන් එහි නරකම අවස්ථාවයි. මිනිසුන්ට ඇහුම්කන් දීම හා සමානයි (ඇත්ත වශයෙන්ම කියවීමට කරදර වන්නේ ස්වල්ප දෙනෙක්) "ගොටෝ ප්‍රකාශය හානිකර යැයි සැලකේ" සහ ගොටෝස් සන්දර්භය නොසලකා නරක කේතයේ ලකුණක් යැයි සිතයි.
හෙජාස්මන්

Answers:


684

මෙටාක්ලාස් එකක් භාවිතා කරන්න

මම ක්‍රමය # 2 නිර්දේශ කරමි , නමුත් ඔබ මූලික පන්තියකට වඩා මෙටැක්ලාස් භාවිතා කිරීම වඩා හොඳය . මෙන්න නියැදි ක්‍රියාත්මක කිරීමකි:

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

හෝ පයිතන් 3 හි

class Logger(metaclass=Singleton):
    pass

__init__පංතිය කැඳවන සෑම අවස්ථාවකම ඔබට ධාවනය කිරීමට අවශ්‍ය නම්, එකතු කරන්න

        else:
            cls._instances[cls].__init__(*args, **kwargs)

හි ifප්‍රකාශයට Singleton.__call__.

මෙටාක්ලාස් ගැන වචන කිහිපයක්. මෙටාක්ලාස් යනු පන්තියක පන්තියකි ; එනම්, පන්තියක් යනු එහි මෙටාක්ලාස් හි නිදසුනකි . පයිතන් හි ඇති වස්තුවක මෙටාක්ලාස් ඔබ සොයා ගනී type(obj). සාමාන්‍ය නව විලාසිතාවේ පන්ති වර්ග typeවේ. (එකම) උදාහරණය Loggerවර්ගයට සමාන වන පරිදි ඉහත කේතයේ වර්ගය වේ. ඔබ සමඟ logger අමතන විට , Python පළමු වන metaclass අසයි , , කළ යුතු දේ, උදාහරණයක් නිර්මාණය පෙර empted වීමට ඉඩ. මෙම ක්රියාවලිය Python ඇමතීම මගින් සිදු කරන්නේ කුමක් ද පන්ති ඉල්ලා හා සමාන වේ ඔයා කරන්නේ එය ගතිලක්ෂණ එක අදාල විට .class 'your_module.Singleton'Loggerclass 'your_module.Logger'Logger()LoggerSingleton__getattr__myclass.attribute

පංතියක අර්ථ දැක්වීම යන්නෙන් අදහස් කරන්නේ කුමක්ද සහ එම අර්ථ දැක්වීම ක්‍රියාත්මක කරන්නේ කෙසේද යන්න මෙටාක්ලාස් විසින් මූලික වශයෙන් තීරණය කරයි . උදාහරණයක් ලෙස http://code.activestate.com/recipes/498149/ බලන්න , structමෙටාක්ලාස් භාවිතයෙන් පයිතන් හි සී-ස්ටයිල් ප්‍රතිනිර්මාණය කරයි. නූල් මෙටාක්ලාස් සඳහා සමහර (කොන්ක්‍රීට්) භාවිත අවස්ථා මොනවාද? සමහර උදාහරණ ද සපයයි, ඒවා සාමාන්‍යයෙන් ප්‍රකාශන වැඩසටහන්කරණයට සම්බන්ධ බව පෙනේ, විශේෂයෙන් ORM වල භාවිතා වන පරිදි.

මෙම තත්වය තුළ, ඔබ ඔබේ ක්‍රමය # 2 භාවිතා කරන්නේ නම් සහ උප පංතියක් __new__ක්‍රමයක් නිර්වචනය කරන්නේ නම් , ඔබ අමතන සෑම අවස්ථාවකමSubClassOfSingleton() එය ක්‍රියාත්මක වේ - මන්ද ගබඩා කළ අවස්ථාව නැවත ලබා දෙන ක්‍රමය ඇමතීමට එය වගකිව යුතු බැවිනි. මෙටාක්ලාස් සමඟ, එකම අවස්ථාව නිර්මාණය කළ විට එය එක් වරක් පමණක් කැඳවනු ලැබේ. පංතිය ඇමතීම යන්නෙන් අදහස් කරන්නේ කුමක්ද යන්න අභිරුචිකරණය කිරීමට ඔබට අවශ්‍යය , එය එහි වර්ගය අනුව තීරණය වේ.

පොදුවේ ගත් කල, සිංගල්ටන් එකක් ක්‍රියාත්මක කිරීම සඳහා මෙටැක්ලාස් භාවිතා කිරීම අර්ථවත් කරයි . සිංගල්ටන් එකක් විශේෂ වන්නේ එක් වරක් පමණක් නිර්මාණය කර ඇති අතර මෙටාක්ලාස් යනු ඔබ පන්තියක් නිර්මාණය කිරීම රිසිකරණය කරන ආකාරයයි . ඔබට වෙනත් ආකාරවලින් සිංගල්ටන් පංති අර්ථ දැක්වීම් අභිරුචිකරණය කිරීමට අවශ්‍ය නම් මෙටාක්ලාස් භාවිතා කිරීමෙන් ඔබට වැඩි පාලනයක් ලබා දේ .

ඔබේ සිංගල්ටන් වලට බහු උරුමයක් අවශ්‍ය නොවනු ඇත (මෙටාක්ලාස් මූලික පංතියක් නොවන නිසා), නමුත් බහු උරුමයක් භාවිතා කරන සාදන ලද පන්තියේ උප පංති සඳහා, නැවත අර්ථ දක්වන මෙටාක්ලාස් එකක් සහිත පළමු / වම්පස එක සිංගල්ටන් පන්තිය බව ඔබ සහතික කළ යුතුය. __call__මෙය ගැටලුවක් වීමට බොහෝ දුරට ඉඩ නැත. නිදර්ශන ආ ict ාව නිදර්ශන නාම අවකාශයේ නොමැති බැවින් එය අහම්බෙන් එය නැවත ලියන්නේ නැත.

සිංගල්ටන් රටාව "තනි වගකීම් මූලධර්මය" උල්ලං that නය කරන බව ඔබට අසන්නට ලැබේ - සෑම පන්තියක්ම කළ යුත්තේ එක් දෙයක් පමණි . ඒ ආකාරයෙන් ඔබට තවත් දෙයක් වෙනස් කිරීමට අවශ්‍ය නම් කේතය කරන එක් දෙයක් අවුල් කිරීම ගැන කරදර විය යුතු නැත, මන්ද ඒවා වෙනම හා සංවෘත වී ඇති බැවිනි. මෙටාක්ලාස් ක්‍රියාත්මක කිරීම මෙම පරීක්ෂණය සමත් වේ. රටාව බලාත්මක කිරීම සඳහා මෙටාක්ලාස් වගකිව යුතු අතර නිර්මාණය කරන ලද පංතිය සහ උප පංති ඒවා තනි බොත්තම් බව දැන සිටිය යුතු නොවේ . "MyClass යනු aa ශ්‍රිතයක් මිස පන්තියක් නොවේ, එබැවින් ඔබට එයින් පන්ති ක්‍රම ඇමතිය නොහැක" යනුවෙන් ඔබ සඳහන් කළ පරිදි # 1 ක්‍රමය මෙම පරීක්ෂණය අසමත් වේ.

පයිතන් 2 සහ 3 අනුකූල අනුවාදය

පයිතන් 2 සහ 3 යන දෙකින්ම ක්‍රියාත්මක වන දෙයක් ලිවීමට තරමක් සංකීර්ණ යෝජනා ක්‍රමයක් භාවිතා කිරීම අවශ්‍ය වේ. මෙටාක්ලාස් සාමාන්‍යයෙන් වර්ගයේ උප පංති වන බැවින් type, ධාවන වේලාවේදී අතරමැදි පාදක පන්තියක් එහි මෙටාක්ලාස් ලෙස ගතිකව නිර්මාණය කිරීමට එකක් භාවිතා කළ හැකි අතර පසුව එය පොදු පාදක පන්තියේ මූලික පන්තිය ලෙස භාවිතා කළ හැකිය Singleton. ඊළඟට නිදර්ශනය කර ඇති පරිදි එය පැහැදිලි කිරීමට වඩා පැහැදිලි කිරීම දුෂ්කර ය:

# works in Python 2 & 3
class _Singleton(type):
    """ A metaclass that creates a Singleton base class when called. """
    _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 Singleton(_Singleton('SingletonMeta', (object,), {})): pass

class Logger(Singleton):
    pass

මෙම ප්‍රවේශයේ උත්ප‍්‍රාසාත්මක අංගයක් වන්නේ එය මෙටා ක්ලාස් ක්රියාත්මක කිරීම සඳහා උප පංති භාවිතා කිරීමයි. විය හැකි එක් වාසියක් නම්, පිරිසිදු මෙටැක්ලාස් එකක් මෙන් නොව, isinstance(inst, Singleton)නැවත පැමිණීමයි True.

නිවැරදි කිරීම්

වෙනත් මාතෘකාවක් මත, ඔබ මෙය දැනටමත් දැක ඇති නමුත් ඔබේ මුල් ලිපියේ මූලික පන්ති ක්‍රියාත්මක කිරීම වැරදිය. _instancesකළ යුතු අවශ්යතා පන්ති මත නමෙන්ම , ඔබ භාවිතා කිරීමට අවශ්ය super()නම් හෝ ඔබ recursing , සහ __new__ඔබ කිරීමට ඇති බව ස්ථිතික ක්රමය සත්ය වන පන්තියෙන් සමත් සැබෑ පන්ති ලෙස නොව, පන්ති ක්රමය නිර්මාණය කර නැත විට එය තවමත් ලෙස හැඳින්වේ. මෙටාක්ලාස් ක්‍රියාත්මක කිරීම සඳහා මේ සියල්ල සත්‍ය වනු ඇත.

class Singleton(object):
  _instances = {}
  def __new__(class_, *args, **kwargs):
    if class_ not in class_._instances:
        class_._instances[class_] = super(Singleton, class_).__new__(class_, *args, **kwargs)
    return class_._instances[class_]

class MyClass(Singleton):
  pass

c = MyClass()

සැරසිලි කරන්නා නැවත පන්තියක්

මම මුලින් අදහස් දැක්වීමක් කළ නමුත් එය දිගු වැඩියි, එබැවින් මම මෙය මෙහි එක් කරමි. ක්රමය # 4 අනෙක් සැරසිලි අනුවාදයට වඩා හොඳයි, නමුත් එය සිංගල්ටන් සඳහා අවශ්යතාවයට වඩා කේතයක් වන අතර එය කරන්නේ කුමක්ද යන්න පැහැදිලි නැත.

ප්‍රධාන ගැටලු පැන නගින්නේ පන්තියේම මූලික පන්තිය වීමයි. පළමුවෙන්ම, පංතියක් එහි __class__ගුණාංගයේ පමණක් පවතින එකම නමක් සහිත සමාන පන්තියක උප පංතියක් වීම අමුතු දෙයක් නොවේද? මෙය ද ඔබ අර්ථ නොහැකි බව මින් අදහස් වේ ඔවුන්ගේ පදනම පන්තිය මත එම නම භාවිත කරන ක්රමය කතා කරන ඕනෑම ක්රම සමග super()ඔවුන් recurse ඇත නිසා. මෙයින් අදහස් කරන්නේ ඔබේ පන්තියට අභිරුචිකරණය __new__කළ නොහැකි __init__අතර ඒවා කැඳවිය යුතු පන්ති වලින් ව්‍යුත්පන්න කළ නොහැකි බවයි.

සිංගල්ටන් රටාව භාවිතා කළ යුත්තේ කවදාද?

ඔබේ භාවිත නඩුව සිංගල්ටන් එකක් භාවිතා කිරීමට අවශ්‍ය හොඳම උදාහරණයකි . ඔබ එක් අදහස් දැක්වීමකදී "මට ලොග් වීම සැමවිටම සිංගල්ටන් සඳහා ස්වාභාවික අපේක්ෂකයෙකු ලෙස පෙනේ." ඔබ ඇත්තෙන්ම හරි .

සිංගල්ටන් නරක යැයි මිනිසුන් පවසන විට, වඩාත් පොදු හේතුව වන්නේ ඒවා ව්‍යාජ හවුල් තත්වයකි . ගෝලීය විචල්‍යයන් සහ ඉහළ මට්ටමේ මොඩියුල ආනයනයන් පැහැදිලිව බෙදාගත් තත්වයක් වන අතර, අවට ඇති වෙනත් වස්තූන් සාමාන්‍යයෙන් ක්ෂණිකව ක්‍රියාත්මක වේ. මෙය හොඳ කරුණක් වන අතර, ව්‍යතිරේක දෙකක් ඇත.

පළමු හා විවිධ ස්ථානවල සඳහන් වන්නේ තනි තල නියත වන විට ය . ගෝලීය නියතයන්, විශේෂයෙන් එනූම්ස් භාවිතය පුළුල් ලෙස පිළිගෙන ඇති අතර, එය බුද්ධිමත් යැයි සලකනු ලබන්නේ කුමක් වුවත්, පරිශීලකයින්ට වෙනත් පරිශීලකයෙකු සඳහා ඒවා අවුල් කළ නොහැකි බැවිනි . නියත සිංගල්ටන් සඳහා මෙය සමානව සත්‍ය වේ.

අඩුවෙන් සඳහන් වන දෙවන ව්‍යතිරේකය ප්‍රතිවිරුද්ධ දෙයකි - සිංගල්ටන් යනු දත්ත බේසමක් පමණක් වන විට දත්ත ප්‍රභවයක් නොවේ (සෘජුව හෝ වක්‍රව). ලොගර්වරුන්ට සිංගල්ටන් සඳහා “ස්වාභාවික” භාවිතයක් ලෙස හැඟෙන්නේ මේ නිසා ය. විවිධ පරිශීලකයින් වෙනත් පරිශීලකයින් සැලකිලිමත් වන ආකාරයෙන් ල gers ු-සටහන් වෙනස් නොකරන බැවින්, සැබවින්ම හවුල් තත්වයක් නොමැත . මෙය සිංගල්ටන් රටාවට එරෙහි මූලික තර්කය ප්‍රතික්ෂේප කරන අතර, එම කාර්යය සඳහා ඔවුන් භාවිතා කිරීමේ පහසුව නිසා ඔවුන් සාධාරණ තේරීමක් කරයි .

මෙන්න http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html වෙතින් උපුටා ගැනීමකි :

දැන්, එක් ආකාරයක සිංගල්ටන් එකක් තිබේ. ළඟා විය හැකි සියලුම වස්තූන් වෙනස් කළ නොහැකි තනි ඒකයකි. සෑම වස්තුවක්ම නිශ්චල බැවින් සිංගල්ටන්ට ගෝලීය තත්වයක් නැත. නමුත් මේ ආකාරයේ සිංගල්ටන් විකෘති එකක් බවට පත් කිරීම එතරම් පහසු ය, එය ඉතා ලිස්සන සුළු බෑවුමකි. එමනිසා, මම මෙම සිංගල්ටන්වලටද විරුද්ධ වෙමි, ඒවා නරක නිසා නොව, ඔවුන්ට නරක වීමට ඉතා පහසු නිසාය. .

අර්ධ පිළිගත හැකි අනෙක් වර්ගයේ සිංගල්ටන් යනු ඔබේ කේතය ක්‍රියාත්මක කිරීමට බල නොපායි, ඒවාට “අතුරු ආබාධ” නොමැත. ලොග් වීම කදිම නිදසුනකි. එය සිංගල්ටන් සහ ගෝලීය රාජ්‍යය සමඟ පටවා ඇත. එය පිළිගත හැකි ය (එය ඔබට හානියක් නොවන පරිදි) ඔබගේ යෙදුම ලබා දී ඇති ලොගර් සක්‍රීය කර තිබුණත් නැතත් වෙනස් ලෙස හැසිරෙන්නේ නැත. මෙහි ඇති තොරතුරු එක් ආකාරයකින් ගලා යයි: ඔබගේ යෙදුමෙන් ලොගර් වෙත. ඔබගේ යෙදුමට ලොගර්ස් වෙතින් කිසිදු තොරතුරක් ගලා නොයන බැවින්, ලොගර් පවා ගෝලීය තත්වයේ පවතී. යම් දෙයක් ලොග් වී ඇති බව ඔබේ පරීක්ෂණයෙන් තහවුරු කර ගැනීමට අවශ්‍ය නම් ඔබ තවමත් ඔබේ ලොගර් එන්නත් කළ යුතුය, නමුත් සාමාන්‍යයෙන් ලොගර්ස් රාජ්‍යයෙන් පිරී තිබියදීත් හානිකර නොවේ.


5
නැත, සිංගල්ටන් කිසි විටෙකත් යහපත් නොවේ. ලොග් වීම ගෝලීය වීම සඳහා හොඳ අපේක්ෂකයෙකු විය හැකිය (ඔවුන් තරම් භයානක), නමුත් නිසැකවම තනි පුද්ගලයෙක් නොවේ.
කැට් ප්ලස් ප්ලස්

12
Googletesting.blogspot.com/2008/08/… බලන්න . එය සාමාන්‍යයෙන් ප්‍රති-සිංගල්ටන් ය (හොඳ හේතුවක් නිසා) නමුත් අතුරු ආබාධවලින් තොර වෙනස් කළ නොහැකි සිංගල්ටන් සහ සිංගල්ටන් එකම ගැටළු ඇති නොවීමට හේතුව පිළිබඳ හොඳ පැහැදිලි කිරීමක් ඇත, ඔබ පරිස්සම් නම්. මම මගේ පෝස්ට් අවසානයේ එය ටිකක් උපුටා දක්වන්නෙමි.
agf

4
සිංගල්ටන් සමඟ ඇති මගේ ගැටලුව වන්නේ “එක් අවස්ථාවක් පමණක්” යන මෝඩ පරිශ්‍රයයි. එය සහ නූල් ආරක්ෂණ ගැටළු ටොන්. සහ යැපීම් සැඟවීම. ග්ලෝබල් නරකයි, සහ සිංගල්ටන් යනු තවත් ගැටලු ඇති ගෝලීය ය.
කැට් ප්ලස් ප්ලස්

4
At කැට් සිංගල්ටන් සඳහා ඉතා හොඳ භාවිතයන් ඇත. දෘඩාංග මොඩියුලවල කම්මැලි ක්ෂණිකකරණය (විශේෂයෙන් තනි නූල් යෙදුම්වල) ඒවායින් එකකි (නමුත් නූල් ආරක්ෂිත තනි බොත්තම් ද පවතී).
පෝල් මන්ටා

3
Ac මෙටාක්ලාස් එකක ඇල්කොට් __new__යනු පන්තිය අළුත් වූ විට - එය නිර්වචනය කළ විට මිස උදාහරණය අළුත් වූ විට නොවේ . පංතිය ( MyClass()) ලෙස හැඳින්වීම යනු ඔබට අභිබවා යාමට අවශ්‍ය මෙහෙයුම මිස පන්තියේ අර්ථ දැක්වීම නොවේ. පයිතන් ක්‍රියා කරන ආකාරය ඔබට සැබවින්ම තේරුම් ගැනීමට අවශ්‍ය නම්, ඔබට කළ හැකි හොඳම දේ (එය දිගටම භාවිතා කිරීම හැර) docs.python.org/reference/datamodel.html කියවන්න . මෙටාක්ලාස් පිළිබඳ හොඳ සඳහනක් වන්නේ eli.thegreenplace.net/2011/08/14/python-metaclasses-by-example . සිංගල්ටන් පිළිබඳ හොඳ ලිපියක් වන්නේ මෙම පිළිතුරට මා සම්බන්ධ කළ ගූගල් බ්ලොග් අඩවියයි.
agf

96
class Foo(object):
     pass

some_global_variable = Foo()

මොඩියුල ආනයනය කරනු ලබන්නේ එක් වරක් පමණි, අනෙක් සියල්ල අධිතක්සේරු කරයි. සිංගල්ටන් භාවිතා නොකර ග්ලෝබල් භාවිතා නොකිරීමට උත්සාහ කරන්න.


18
"සිංගල්ටන් භාවිතා නොකරන්න" යැයි ඔබ කීවේ ඇයි? ඕනෑම හේතුවක්?
ඇල්කොට්

3
සිංගල්ටන් අච්චාරු දැමිය යුතු නම් මෙය ක්‍රියා නොකරනු ඇත. ඔබ දුන් උදාහරණය භාවිතා කරමින්:s = some_global_variable; str = pickle.dumps(s); s1 = pickle.loads(str); print s is s1; # False
divbyzero

5
ivdividebyzero: isදර්ශක සමානාත්මතාවය සඳහා ක්‍රියාකරු පරීක්ෂා කරයි. මා පුදුමයට පත් වනු ඇත --- එය දෝෂයක් ලෙස හඳුන්වන තැනට --- pickle.loadsඅළුතින් සාදන ලද වස්තුවක් ගැන සඳහන් කරනවාට වඩා කලින් පැවති වස්තුවකට යොමු කිරීමක් ආපසු ලබා දුන්නේ නම් . මේ අනුව, s is s1මොඩියුලයන් තනි බොත්තම් ලෙස භාවිතා කිරීමේ යෝග්‍යතාවය ගැන ඔබට කිසිවක් නොකියන්නේ දැයි පරීක්ෂා කිරීම .
ජොනස් කොල්කර්

1
@ JonasKölker pickle.loads()අවස්ථා සඳහා, දැනටමත් ඒක කරන්න උදා: කරන්නේ boolහා NoneType. pickle.loads(pickle.dumps(False)) is Falseඅස්වැන්නTrue
ඩෑන් පැසාරෝ

2
@ ලියෝ-ද-මැනික්: සාධාරණ ලක්ෂ්‍යය; කෙසේ වෙතත්, එය පයිතන් වස්තූන් අභ්‍යන්තරයේ අතුරු effect ලයක් පමණක් Trueවන Falseඅතර None, පිටුපස ඇති කේතය සමඟ කිසිදු සම්බන්ධයක් නැත pickle.loads. එසේම, කියවීමට පමණක් ඇති වස්තු සඳහා පමණක් කිරීම ආරක්ෂිතයි. නම් pickle.loadsමේ වන විට පවතින සැඳහුම ආපසු විය modifiable වස්තුව-එවැනි මොඩියුලය-දෝෂය වනු ලෙස. (මම මගේ ව්යංගාර්ථවත් සිටගෙන ඉන්නේ dividebyzero කේතය උදාහරණයක් කිසිවක් ඔප්පු නොවන බව එසේ.)
Jonas Kölker

68

මොඩියුලයක් භාවිතා කරන්න. එය ආනයනය කරනු ලබන්නේ එක් වරක් පමණි. එහි ඇති සමහර ගෝලීය විචල්‍යයන් නිර්වචනය කරන්න - ඒවා සිංගල්ටන්ගේ 'ගුණාංග' වනු ඇත. සමහර කාර්යයන් එක් කරන්න - සිංගල්ටන්ගේ 'ක්‍රම'.


11
ඉතින් ඔබ අවසන් කරන්නේ ... පන්තියක් නොවේ. ඔබට එය පංතියක් ලෙස භාවිතා කළ නොහැක, ඔබට වෙනත් පංති මත පදනම් විය නොහැක, ඔබ ආනයන සින්ටැක්ස් භාවිතා කරයි, හදිසියේම ඔබට OOP හි සියලු ප්‍රතිලාභ අහිමි වේ ...
theheadofabroom

17
ඔබට වෙනත් පංති පදනම් කර ගත හැකි නම්, එය තනි පුද්ගලයකු නොවිය හැකිය. ඔබට ව්‍යුත්පන්න පංතියෙන් එකක් පමණක් නොව මූලික පංතියෙන් එකක් ද නිර්මාණය කළ හැකිය, නමුත් ව්‍යුත්පන්න පංතිය ද පාදමේ සාමාජිකයෙකි, ඔබට පාදම දෙකක් තිබේ, ඔබ භාවිතා කළ යුත්තේ කුමන එකද?
SingleNegationElimination

මෙය මොඩියුල හරහා ක්‍රියා නොකරයි. මගේ "ප්‍රධාන" මොඩියුලය තුළ මම අගයක් නියම කළෙමි. මම එය වෙනත් මොඩියුලයක සහ එහි ශුන්‍යයේ සඳහන් කරමි. සැනසුම් සුසුමක්.
පෝල් කෙන්ජෝරා

1
APaulKenjora ඔබේ කේතයේ දෝෂයක් තිබිය යුතුය. ඔබ මොඩියුලයක ගෝලීය විචල්‍යයක් අර්ථ දක්වන්නේ නම්, ඔබ එය වෙනත් මොඩියුලයකින් ප්‍රවේශ කරන විට එහි වටිනාකම තිබිය යුතුය.
warvariuc

1
ඔබට හැකි import * from base_module... හෙඩ්ෆොබ්රූම් ගැන නැවත සිතා බලන්න! hahahah
polvoazul

29

ඔබට කිසි විටෙකත් පයිතන් හි තනි පුද්ගලයකු අවශ්‍ය නොවේ. මොඩියුලයක ඔබගේ සියලු දත්ත සහ ක්‍රියාකාරකම් නිර්වචනය කරන්න, එවිට ඔබට තථ්‍ය තනිකඩ පුද්ගලයෙක් සිටී.

ඔබට සැබවින්ම සිංගල්ටන් පංතියක් තිබිය යුතු නම් මම සමඟ යන්නෙමි:

class My_Singleton(object):
    def foo(self):
        pass

my_singleton = My_Singleton()

භාවිතා කිරීමට:

from mysingleton import my_singleton
my_singleton.foo()

mysingleton.py යනු My_Singleton යන්න අර්ථ දක්වා ඇති ඔබේ ගොනු නාමයයි. මෙය ක්‍රියාත්මක වන්නේ පළමු වරට ගොනුවක් ආනයනය කිරීමෙන් පසුව, පයිතන් කේතය නැවත ක්‍රියාත්මක නොකරන බැවිනි.


4
බොහෝ දුරට ඇත්ත, නමුත් සමහර විට එය ප්රමාණවත් නොවේ. උදා: DEBUG මට්ටමින් බොහෝ පංතිවල තොරතුරු ඇතුළත් කිරීමේ අවශ්‍යතාවයක් සහිත ව්‍යාපෘතියක් මා සතුව ඇත. එම පන්ති ක්ෂණිකව ආරම්භ කිරීමට පෙර පරිශීලකයා විසින් නියම කරන ලද ල ging ු -සටහන් මට්ටම සැකසීම සඳහා මට විධාන රේඛා විකල්පයන් විග්‍රහ කිරීමට අවශ්‍යය . මොඩියුල මට්ටමේ ක්ෂණිකකරණයන් එය ගැටළු සහගත කරයි. CLI සැකසීම සිදු වන තුරු එම පංති සියල්ලම ආනයනය නොකිරීමට මට යෙදුම ප්‍රවේශමෙන් සැකසීමට හැකිය, නමුත් මගේ යෙදුමේ ස්වාභාවික ව්‍යුහය "සිංගල්ටන් නරක" යැයි පිළිපැදීමට වඩා වැදගත් වේ. තරමක් පිරිසිදුයි.
CryingCyclops

my_singleton ඇලවීමේදී ඔබ ඔබේ කේතය පරීක්ෂා කරන්නේ නම්, එය කළ හැකිද? මෙම my_singleton වෙනත් මොඩියුලයකින් ස්ථාපනය කළ හැකි බැවින්.
නවීන්

Ave නවීන් - my_singleton යනු තනි වස්තුවකි. ඔබ එය "පැච්" කළහොත් එම වෙනස අනෙකුත් සියලුම මොඩියුලවල පවා අනාගත යොමු කිරීම් වලට බලපායි.
ඇලන් ඩයික්

16

මෙන්න ඔබ වෙනුවෙන් එක් ලයිනර් එකක්:

singleton = lambda c: c()

මෙන්න ඔබ එය භාවිතා කරන ආකාරය:

@singleton
class wat(object):
    def __init__(self): self.x = 1
    def get_x(self): return self.x

assert wat.get_x() == 1

ඔබේ වස්තුව උනන්දුවෙන් ක්ෂණිකව ලබා ගනී. මෙය ඔබට අවශ්‍ය දේ හෝ නොවිය හැකිය.


5
-1. මෙය ඉතා නරක හා මෝඩය. ඔබ වස්තුවක් ලෙස භාවිතා කිරීමට පන්තියක් නිර්වචනය නොකරයි. ඉතා අවලස්සන type(wat)හෝ නොවී ඔබට තවදුරටත් පන්තියට පිවිසිය නොහැක wat.__class__. ඔබට මෙය සැබවින්ම සාක්ෂාත් කර ගැනීමට අවශ්‍ය නම්, පන්තිය වඩා හොඳින් අර්ථ දක්වා එය වහාම ක්‍රියාත්මක කරන්න, සැරසිලි කරුවා සමඟ පටලවා ගැනීමට අවශ්‍ය නැත.
0xc0de

2
සිංගල්ටන් පන්තියක් භාවිතා කිරීම ඔබ දැනගත යුත්තේ ඇයි?
සිංගල්ටන්

1
එය සිංගල්ටන් රටාව නොවේ , එබැවින් IMO ශ්‍රිතය වෙනස් ලෙස නම් කළ යුතුය.
ජින්ජර් ප්ලස් ප්ලස්

8
විකිපීඩියා: "සිංගල්ටන් රටාව යනු එක් වස්තුවකට පන්තියක් ක්ෂණිකව සීමා කරන නිර්මාණ රටාවකි". මගේ විසඳුම එයම කරන බව මම කියමි. හරි, මම හිතන්නේ කෙනෙකුට කරන්න පුළුවන් wat2 = type(wat)(), නමුත් මේ පයිතන්, අපි හැමෝම වැඩිහිටියන්ට එකඟයි. ඔබට හැකි නොවේ සහතිකයක් එකම එක උදාහරණයක් වනු ඇත, නමුත් ඔබ ඔවුන් ඉන්නේ යහපත්, upstanding ජනතාව වැනි ඔවුන්ට අනතුරු ඇඟවීමක් ජනතාව දෙවන එක් කරන්න නම්, එය කැත බලන්න බව සහතික කළ හැකි සහ-නම්. මට නැති වී ඇත්තේ කුමක්ද?
ජොනස් කොල්කර්

7

Stack පමාණය ප්රශ්නය පරීක්ෂා Python දී singletons නිර්වචනය කිරීමට සරල, අලංකාර ක්රමයක් නැද්ද? විසඳුම් කිහිපයක් සමඟ.

පයිතන් හි සැලසුම් රටා පිළිබඳ ඇලෙක්ස් මාටෙලිගේ කතා නැරඹීමට මම තරයේ නිර්දේශ කරමි: 1 වන කොටස සහ 2 වන කොටස . විශේෂයෙන්, 1 වන කොටසේදී ඔහු සිංගල්ටන් / හවුල් රාජ්‍ය වස්තු ගැන කතා කරයි.


2
මෙය ඇත්ත වශයෙන්ම මගේ ප්‍රශ්නයට පිළිතුරක් නොවන අතර, ඔබ පෙන්වා දෙන සම්පත් ඉතා ප්‍රයෝජනවත් වේ. මම ඔබට +1
theheadofabroom

4

මෙන්න මගේම සිංගල්ටන් ක්‍රියාත්මක කිරීම. ඔබ කළ යුත්තේ පන්තිය අලංකාර කිරීම පමණි; සිංගල්ටන් ලබා ගැනීම සඳහා, ඔබ එම Instanceක්‍රමය භාවිතා කළ යුතුය. මෙන්න උදාහරණයක්:

   @Singleton
   class Foo:
       def __init__(self):
           print 'Foo created'

   f = Foo() # Error, this isn't how you get the instance of a singleton

   f = Foo.Instance() # Good. Being explicit is in line with the Python Zen
   g = Foo.Instance() # Returns already created instance

   print f is g # True

මෙන්න කේතය:

class Singleton:
    """
    A non-thread-safe helper class to ease implementing singletons.
    This should be used as a decorator -- not a metaclass -- to the
    class that should be a singleton.

    The decorated class can define one `__init__` function that
    takes only the `self` argument. Other than that, there are
    no restrictions that apply to the decorated class.

    To get the singleton instance, use the `Instance` method. Trying
    to use `__call__` will result in a `TypeError` being raised.

    Limitations: The decorated class cannot be inherited from.

    """

    def __init__(self, decorated):
        self._decorated = decorated

    def Instance(self):
        """
        Returns the singleton instance. Upon its first call, it creates a
        new instance of the decorated class and calls its `__init__` method.
        On all subsequent calls, the already created instance is returned.

        """
        try:
            return self._instance
        except AttributeError:
            self._instance = self._decorated()
            return self._instance

    def __call__(self):
        raise TypeError('Singletons must be accessed through `Instance()`.')

    def __instancecheck__(self, inst):
        return isinstance(inst, self._decorated)

2
එය සත්‍ය සිංගල්ටන් නොවේ. සත්‍ය සිංගල්ටන් SingletonList = Singleton(list).Instance(); print(SingletonList is type(SingletonList)())මුද්‍රණය කළ යුතුය True; ඔබේ කේත මුද්‍රණයන් සමඟFalse
ජින්ජර් ප්ලස්ප්ලස්

@GingerPlusPlus සීමාවන් කිහිපයක් ගැන මම දැන සිටියෙමි, නමුත් ඔබ පෙන්වා දුන් සීමාව ගැන නොවේ. එය සඳහන් කිරීම ගැන ස්තූතියි. අවාසනාවකට මෙන්, මේ සඳහා විසඳුමක් ගැන සිහින් වීමට මට මේ මොහොතේ වෙලාවක් නැත.
පෝල් මාන්ටා

2

3 වන ක්‍රමය ඉතා පිළිවෙලට ඇති බව පෙනේ, නමුත් ඔබේ වැඩසටහන පයිතන් 2 සහ පයිතන් 3 යන දෙකින්ම ක්‍රියාත්මක වීමට අවශ්‍ය නම් එය ක්‍රියා නොකරයි. පයිතන් අනුවාදය සඳහා වන පරීක්ෂණ සමඟ වෙනම ප්‍රභේද ආරක්ෂා කිරීම පවා අසාර්ථක වේ, මන්ද පයිතන් 3 අනුවාදය පයිතන් 2 හි සින්ටැක්ස් දෝෂයක් ලබා දෙයි.

මයික් වොට්කින්ස්ට ස්තූතියි: http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/ . ඔබට මෙම වැඩසටහන පයිතන් 2 සහ පයිතන් 3 යන දෙඅංශයෙන්ම ක්‍රියාත්මක වීමට අවශ්‍ය නම්, ඔබ එවැනි දෙයක් කළ යුතුය:

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]

MC = Singleton('MC', (object), {})

class MyClass(MC):
    pass    # Code for the class implementation

පැවරුමේ ඇති 'වස්තුව' 'බේස් ක්ලාස්' සමඟ ප්‍රතිස්ථාපනය කළ යුතු යැයි මම සිතමි, නමුත් මම එය උත්සාහ කර නැත (මම නිදර්ශනය කර ඇති පරිදි කේතය උත්සාහ කර ඇත).


නියත වශයෙන්ම මෙය මෙටාක්ලාස් එකක් නොවේ - පයිතන් 3 හි ඔබ විසින් මයික්ලාස් තැනීම සඳහා මෙටැක්ලාස් එකක් භාවිතා කිරීමclass MyClass(metaclass=Singleton)
හෙඩ්ඩොබබ්රූම්

මෙම mikewatkins.ca ලින්ක් (ඵලදායී) කඩා ඇත.
පීටර් මෝර්ටෙන්සන්

2

මම මගේ වළල්ලට විසි කරන්නම් එය සරල සැරසිලි කරුවෙකි.

from abc import ABC

def singleton(real_cls):

    class SingletonFactory(ABC):

        instance = None

        def __new__(cls, *args, **kwargs):
            if not cls.instance:
                cls.instance = real_cls(*args, **kwargs)
            return cls.instance

    SingletonFactory.register(real_cls)
    return SingletonFactory

# Usage
@singleton
class YourClass:
    ...  # Your normal implementation, no special requirements.

ප්‍රතිලාභ මම හිතන්නේ එයට වෙනත් විසඳුම් කිහිපයක් තිබේ:

  • එය පැහැදිලි හා සංක්ෂිප්ත ය (මගේ ඇසට; ඩී).
  • එහි ක්‍රියාව මුළුමනින්ම ආවරණය කර ඇත. ක්‍රියාත්මක කිරීම පිළිබඳ එක දෙයක්වත් වෙනස් කිරීමට ඔබට අවශ්‍ය නැතYourClass . ඔබේ පන්තිය සඳහා මෙටැක්ලාස් භාවිතා කිරීම අවශ්‍ය නොවීම මෙයට ඇතුළත් වේ (ඉහත මෙටාක්ලාස් කර්මාන්ත ශාලාව මත ඇති බව සලකන්න, “සැබෑ” පන්තිය නොවේ).
  • එය කිසිවක් වඳුරන් ඇල්ලීම මත රඳා නොපවතී.
  • එය අමතන්නන්ට විනිවිද පෙනෙන ය:
    • අමතන්නන් තවමත් සරලව ආනයනය කරයි YourClass , එය පංතියක් සේ පෙනේ (එය එසේ නිසා), ඔවුන් එය සාමාන්‍යයෙන් භාවිතා කරයි. කර්මාන්තශාලා කාර්යයකට ඇමතුම් අනුගත කිරීමට අවශ්‍ය නැත.
    • කුමක්ද YourClass()instantiates තවමත් සැබෑ උදාහරණයක් වේ YourClassඔබ යම් ආකාරයක නැහැ ප්රොක්සි, එසේ බව නිසා ඇතිවන අතුරු ආබාධ අවස්ථාවක් නැහැ ක්රියාත්මක.
    • isinstance(instance, YourClass) ඒ හා සමාන මෙහෙයුම් තවමත් අපේක්ෂිත පරිදි ක්‍රියාත්මක වේ (මෙම බිට් එකට abc අවශ්‍ය වුවද පයිතන් <2.6 වළක්වයි).

එක් අවාසියක් මට සිදු වේ: සැබෑ පන්තියේ පන්ති ක්‍රම සහ ස්ථිතික ක්‍රම එය සැඟවී ඇති කර්මාන්තශාලා පන්තිය හරහා විනිවිද පෙනෙන ලෙස ඇමතිය නොහැක. මම මෙය කලාතුරකින් භාවිතා කර ඇති අතර, එම අවශ්‍යතාවයට මා කිසි විටෙකත් නොපැමිණෙන නමුත් කර්මාන්තශාලාවේ අභිරුචි මෙටැක්ලාස් එකක් භාවිතා කිරීමෙන් එය පහසුවෙන් නිවැරදි කළ හැකිය.__getattr__() හැකි අතර එමඟින් සැබෑ පන්තියට සියලු ගුණාංග ආරෝපණය කිරීමට අවශ්‍ය වේ.

ආශ්‍රිත රටාවක් ඇත්ත වශයෙන්ම මම වඩාත් ප්‍රයෝජනවත් යැයි සිතමි (මේ ආකාරයේ දේවල් බොහෝ විට අවශ්‍ය යැයි මම නොකියමි) යනු “අද්විතීය” රටාවකි, එහිදී එකම තර්ක සමඟ පන්තිය ක්ෂණිකව ස්ථාපනය කිරීමෙන් එකම අවස්ථාව නැවත ලබා ගත හැකිය. එනම් “තර්කයකට තනි පුද්ගලයෙක්”. ඉහත සඳහන් ළිඳට අනුවර්තනය වන අතර එය වඩාත් සංක්ෂිප්ත වේ:

def unique(real_cls):

    class UniqueFactory(ABC):

        @functools.lru_cache(None)  # Handy for 3.2+, but use any memoization decorator you like
        def __new__(cls, *args, **kwargs):
            return real_cls(*args, **kwargs)

    UniqueFactory.register(real_cls)
    return UniqueFactory

මේ සියල්ලෙන් එකක්, ඔබට මේ දේවල් වලින් එකක් අවශ්‍ය යැයි ඔබ සිතන්නේ නම්, ඔබ සැබවින්ම මොහොතකට නතර වී ඔබ ඇත්තටම එසේ කරන්නේ දැයි ඔබෙන්ම අසාගත යුතුය යන සාමාන්‍ය උපදෙස් සමඟ මම එකඟ වෙමි. 99% කාලය, යග්නි.


1

හොඳයි, මොඩියුල මට්ටමේ ගෝලීය වීම පිළිබඳ පොදු පයිතොනික් යෝජනාවට එකඟ වීම හැර, මේ ගැන:

def singleton(class_):
    class class_w(class_):
        _instance = None
        def __new__(class2, *args, **kwargs):
            if class_w._instance is None:
                class_w._instance = super(class_w, class2).__new__(class2, *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(object):
    def __init__(self, text):
        print text
    @classmethod
    def name(class_):
        print class_.__name__

x = MyClass(111)
x.name()
y = MyClass(222)
print id(x) == id(y)

ප්‍රතිදානය:

111     # the __init__ is called only on the 1st time
MyClass # the __name__ is preserved
True    # this is actually the same instance

_sealedගුණාංගයේ තේරුම කුමක්ද? මා දකින පරිදි මෙය කිසිවක් නොකරයිද? මෙය හොඳින් ක්‍රියාත්මක නොවිය යුතු යැයි පවසන මේ ගැන යමක් මට විහිළුවක් කරයි ... මම මේ සතිය අගදී සංසන්දනාත්මක පරීක්ෂණ කිහිපයක් පවත්වමි.
theheadofabroom

වගකීම _sealed ඔබගේ init එක් වරක් පමණක් දිව ය; සාමාන්‍ය ශ්‍රිතයට සමාන සැරසිලි කරුවාට වඩා නරක ලෙස ක්‍රියා කළ යුත්තේ මන්දැයි මට කිසිම කරුණක් නොපෙනේ - ශ්‍රිතය ක්‍රියාත්මක වන්නේ පන්තියකට එක් වරක් පමණක් වන අතර නව උරුම පන්තියක් නැවත ලබා දෙයි
ගාඩ්

බී.ටී.ඩබ්ලිව්, ඔබේ සංස්කරණයේ ඉන්ඩෙන්ට්ස් බිඳ දැමිය හැකි ටැබ් අඩංගු වේ ඔබත් කියනවා 'අපි පන්ති 2 ක් නිර්මාණය කරනවා' කියලා - ඔබ අදහස් කරන්නේ අපි 'අමතර පන්ති 1 ක්' නිර්මාණය කරන බව ද?
ගාඩ්

ඔව් එක් අමතර පන්තියක් යනු මා අදහස් කළ දෙයයි. __init__එය ආරම්භ කරන සෑම අවස්ථාවකම ඇමතීමට අවශ්‍ය දෑ ඇතුළත් කිරීමට මම අදහස් කරමි . සරල 'class.method හි ආරම්භ කිරීම'. ඉන්ඩෙන්ටේෂන් සඳහා - ඔබ ටැබ් සහ අවකාශ භාවිතා කර ඇත - මම එය බොහෝමයක් සවි කළෙමි, නමුත් ඔබට එය ලබා ගැනීමට අවශ්‍ය නම් එකක් මග හැරී ඇති බවක් පෙනේ (සංස්කරණ ලොගය පරීක්ෂා කරන්න)
theheadofabroom

re init : ඇත්ත වශයෙන්ම එය ඔබට භාරයි, මම වෙනත් භාෂාවලින් සිංගල්ටන් හැසිරීම අනුකරණය කිරීමට උත්සාහ කළෙමි, එහිදී ඉදිකිරීම්කරු කේතය (එය හරියටම init නොවේ , නමුත් එහි අර්ථයෙන් ඉතා ආසන්නය) කැඳවනු ලබන්නේ ඔබට init වීමට අවශ්‍ය නම් එක් වරක් පමණි සෑම අවස්ථාවකදීම කැඳවනු ලැබේ, _ මුද්‍රා තැබූ නැවත අවකාශ / ටැබ් වෙත ඇති සියලුම යොමු කිරීම් මරා දමන්න - හොඳයි, එවිට මගේ ඉමාක්ස් සවි කිරීම අවශ්‍ය වේ. කෙසේ වෙතත්, ඉහත නිවැරදි කළ අනුවාදය
ගාඩ්

1

කොහොමද මේ:

def singleton(cls):
    instance=cls()
    cls.__new__ = cls.__call__= lambda cls: instance
    cls.__init__ = lambda self: None
    return instance

ඒක පුද්ගලයකු විය යුතු පන්තියක සැරසිලි කරුවෙකු ලෙස එය භාවිතා කරන්න. මෙවැනි:

@singleton
class MySingleton:
    #....

මෙය singleton = lambda c: c()වෙනත් පිළිතුරක සැරසිලි කරුවාට සමාන ය . අනෙක් විසඳුම මෙන්, එකම අවස්ථාව පන්තියේ ( MySingleton) නම ඇත . කෙසේ වෙතත්, මෙම විසඳුම සමඟ ඔබට තවමත් පන්ති වලින් "සැබවින්ම" අවස්ථා නිර්මාණය කළ හැකිය (ඇත්ත වශයෙන්ම එකම අවස්ථාව ලබා ගන්න) MySingleton(). එසේ කිරීමෙන් අමතර අවස්ථා නිර්මාණය කිරීමෙන් එය වළක්වයි type(MySingleton)()(එයද එම අවස්ථාවම ලබා දෙයි).


පංතියක් වස්තුවක් ලෙස භාවිතා කිරීමට ඔබ එය අර්ථ දක්වන්නේ නැත.
0xc0de

1
ඔයාට කෝල් සෑම අවස්ථාවකදීම type(MySingleton)(), MySingleton.__init__()නමින් ලක්වෙයි හා වස්තුව බහු ටයිම්ස් ආරම්භනය ලක්වෙයි; ඔබ ලියන ඒක හදන්න පුළුවන් cls.__init__ = lambda self: passඔබේ singleton. එසේම, ඉක්මවා යාම cls.__call__අර්ථ විරහිත බවක් පෙනේ, හා හානිකර පවා - __call__මෙම සන්දර්භය තුළ අර්ථ දක්වා ඇත්තේ ඔබ අමතන MySingleton(any, list, of, arguments)විට නොව ඔබ අමතන විටය type(MySingleton)(any, list, of, arguments).
ජින්ජර් ප්ලස් ප්ලස්

-ජින්ජර් ප්ලස්ප්ලස්, කරන __init__()විට නැවත ඇමතුමක් ලබා දුන් බව පෙන්වා දීමට ස්තූතියි type(MySingleton)(). ඔබ යෝජනා කළ විසඳුම (එකතු කිරීම cls.__init__ = lambda self: pass) සින්ටැක්ස් දෝෂයක් ලබා දෙයි, මන්ද ලැම්බඩා ප්‍රකාශනයේ අවසාන කොටස ප්‍රකාශයක් නොව ප්‍රකාශයක් විය යුතුය. කෙසේ වෙතත්, cls.__init__ = lambda self: Noneකෘති එකතු කිරීම නිසා මම එය මගේ පිළිතුරට එකතු කළෙමි.
ටොලි

1
-ජින්ජර් ප්ලස් ප්ලස්, භාවිතය සම්බන්ධයෙන් __call__. මම අදහස් දෙකම පත් කිරීම ය type(MySingleton)()සහ MySingleton()ගැණුම්කරුවන්ගේ ආපසු යන්න. ඉතින් ඒක මට ඕන දේ කරනවා. ඔබට MySingleton එක සිංගල්ටන් වර්ගය හෝ සිංගල්ටන් (හෝ දෙකම) ලෙස සිතිය හැකිය.
ටොලි

1
  • යමෙකුට එකම පංතියේ අවස්ථා ගණනක් ලබා ගැනීමට අවශ්‍ය නම්, නමුත් ආග්ස් හෝ ක්වාර්ග්ස් වෙනස් නම් පමණක් කෙනෙකුට තෙවන පාර්ශවීය පයිතන් පැකේජයක් හැන්ඩි ඩෙකොරේටර්ස් (පැකේජය decorators) භාවිතා කළ හැකිය .
  • උදා.
    1. ඔබට පන්ති හැසිරවීමේ serialසන්නිවේදනයක් තිබේ නම්, සහ ඔබට අනුක්‍රමික වරාය තර්කයක් ලෙස යැවීමට අවශ්‍ය අවස්ථාවක් නිර්මාණය කිරීමට නම්, සාම්ප්‍රදායික ප්‍රවේශය සමඟ ක්‍රියා නොකරනු ඇත
    2. ඉහත සඳහන් කළ සැරසිලි කරුවන් භාවිතා කරමින් කෙනෙකුට පන්තියේ විවිධ අවස්ථා නිර්මාණය කළ හැකිය.
    3. එකම ආගන් සඳහා, සැරසිලි කරුවා දැනටමත් නිර්මාණය කර ඇති එම අවස්ථාවම නැවත ලබා දෙනු ඇත.
>>> from decorators import singleton
>>>
>>> @singleton
... class A:
...     def __init__(self, *args, **kwargs):
...         pass
...
>>>
>>> a = A(name='Siddhesh')
>>> b = A(name='Siddhesh', lname='Sathe')
>>> c = A(name='Siddhesh', lname='Sathe')
>>> a is b  # has to be different
False
>>> b is c  # has to be same
True
>>>

0

ටොලිගේ පිළිතුර මත පදනම් වූ කේතය .

#decorator, modyfies new_cls
def _singleton(new_cls):
    instance = new_cls()                                              #2
    def new(cls):
        if isinstance(instance, cls):                                 #4
            return instance
        else:
            raise TypeError("I can only return instance of {}, caller wanted {}".format(new_cls, cls))
    new_cls.__new__  = new                                            #3
    new_cls.__init__ = lambda self: None                              #5
    return new_cls


#decorator, creates new class
def singleton(cls):
    new_cls = type('singleton({})'.format(cls.__name__), (cls,), {} ) #1
    return _singleton(new_cls)


#metaclass
def meta_singleton(name, bases, attrs):
    new_cls = type(name, bases, attrs)                                #1
    return _singleton(new_cls)

පැහැදිලි කිරීම:

  1. නව පන්තියක් සාදන්න, ලබා දීමෙන් උරුම වන්න cls
    ( clsයමෙකුට උදාහරණයක් අවශ්‍ය නම් එය වෙනස් නොවේ singleton(list))

  2. උදාහරණයක් සාදන්න. ඉක්මවා යාමට පෙර __new__එය එතරම් පහසුය.

  3. දැන්, අපි පහසුවෙන් නිදසුනක් නිර්මාණය කළ විට, __new__මොහොතකට පෙර අර්ථ දක්වා ඇති ක්‍රමය භාවිතා කර අභිබවා යයි .
  4. ශ්‍රිතය නැවත පැමිණෙන්නේ instanceඇමතුම්කරු අපේක්ෂා කරන විට පමණිTypeError .
    යමෙකු අලංකාර පන්තියෙන් උරුම කර ගැනීමට උත්සාහ කරන විට කොන්දේසිය සපුරා නැත.

  5. __new__()නිදසුනක් නැවත ලබා දෙන්නේ නම් cls, නව අවස්ථාවෙහි __init__()ක්‍රමය ක්‍රියාත්මක වේ මෙන්__init__(self[, ...]) , එහිදී ස්වයං යනු නව අවස්ථාව වන අතර ඉතිරි තර්ක සම්මත වූ ආකාරයටම වේ __new__().

    instanceදැනටමත් ආරම්භ කර ඇති බැවින් ශ්‍රිතය __init__කිසිවක් නොකර ශ්‍රිතය ප්‍රතිස්ථාපනය කරයි .

එය මාර්ගගතව ක්‍රියාත්මක වන ආකාරය බලන්න


0

එය ෆැබ්ගේ පිළිතුරට තරමක් සමාන නමුත් හරියටම සමාන නොවේ.

මෙම කටය කොන්ත්රාත්තුව අපි ඉදිකිරීමටත් වාර කිහිපයක් කතා කිරීමට හැකි වනු බව අවශ්ය නොවේ. සිංගල්ටන් එකක් එක් වරක් පමණක් නිර්මාණය කළ යුතු බැවින් එය එක් වරක් පමණක් නිර්මාණය කළ යුතු නොවේද? ඉදිකිරීම්කරු “ස්පූෆිං” කිරීම පැහැදිලි බව දුර්වල කරයි.

ඉතින් මගේ යෝජනාව මෙයයි:

class Elvis():
    def __init__(self):
        if hasattr(self.__class__, 'instance'):
            raise Exception()
        self.__class__.instance = self
        # initialisation code...

    @staticmethod
    def the():
        if hasattr(Elvis, 'instance'):
            return Elvis.instance
        return Elvis()

instanceපරිශීලක කේතය මඟින් ඉදිකිරීම්කරු හෝ ක්ෂේත්‍රය භාවිතා කිරීම මෙය ප්‍රතික්ෂේප නොකරයි :

if Elvis() is King.instance:

... ඔබ Elvisතවමත් දන්නවා නම් එය තවම නිර්මාණය වී නැති බවත් එය සිදුවී ඇති බවත් King.

නමුත් එය විශ්වීයව භාවිතා කිරීමට පරිශීලකයින් දිරිමත් කරයි the:

Elvis.the().leave(Building.the())

මෙම සම්පූර්ණ කිරීමට ඔබට ද ඉක්මවා යැමට හැකි __delattr__()උත්සාහයක් මැකීමට ඉදිරිපත් වුවහොත් ව්යතිරේකයක් වැඩි කිරීමට instance, සහ අභිබවා__del__() එවිට එය ව්‍යතිරේකයක් මතු කරයි (වැඩසටහන අවසන් වන බව අප නොදන්නේ නම් ...)

තවදුරටත් වැඩිදියුණු කිරීම්


අදහස් දැක්වීම් සහ සංස්කරණයන් සඳහා උදව් කළ අයට මගේ ස්තූතිය. මම ජයිතන් භාවිතා කරන අතර, මෙය වඩාත් සාමාන්‍යයෙන් ක්‍රියාත්මක විය යුතු අතර නූල් ආරක්ෂිත විය යුතුය.

try:
    # This is jython-specific
    from synchronize import make_synchronized
except ImportError:
    # This should work across different python implementations
    def make_synchronized(func):
        import threading
        func.__lock__ = threading.Lock()

        def synced_func(*args, **kws):
            with func.__lock__:
                return func(*args, **kws)

        return synced_func

class Elvis(object): # NB must be subclass of object to use __new__
    instance = None

    @classmethod
    @make_synchronized
    def __new__(cls, *args, **kwargs):
        if cls.instance is not None:
            raise Exception()
        cls.instance = object.__new__(cls, *args, **kwargs)
        return cls.instance

    def __init__(self):
        pass
        # initialisation code...

    @classmethod
    @make_synchronized
    def the(cls):
        if cls.instance is not None:
            return cls.instance
        return cls()

සටහන් කරුණු:

  1. ඔබ python2.x හි වස්තුවෙන් උප පංතියක් නොකළහොත් ඔබට පැරණි විලාසිතාවේ පන්තියක් ලැබෙනු ඇත, එය භාවිතා නොකරයි __new__
  2. අලංකාර කිරීමේදී __new__ඔබ @classmethod වලින් සරසා ගත යුතුය, නැතහොත් අසීමිත __new__උදාහරණ ක්‍රමයක් වනු ඇත
  3. මෙටාක්ලාස් භාවිතා කිරීමෙන් මෙය වැඩිදියුණු කළ හැකිය, මෙය ඔබට theපන්ති මට්ටමේ දේපලක් සෑදීමට ඉඩ සලසයි , සමහර විට එය නම් කිරීමinstance

මෙය සිංගල්ටන් රටාවේ තරමක් වෙනස් අර්ථකථනයක් වන අතර, එය තවමත් වලංගු බව මට විශ්වාසයි, නමුත් එය __new__ භාවිතා කිරීමට පෙළඹවිය හැකි වුවත් __init__, එය හුදෙක් පන්ති ලක්ෂණ මත ක්‍රියා කරන අතර මෙය කෙටියෙන් දෙවන අවස්ථාව වීම වළක්වයි. මෙය සහ 2 වන ක්‍රමය අතර ඇති වෙනස නම්, එක් වරකට වඩා වැඩි වාර ගණනක් ආරම්භ කිරීමට උත්සාහ කිරීම තනි අවස්ථාව නැවත ලබා දෙන්නේද නැතහොත් ව්‍යතිරේකයක් මතු කරයිද යන්නයි. එක්කෝ සිංගල්ටන් රටාව තෘප්තිමත් කිරීම ගැන මම සතුටු වන අතර, එකක් භාවිතා කිරීමට පහසු වන අතර අනෙක එය සිංගල්ටන් බව වඩාත් පැහැදිලිය.
theheadofabroom

නිසැකවම පන්ති නාමය භාවිතා කිරීම __init__උප වර්ගීකරණය වළක්වයි, නමුත් මෙය පහසු කරවන නමුත් එය අවශ්‍ය නොවේ
theheadofabroom

ස්තූතියි ... ආ ඔව්, ව්‍යතිරේකය විසි වීමට මොහොතකට පෙර දෙවන අවස්ථාව. මම මෙය වෙනස් කර ඇති __init__බැවින් මෙය උපවර්ගයක් විය යුතුය ...
මයික් මීයන්

කූල්, theබොහෝ විට සමාන හේතු නිසා පන්ති ක්‍රමයක් වීමෙන් ප්‍රයෝජන ගත හැකිය
theheadofabroom

ඔව්, ඔබ හරි. එවිට ඔබට සුපර්එල්විස් උප පංතියේ සිංගල්ටන් එකක් සහ (නිදසුනක් ලෙස) ඉමාජිනරි එල්විස් උප පංතියේ සිංගල්ටන් එකක් තිබිය හැකිය ... එවිට ඒවාට සහජීවනය තිබිය හැකිය. අමතර සිතුවිලි බලන්න. කරුණාකර මගේ කේතය වැඩි දියුණු කිරීමට නිදහස් වන්න.
මයික් මීයන්

0

එක් ලයිනර් (මම ආඩම්බර නොවෙමි, නමුත් එය කාර්යය ඉටු කරයි):

class Myclass:
  def __init__(self):
      # do your stuff
      globals()[type(self).__name__] = lambda: self # singletonify

ඔබේ පන්තිය වෙනත් මොඩියුලයකට ආනයනය කර නොමැති තාක් කල් මෙය කාර්යය ඉටු කරයි ...
අරන්-ෆේ

සැබෑ. පංතිය ආරම්භ කිරීමේ පිරිවැය ඔබට ගෙවිය හැකි නම්, මෙය වළක්වා ගැනීම සඳහා පන්ති අර්ථ දැක්වීමෙන් පසු ඔබට මයික්ලාස් () ධාවනය කළ හැකිය.
polvoazul

0

ඔබට සිංගල්ටන් උදාහරණය කම්මැලි ලෙස ආරම්භ කිරීම අවශ්‍ය නොවේ නම්, පහත සඳහන් දෑ පහසු සහ නූල් ආරක්ෂිත විය යුතුය:

class A:
    instance = None
    # Methods and variables of the class/object A follow
A.instance = A()

මෙම ක්‍රමය Aමොඩියුල ආනයනයේදී ආරම්භ කරන ලද සිංගල්ටන් ය.


0

සමහර විට මම සිංගල්ටන් රටාව වැරදියට වටහාගෙන ඇති නමුත් මගේ විසඳුම මෙය සරල හා ප්‍රායෝගික (පයිතොනික්?) ය. මෙම කේතය ඉලක්ක දෙකක් පුරවයි

  1. Fooසෑම තැනකටම ප්‍රවේශ විය හැකි අවස්ථාව (ගෝලීය) කරන්න.
  2. Fooපැවතිය හැක්කේ එක් අවස්ථාවක් පමණි .

මෙය කේතයයි.

#!/usr/bin/env python3

class Foo:
    me = None

    def __init__(self):
        if Foo.me != None:
            raise Exception('Instance of Foo still exists!')

        Foo.me = self


if __name__ == '__main__':
    Foo()
    Foo()

ප්‍රතිදානය

Traceback (most recent call last):
  File "./x.py", line 15, in <module>
    Foo()
  File "./x.py", line 8, in __init__
    raise Exception('Instance of Foo still exists!')
Exception: Instance of Foo still exists!

0

ටික වේලාවක් මේ සමඟ පොරබදමින් මම අවසානයේදී පහත සඳහන් කරුණු ඉදිරිපත් කළෙමි, එවිට වෙනම මොඩියුලයන්ගෙන් ඇමතූ විට වින්‍යාස වස්තුව එක් වරක් පමණක් පටවනු ලැබේ. මෙටාක්ලාස් විසින් ගෝලීය පංතියේ නිදසුනක් බිල්ඩින් ඩික්ට් තුළ ගබඩා කිරීමට ඉඩ සලසයි, වර්තමානයේදී එය නිසි වැඩපිළිවෙලක් ගෝලීයව ගබඩා කිරීමේ පිළිවෙලම ක්‍රමය ලෙස පෙනේ.

import builtins

# -----------------------------------------------------------------------------
# So..... you would expect that a class would be "global" in scope, however
#   when different modules use this,
#   EACH ONE effectively has its own class namespace.  
#   In order to get around this, we use a metaclass to intercept
#   "new" and provide the "truly global metaclass instance" if it already exists

class MetaConfig(type):
    def __new__(cls, name, bases, dct):
        try:
            class_inst = builtins.CONFIG_singleton

        except AttributeError:
            class_inst = super().__new__(cls, name, bases, dct)
            builtins.CONFIG_singleton = class_inst
            class_inst.do_load()

        return class_inst

# -----------------------------------------------------------------------------

class Config(metaclass=MetaConfig):

    config_attr = None

    @classmethod
    def do_load(cls):
        ...<load-cfg-from-file>...

0

ශ්‍රිත ලක්ෂණයක් භාවිතා කිරීම ද ඉතා සරල ය

def f():
    if not hasattr(f, 'value'):
        setattr(f, 'value', singletonvalue)
    return f.value

0

මෙටාක්ලාස් භාවිතයෙන් අලංකාර විසඳුමක් නිර්දේශ කරමි

class Singleton(type): 
    # Inherit from "type" in order to gain access to method __call__
    def __init__(self, *args, **kwargs):
        self.__instance = None # Create a variable to store the object reference
        super().__init__(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            # if the object has not already been created
            self.__instance = super().__call__(*args, **kwargs) # Call the __init__ method of the subclass (Spam) and save the reference
            return self.__instance
        else:
            # if object (Spam) reference already exists; return it
            return self.__instance

class Spam(metaclass=Singleton):
    def __init__(self, x):
        print('Creating Spam')
        self.x = x


if __name__ == '__main__':
    spam = Spam(100)
    spam2 = Spam(200)

ප්‍රතිදානය:

Creating Spam

නිමැවුමෙන් ඔබට පෙනෙන පරිදි, ක්ෂණික වන්නේ එක් වස්තුවක් පමණි


-1

මෙම විසඳුම මා සොයාගත්තේ කොහෙන්දැයි මට මතක නැත, නමුත් එය මගේ පයිතන් නොවන විශේෂ expert දෘෂ්ටි කෝණයෙන් වඩාත්ම 'අලංකාර' බව මට පෙනේ:

class SomeSingleton(dict):
    __instance__ = None
    def __new__(cls, *args,**kwargs):
        if SomeSingleton.__instance__ is None:
            SomeSingleton.__instance__ = dict.__new__(cls)
        return SomeSingleton.__instance__

    def __init__(self):
        pass

    def some_func(self,arg):
        pass

ඇයි මම මේකට කැමති? සැරසිලි කරන්නන් නැත, මෙටා පංති නැත, බහු උරුමයක් නොමැත ... තවද ඔබ එය තවදුරටත් සිංගල්ටන් එකක් වීමට අවශ්‍ය නැති බව තීරණය කරන්නේ නම්, __new__ක්‍රමය මකන්න . මම පයිතන්ට (සහ සාමාන්‍යයෙන් ඕඕපී) අලුත් බැවින් මෙය භයානක ප්‍රවේශයක් වන්නේ මන්දැයි යමෙකු මා වෙත යොමු කරනු ඇතැයි මම අපේක්ෂා කරමි.


2
මෙය භයානක ප්‍රවේශයක් වන්නේ ඇයි? ඔබට වෙනත් සිංගල්ටන් පංතියක් සෑදීමට අවශ්‍ය වූ විට, ඔබ එය පිටපත් කර ඇලවිය යුතුය __new__. ඔබම නැවත කියන්න එපා .
ජින්ජර් ප්ලස් ප්ලස්

ද, ඇයි ඔබේ නව ගනී *argsසහ **kwargs, පසුව ඔවුන් සමඟ කිසිවක් කර නැත? ඒවා dict.__new__මේ ආකාරයට යොමු කරන්න : dict.__new__(cls, *args, **kwargs).
ජින්ජර් ප්ලස් ප්ලස්

__init__පංතිය කැඳවන සෑම අවස්ථාවකම මෙය ක්‍රමය අමතනු ඇත. ඔබේ __init__ක්‍රමය ඇත්ත වශයෙන්ම යමක් කර ඇත්නම් , ඔබට ගැටලුව පෙනෙනු ඇත. ඔබ කරන සෑම අවස්ථාවකම SomeSingleton(), ඔබේ සිංගල්ටන්ගේ තත්වය __init__ක්‍රමවේදය මගින් නැවත සකසනු ලැබේ .
අරන්-ෆේ

-2

සිංගල්ටන් ක්‍රියාත්මක කිරීමේ මගේ ප්‍රියතම ක්‍රමය මෙයයි:

class Test(object):
    obj = None

    def __init__(self):
        if Test.obj is not None:
            raise Exception('A Test Singleton instance already exists')
        # Initialization code here

    @classmethod
    def get_instance(cls):
        if cls.obj is None:
            cls.obj = Test()
        return cls.obj

    @classmethod
    def custom_method(cls):
        obj = cls.get_instance()
        # Custom Code here

1
පංතියේ එක් අවස්ථාවකට වඩා පැවතීමට ඉඩ සලසන බැවින් මෙය තදින්ම තනි පුද්ගලයෙක් නොවේ. වැඩිදියුණු කිරීමක් වනුයේ පන්තිය ආරම්භ කිරීමට නොහැකි වීම සහ සියලු පන්ති ක්‍රම පන්ති ගුණාංග මත ක්‍රියා කිරීමයි
theheadofabroom

-2

මෙම පිළිතුර බොහෝ විට ඔබ සොයන දේ නොවේ. මට සිංගල්ටන් එකක් අවශ්‍ය වූයේ එම වස්තුවට එහි අනන්‍යතාවය ඇත්තේ සංසන්දනය කිරීම සඳහා පමණි. මගේ නඩුවේ එය සෙන්ටිනල් අගයක් ලෙස භාවිතා විය . පිළිතුර ඉතා සරල, ඕනෑම වස්තුවක් සාදන්න mything = object()සහ පයිතන්ගේ ස්වභාවය අනුව, එහි අනන්‍යතාවය ඇත්තේ එම දෙයට පමණි.

#!python
MyNone = object()  # The singleton

for item in my_list:
    if item is MyNone:  # An Example identity comparison
        raise StopIteration

මොඩියුලයන් ඇත්ත වශයෙන්ම කිහිප වතාවක් ආනයනය කළ හැකි බව මම ඉගෙන ගෙන ඇත්තෙමි, එවැනි අවස්ථාවක මෙය දේශීය සිංගල්ටන් එකක් පමණක් වන අතර එය ඇත්ත වශයෙන්ම කිසිදු ධාරිතාවයකින් යුත් සිංගල්ටන් නොවේ.
ThorSummoner

මොඩියුලයක් කිහිප වතාවක් ආනයනය කළ හැකි ආකාරය ගැන ඔබට විස්තර කළ හැකිද? මා දුටු එකම අවස්ථාව වන්නේ මොඩියුලය පටවන අතරතුර ව්‍යතිරේකයක් සිදු වූ විට, පරිශීලකයාට පසුව මොඩියුලය පටවනු ඇත, නමුත් අතුරු ආබාධ දැනටමත් සිදුවී ඇති බැවින් සමහර ක්‍රියා දෙවන වරටත් ක්‍රියාත්මක කළ හැකිය.
sleblanc

මොඩියුල මොඩියුල සම්පූර්ණෙයන් පටවා ඇති විට, මම භාවිතා එය කරන්නේ බවට භාෂණ coercing විසින් හැර වෙනත් මෙම මොඩියුලය නැවත ක්රියාත්මක කිරීමට ක්රමයක් බලන්න එපා, evalහෝ importlib.reload.
sleblanc

-3

මෙම විසඳුම මොඩියුල මට්ටමින් සමහර නාම අවකාශ දූෂණයට හේතු වේ (එකක් පමණක් නොව අර්ථ දැක්වීම් තුනක්), නමුත් මට එය අනුගමනය කිරීම පහසුය.

මම කැමතියි මේ වගේ දෙයක් ලිවීමට (කම්මැලි ආරම්භය), නමුත් අවාසනාවකට පන්ති ඔවුන්ගේම අර්ථ දැක්වීම් අනුව ලබා ගත නොහැක.

# wouldn't it be nice if we could do this?
class Foo(object):
    instance = None

    def __new__(cls):
        if cls.instance is None:
            cls.instance = object()
            cls.instance.__class__ = Foo
        return cls.instance

එය කළ නොහැකි බැවින්, අපට ආරම්භය සහ ස්ථිතික අවස්ථාව බිඳ දැමිය හැකිය

උනන්දුවෙන් ආරම්භ කිරීම:

import random


class FooMaker(object):
    def __init__(self, *args):
        self._count = random.random()
        self._args = args


class Foo(object):
    def __new__(self):
        return foo_instance


foo_instance = FooMaker()
foo_instance.__class__ = Foo

කම්මැලි ආරම්භය:

උනන්දුවෙන් ආරම්භ කිරීම:

import random


class FooMaker(object):
    def __init__(self, *args):
        self._count = random.random()
        self._args = args


class Foo(object):
    def __new__(self):
        global foo_instance
        if foo_instance is None:
            foo_instance = FooMaker()
        return foo_instance


foo_instance = None
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.