මෙටාක්ලාස් එකක් භාවිතා කරන්න
මම ක්රමය # 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'
Logger
class 'your_module.Logger'
Logger()
Logger
Singleton
__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 වෙතින් උපුටා ගැනීමකි :
දැන්, එක් ආකාරයක සිංගල්ටන් එකක් තිබේ. ළඟා විය හැකි සියලුම වස්තූන් වෙනස් කළ නොහැකි තනි ඒකයකි. සෑම වස්තුවක්ම නිශ්චල බැවින් සිංගල්ටන්ට ගෝලීය තත්වයක් නැත. නමුත් මේ ආකාරයේ සිංගල්ටන් විකෘති එකක් බවට පත් කිරීම එතරම් පහසු ය, එය ඉතා ලිස්සන සුළු බෑවුමකි. එමනිසා, මම මෙම සිංගල්ටන්වලටද විරුද්ධ වෙමි, ඒවා නරක නිසා නොව, ඔවුන්ට නරක වීමට ඉතා පහසු නිසාය. .
අර්ධ පිළිගත හැකි අනෙක් වර්ගයේ සිංගල්ටන් යනු ඔබේ කේතය ක්රියාත්මක කිරීමට බල නොපායි, ඒවාට “අතුරු ආබාධ” නොමැත. ලොග් වීම කදිම නිදසුනකි. එය සිංගල්ටන් සහ ගෝලීය රාජ්යය සමඟ පටවා ඇත. එය පිළිගත හැකි ය (එය ඔබට හානියක් නොවන පරිදි) ඔබගේ යෙදුම ලබා දී ඇති ලොගර් සක්රීය කර තිබුණත් නැතත් වෙනස් ලෙස හැසිරෙන්නේ නැත. මෙහි ඇති තොරතුරු එක් ආකාරයකින් ගලා යයි: ඔබගේ යෙදුමෙන් ලොගර් වෙත. ඔබගේ යෙදුමට ලොගර්ස් වෙතින් කිසිදු තොරතුරක් ගලා නොයන බැවින්, ලොගර් පවා ගෝලීය තත්වයේ පවතී. යම් දෙයක් ලොග් වී ඇති බව ඔබේ පරීක්ෂණයෙන් තහවුරු කර ගැනීමට අවශ්ය නම් ඔබ තවමත් ඔබේ ලොගර් එන්නත් කළ යුතුය, නමුත් සාමාන්යයෙන් ලොගර්ස් රාජ්යයෙන් පිරී තිබියදීත් හානිකර නොවේ.
foo.x
හෝ ඔබFoo.x
ඒ වෙනුවට අවධාරනය කරන්නේ නම්Foo().x
); පන්ති ලක්ෂණ සහ ස්ථිතික / පන්ති ක්රම භාවිතා කරන්න (Foo.x
).