2012-03-02 5 views
5

मेरे पास एक कक्षा है जिसमें मानक पायथन सिंगलटन फॉर्म है जिसका उपयोग मैं करता हूं। यह एक सिंगल वैल्यू भी करता है, लेकिन प्रत्येक इंस्टेंस में इसे इटिट करने के बजाए, जब मैं सिंगलटन हैंडलिंग करता हूं तो इसे __new__() में लगाता हूं। क्या यह करने के लिए यह पाइथोनिक तरीका है? यदि नहीं, तो मैं और कैसे कर सकता हूं?क्या यह __new__ में काम करने के लिए एक 'मूल पाप' है? यदि हां, तो सिंगलेट्स के लिए एक बार इनिट को कैसे संभालना सबसे अच्छा है?

class Foo(object): 
    _inst = None 
    def __new__(cls, val): 
     if Foo._inst is None: 
      Foo._inst = super(Foo, self).__new__(cls) 
      Foo._inst.val = val 
     return Foo._inst 

यह स्पष्ट रूप से सरलीकृत रूप है। मैंने तक प्रतीक्षा करने के लिए Foo._inst को एक सिंगलटन के लिए एक बार चलने के लिए सेट करने के लिए उपयोग किया है, लेकिन यह एक बहुप्रचारित स्थिति में सिंक्रनाइज़ेशन त्रुटियों के लिए परिपक्व लगता है। ऐसी परिस्थितियों के लिए जहां मौजूदा मान में कोई भी मान नहीं है जो __init__() फिर से चलाया जाता है, __init__() में init डालने में कोई हानि नहीं है, सिवाय इसके कि आप कोड चला रहे हैं जो प्रभावी रूप से कुछ भी नहीं करता है जब आपको आवश्यकता नहीं होती है, लेकिन अक्सर भ्रष्ट राज्य मूल्य होते हैं जिन्हें मैं ओवरराइट नहीं करना चाहता हूं। मुझे पता है कि सिंगलेट भी बुराई हैं, लेकिन कुछ बार, वे सबसे अच्छे समाधान हैं (जैसे विशेष उपयोग प्रकारों को परिभाषित करना, मैं is के साथ जांच करने में सक्षम होना चाहता हूं)।

ऐसा लगता है कि मैं सबसे अच्छा समाधान कर सकता हूं, लेकिन मुझे __new__() में उदाहरण मानों को गंदे शुरू करना लगता है। क्या किसी के पास इस तरीके को बेहतर तरीके से संभालने के बारे में विचार है?

+7

सिंगलेट्स का उपयोग करने के लिए यह एक मूल पाप है। वे ग्लोबल्स को अतिरिक्त दोष और अजीब प्रतिबंध जोड़ने का एक तरीका हैं। यदि आपको वैश्विक स्थिति की आवश्यकता है, तो ग्लोबल्स का उपयोग करें, लेकिन उनसे बचने के लिए बेहतर प्रयास करें। कभी भी सिंगलेट का उपयोग न करें। –

+1

@ स्वेन मार्नच मैं अकेले सिंगलटन और ग्लोबल्स से बचने के लिए क्या कर सकता हूं, लेकिन ऐसे कई उदाहरण हैं जहां वे सबसे अच्छे समाधान हैं। उदाहरण के लिए, मैंने अभी एक टर्नरी कक्षा लागू की है, लेकिन मुझे प्रत्येक प्रकार के एक से अधिक उदाहरण (सही, गलत, अज्ञात) की आवश्यकता नहीं है, और वास्तव में, प्रत्येक में से केवल एक को मुझे इसे बूल की तरह उपयोग करने की अनुमति देता है काम करने के लिए ऑपरेटर है। इसलिए जब सिंगलटन से बचा जाना है, तो उन्हें सबसे अच्छा विकल्प होने पर उनका उपयोग करने के अच्छे तरीके हो सकते हैं। –

+3

क्या आपका मतलब "कार्डिनल पाप" नहीं है? –

उत्तर

2

पहले प्रश्न का उत्तर देने के लिए: सिंगलटन का उपयोग पायथन में अक्सर नहीं किया जाता है क्योंकि वास्तव में इसकी आवश्यकता नहीं होती है।

