2011-03-01 22 views
10

पायथन में, मौजूदा बराबर अपरिवर्तनीय वस्तुओं का पुन: उपयोग करना संभव है (जैसे str के लिए किया जाता है)? क्या यह __hash__ विधि को परिभाषित करके किया जा सकता है, या क्या इसे अधिक जटिल उपायों की आवश्यकता है?अपरिवर्तनीय वस्तुओं के लिए मौजूदा वस्तुओं का पुन: उपयोग करें?

+0

+1 दिलचस्प प्रश्न। मुझे तारों के बारे में पता है कि प्रक्रिया को "इंटर्निंग" कहा जाता है लेकिन मुझे यकीन नहीं है कि यह शब्द विशेष रूप से तारों के लिए है, क्योंकि मैंने कभी भी इंटर्निंग करने वाले किसी और चीज के बारे में कभी नहीं सुना है। – Davy8

+0

अक्सर हैश फ़ंक्शन ऑब्जेक्ट के पते के रूप में लागू किया जाएगा, इसलिए आपको चिकन/अंडे की समस्या मिलती है; हैश तब तक बराबर नहीं होगा जब तक कि आप पहले से ही तय नहीं कर लेते हैं कि ऑब्जेक्ट समान हैं। –

उत्तर

11

यदि आप कक्षा कन्स्ट्रक्टर के माध्यम से बनाना चाहते हैं और इसे पहले बनाए गए ऑब्जेक्ट को वापस करना चाहते हैं तो आपको __new__ विधि प्रदान करने की आवश्यकता होगी (क्योंकि जब तक आप __init__ पर ऑब्जेक्ट पहले ही बना चुके हैं)।

यहाँ एक सरल उदाहरण है - अगर आरंभ करने के लिए इस्तेमाल मूल्य से पहले तो देखा गया है पूर्व में बने वस्तु बनाया एक नया एक के बजाय लौटा दिया जाता है:

class Cached(object): 
    """Simple example of immutable object reuse.""" 

    def __init__(self, i): 
     self.i = i 

    def __new__(cls, i, _cache={}): 
     try: 
      return _cache[i] 
     except KeyError: 
      # you must call __new__ on the base class 
      x = super(Cached, cls).__new__(cls) 
      x.__init__(i) 
      _cache[i] = x 
      return x 

ध्यान दें कि यह उदाहरण के लिए आप कुछ भी उपयोग कर सकते हैं जब तक यह हैशबल है तब तक शुरू करने के लिए। और सिर्फ यह दिखाने के लिए कि वास्तव में वस्तुओं का पुन: उपयोग किया जा रहा है:

>>> a = Cached(100) 
>>> b = Cached(200) 
>>> c = Cached(100) 
>>> a is b 
False 
>>> a is c 
True 
+3

धन्यवाद।यह काम करता है, मैंने उपयोग किया जाने वाला एकमात्र अंतर ऐसा था: 'वर्ग ए (ऑब्जेक्ट): _cached = {} <फिर बाकी> '। कारण मैंने ऐसा इसलिए किया क्योंकि मुझे लगता है कि फ़ंक्शन पैरामीटर में तत्काल ऑब्जेक्ट्स भ्रमित हो सकते हैं, क्योंकि कुछ मामलों में लोगों को यह नहीं पता हो सकता है कि इसे केवल एक बार तत्काल किया जा रहा है, और यह उस ऑब्जेक्ट को उस सभी ऑब्जेक्ट्स के लिए संदर्भित करता है समारोह। – Abbafei

+0

@Abafei: हाँ, आपका परिवर्तन एक अच्छा है। बहुत से लोग म्यूटेबल डिफॉल्ट तर्क से बचने के लिए पसंद करते हैं क्योंकि वे अक्सर दूसरों को भ्रमित करते हैं - मैं काफी समझदार नहीं हूं :) –

+2

ध्यान दें कि '__init__' को दो बार * कहा जाएगा * जब कैश मिस हो और एक बार कैश हिट हो । आपको कई कन्स्ट्रक्टर कॉल के खिलाफ स्पष्ट रूप से सुरक्षा करने की आवश्यकता है उदा। '__init__' के अंत में ध्वज सेट करें और ध्वज सेट होने पर तत्काल वापस आएं। – kynan

3

मेरा मानना ​​है कि आपको पहले से बनाए गए उदाहरणों के एक नियम {args: object} रखना होगा, फिर उस शब्दकोश को चेक करने के लिए '__new__ विधि' को ओवरराइड करना होगा, और प्रासंगिक ऑब्जेक्ट को पहले से मौजूद होने पर वापस कर देना होगा। ध्यान दें कि मैंने इस विचार को लागू या परीक्षण नहीं किया है। बेशक, सी स्तर पर तारों को संभाला जाता है।

+0

हां यह काम करता है - मैंने पहले इस विधि का सफलतापूर्वक उपयोग किया है। अगर कल कोई मुझे मारता है तो मैं कल कुछ उदाहरण कोड पोस्ट कर सकता हूं। –

3

इस के लिए दो 'सॉफ्टवेयर इंजीनियरिंग' समाधान हैं जिन्हें पायथन के निम्न स्तर के ज्ञान की आवश्यकता नहीं है। वे निम्नलिखित परिदृश्यों में लागू होते हैं:

पहला परिदृश्य: यदि आपकी रचना के पैरामीटर के साथ निर्मित होते हैं तो आपकी कक्षा के ऑब्जेक्ट 'बराबर' होते हैं, और समानता निर्माण के बाद समय के साथ नहीं बदलेगी। समाधान: उपयोग एक कारखाने कि निर्माता मापदंडों hashses:

class MyClass: 
    def __init__(self, someint, someotherint): 
    self.a = someint 
    self.b = someotherint 

cachedict = { } 
def construct_myobject(someint, someotherint): 
    if (someint, someotherint) not in cachedict: 
    cachedict[(someint, someotherint)] = MyClass(someint, someotherint) 
    return cachedict[(someint, someotherint)] 

यह दृष्टिकोण अनिवार्य रूप से अलग इनपुट जोड़ी प्रति एक अद्वितीय वस्तु को अपने वर्ग के उदाहरण सीमित करता है। स्पष्ट दोष भी हैं: सभी प्रकार आसानी से हर्षनीय नहीं हैं और इसी तरह।

दूसरा परिदृश्य: आपकी कक्षा के ऑब्जेक्ट्स उत्परिवर्तनीय हैं और समय के साथ उनकी 'समानता' बदल सकती है। समाधान: बराबर उदाहरणों में से एक वर्ग के स्तर के रजिस्ट्री को परिभाषित:। जबकि तीसरे पैरामीटर शामिल नहीं किए जाते

class MyClass: 
    registry = { } 

    def __init__(self, someint, someotherint, third): 
    MyClass.registry[id(self)] = (someint, someotherint) 
    self.someint = someint 
    self.someotherint = someotherint 
    self.third = third 

    def __eq__(self, other): 
    return MyClass.registry[id(self)] == MyClass.registry[id(other)] 

    def update(self, someint, someotherint): 
    MyClass.registry[id(self)] = (someint, someotherint) 

इस उदाहरण में, एक ही someint, someotherint जोड़ी के साथ वस्तुओं, बराबर हैं चाल मापदंडों रखना है सिंक में registry में। update के विकल्प के रूप में, आप अपनी कक्षा के लिए getattr और setattr ओवरराइड कर सकते हैं; इससे यह सुनिश्चित होगा कि foo.someint = y कोई भी असाइनमेंट आपके क्लास-स्तरीय शब्दकोश के साथ समन्वयित रखा जाएगा। उदाहरण here देखें।

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