दूसरा जवाब देने के लिए: आपको लगता है कि आप वास्तव में उन्हें जरूरत है, थोड़ा क्लीनर, समान पैटर्न "बोर्ग" जो कभी कभी प्रयोग किया जाता है कहा जाता है, देखें: the Borg design pattern तुम सिर्फ उदाहरण हैं और डॉन के बीच कुछ विशेषताओं को साझा करने की जरूरत है 'टी पूर्ण विकसित सिंगलटन (जो एक बार instantiated जा सकता है) की जरूरत है तो आप बस वर्ग तो जैसे विशेषताओं का उपयोग कर सकते हैं:

class Foo(object): 
    val = ... 

    def __init__(self): 
     ... 

तो सभी उदाहरणों "वैल" विशेषता का एक ही मूल्य को साझा करेंगे।

+0

मैंने अपना उदाहरण oversimplified हो सकता है ... अधिक आम उदाहरण में, मेरे पास वास्तव में कक्षा में संग्रहीत एक आवृत्ति शब्दकोश है, और मेरा लक्ष्य विशेष प्रकार के उदाहरणों की संख्या को सीमित करना है। तो आप 'Foo._insts = {1: Foo (1), 2: Foo (2), 3: Foo (3)} 'के साथ समाप्त होते हैं। फिर आप 3 मानों के लिए एक अद्वितीय प्रकार के साथ समाप्त होते हैं, लेकिन प्रति मान केवल एक उदाहरण। –

+0

पायथन एक ऐसी भाषा नहीं है जो किसी भी चीज के लिए इतनी सख्त अनुमति देती है, यानी आप शायद 100% अपने आप को सुरक्षित रखने में सक्षम नहीं होंगे। हालांकि यदि आप इसके लिए एक सभ्य इंटरफ़ेस बनाना चाहते हैं, तो दो कक्षाएं क्यों न बनाएं, जिनमें से एक रजिस्टर है और सीमा पार नहीं होने पर अन्य के उदाहरण बनाने की अनुमति देता है? यानी Foo() और FooRegistry() और एक विधि है FooRegistry.create() जो Foo उदाहरण देता है यदि सीमा पार नहीं हुई है या अन्यथा अपवाद उठाता है या स्थिति को संभालने के लिए कुछ और करता है ...? – kgr

+0

कक्षाओं की एक और परत एक ही चीज़ करने के लिए क्यों जोड़ती है? यह FooRegistery और Foo को एक ही कक्षा में ध्वस्त करता है जहां FooRegistery.create() Foo में बदल जाता है .__ नया __()। –

1

सिंगलेट बनाने के लिए कोई बेहतर तरीका नहीं है। यदि आप इसके लिए जा रहे हैं (और तीन मूल्यवान तर्क एकमात्र उदाहरण के बारे में है, तो मैं सोच सकता हूं कि यह कहां समझता है), तो आप इसे वैसे ही कर सकते हैं।

+0

हाँ, यह [पायथन ट्रिबूल] (http://www.grantjenks.com/docs/tribool/) डेटा प्रकार के लिए मेरा उपयोग केस था। – GrantJ

4

आप हमेशा सिंगलेट के बजाय वैश्विक चर का उपयोग कर सकते हैं। तीन अलग-अलग उदाहरणों के साथ एक वर्ग के लिए उदाहरण:

class _Ternary(object): 
    """Internal class. Don't instantiate!""" 
    def __init__(self, value): 
     self.value = value 

ternary_0 = _Ternary(0) 
ternary_1 = _Ternary(1) 
ternary_2 = _Ternary(2) 

def ternary(value): 
    """Factory function to request a "ternary" instance.""" 
    return {0: ternary_0, 1: ternary_1: 2: ternary_2}[value] 

यह सीधी-सपाट है और एकमात्र के दर्द से बचने होगा।

+0

लेकिन इस पैटर्न के साथ आप ऑपरेटर-अधिभार काम को अच्छी तरह से कैसे बनाते हैं? उदाहरण के लिए, आप 'ternary_1 - ternary_1' वापसी' ternary_0' कैसे करेंगे? – GrantJ

+0

@GrantJ: मुझे समस्या समझ में नहीं आ रही है। 'टर्नरी' कक्षा पर '__sub__' विधि को परिभाषित करें? –

संबंधित मुद्दे

 संबंधित मुद्दे