2011-12-13 18 views
5

में उप-वर्ग सेट करते समय __repr__ को परिभाषित करना, मैं नीचे दिए गए कोड का उपयोग करके पाइथन में set ऑब्जेक्ट को उपclass करने का प्रयास कर रहा हूं, लेकिन मैं उपयोग करने के लिए __repr__ की समझदार परिभाषा नहीं कर सकता।पाइथन

class Alpha(set): 
    def __init__(self, name, s=()): 
     super(Alpha, self).__init__(s) 
     self.name = name 

मैं इस तरह से है कि मैं निम्नलिखित उत्पादन प्राप्त कर सकते हैं में __repr__ परिभाषित करने के लिए करना चाहते हैं:

>>> Alpha('Salem', (1,2,3)) 
Alpha('Salem', set([1, 2, 3])) 

हालांकि, अगर मैं __repr__ ओवरराइड नहीं करते, उत्पादन मैं name पर ध्यान नहीं देता मूल्य ...

>>> Alpha('Salem', (1,2,3)) 
Alpha([1, 2, 3]) 

... जबकि अगर मैं __repr__ ओवरराइड करते हैं, मैं नहीं समूह में मान के लिए सीधी पहुँच एक नया सेट उदाहरण बनाकर बिना प्राप्त कर सकते हैं:

यह काम करता है, लेकिन __repr__ है कि तब का निपटारा किया जाएगा के लिए एक नया सेट उदाहरण बनाकर मेरे लिए भद्दा और अक्षम लगता है।

क्या इस तरह के वर्ग के लिए __repr__ परिभाषित करने का एक बेहतर तरीका है?

संपादित करें: एक और समाधान जो मेरे साथ हुआ है: मैं स्थानीय रूप से सेट स्टोर कर सकता हूं। यह अन्य विकल्पों की तुलना में थोड़ा साफ दिखता है (__repr__ के प्रत्येक कॉल के लिए कुछ बनाना और नष्ट करना या स्ट्रिंग मैनिपुलेशन के कुछ रूपों का उपयोग करना), लेकिन फिर भी मेरे लिए आदर्श से कम लगता है।

class Alpha(set): 
    def __init__(self, name, s=()): 
     super(Alpha, self).__init__(s) 
     self.name = name 
     self._set = set(s) 
    def __repr__(self): 
     return "%s(%r, %r)" % (self.__class__.__name__, self.name, self._set) 
+5

जिस तरह से आप फोन 'super' लिए, आप अगर subclasses '__init__' को कॉल करने का प्रयास करते हैं तो अनंत रिकर्सन प्राप्त करें। कारण 'सुपर' स्पष्ट रूप से कक्षा लेता है कि यह जानता है कि विधि समाधान आदेश (एमआरओ) में कहां जारी रखना है। 'अल्फा' पास करें (या यदि टैग संकेत के रूप में यह 3.x है, तो बस 'सुपर() 'का उपयोग करें - यह किसी भी तरह से सही चीज करता है)। – delnan

+0

@ डेलनान: डांग। उसके लिए धन्यवाद। और मुझे लगता था कि कक्षा स्पष्ट रूप से निर्दिष्ट करने से बचने में मुझे चालाक था। –

+0

@ डेलनान: किसी कारण से, स्वेन मार्नच ने इस सवाल को पायथन 3.x के रूप में टैग किया। मैं वास्तव में पायथन 2.6 का उपयोग कर रहा हूँ। –

उत्तर

7

मुझे लगता है कि मेरे पास कुछ ऐसा है जो आपको कुछ बेंचमार्क दिखाने के अलावा प्राप्त करता है। वे लगभग सभी समकक्ष हैं हालांकि मुझे यकीन है कि स्मृति उपयोग में कोई अंतर है।

#!/usr/bin/env python 

import time 

class Alpha(set): 
    def __init__(self, name, s=()): 
      super(Alpha, self).__init__(s) 
      self.name = name 
    def __repr__(self): 
      return '%s(%r, set(%r))' % (self.__class__.__name__, 
             self.name, 
             list(self)) 

class Alpha2(set): 
    def __init__(self, name, s=()): 
      super(Alpha2, self).__init__(s) 
      self.name = name 
    def __repr__(self): 
      return '%s(%r, set(%r))' % (self.__class__.__name__, 
             self.name, 
             set(self)) 

class Alpha3(set): 
    def __init__(self, name, s=()): 
      super(Alpha3, self).__init__(s) 
      self.name = name 
    def __repr__(self): 
      rep = super(Alpha3, self).__repr__() 
      rep = rep.replace(self.__class__.__name__, 'set', 1) 
      return '%s(%r, %s)' % (self.__class__.__name__, 
            self.name, 
            rep) 

def timeit(exp, repeat=10000): 
    results = [] 
    for _ in xrange(repeat): 
     start = time.time() 
     exec(exp) 
     end = time.time()-start 
     results.append(end*1000) 
    return sum(results)/len(results) 

if __name__ == "__main__": 
    print "Alpha(): ", timeit("a = Alpha('test', (1,2,3,4,5))") 
    print "Alpha2(): ", timeit("a = Alpha2('test', (1,2,3,4,5))") 
    print "Alpha3(): ", timeit("a = Alpha3('test', (1,2,3,4,5))") 

परिणाम:

अल्फा(): 0,0287627220154

alpha2(): 0,0286467552185

Alpha3(): 0,0285225152969

+0

हां, मैं 'सूची()' के लिए चुनता हूं क्योंकि यह सबसे सरल लगता है, लेकिन स्पष्ट रूप से इससे कोई फर्क नहीं पड़ता। –

+1

मैं शर्त लगाने के लिए तैयार हूं, स्मृति-वार कि पहले और दूसरे कम कुशल हैं क्योंकि वे तत्काल और वस्तुओं को फेंक रहे हैं। लेकिन वास्तव में स्मृति/सीपीयू की जांच किए बिना बस एक धारणा है। तीसरा उदाहरण केवल एक स्ट्रिंग प्राप्त करता है और इसे दोबारा सुधारता है। – jdi

+0

संभवतः। मुझे लगता है कि यह एक प्रश्न है, 'अल्फा 3' की 2 कॉलों की तुलना में 'सेट()' या 'सूची()' तेज है (बेंचमार्क हाँ कह सकता है)। –

2

मुझे ऐसा करने से बेहतर तरीका नहीं मिला। मुझे लगता है कि यह एक सेट फेंकने से बेहतर है हालांकि।

(पायथन 2.x)

>>> class Alpha(set): 
...  def __init__(self, name, s=()): 
...    super(Alpha, self).__init__(s) 
...    self.name = name 
...  def __repr__(self): 
...    return 'Alpha(%r, set(%r))' % (self.name, list(self)) 
... 
>>> Alpha('test', (1, 2)) 
Alpha('test', set([1, 2])) 

या, आप हार्डकोडेड वर्ग के नाम पसंद नहीं है, तो (हालांकि यह वास्तव में कोई फर्क नहीं होना चाहिए)।

>>> class Alpha(set): 
...  def __init__(self, name, s=()): 
...    super(Alpha, self).__init__(s) 
...    self.name = name 
...  def __repr__(self): 
...    return '%s(%r, set(%r))' % (self.__class__.__name__, self.name, list(self)) 
... 
>>> Alpha('test', (1, 2)) 
Alpha('test', set([1, 2])) 
+1

मैं वर्गनाम को हार्डकोड नहीं करता और इसके बजाय 'स्वयं .__ वर्ग __.__ name__' का उपयोग करता हूं (जैसे me_and किया) – gecco

+1

@gecco: व्यक्तिगत वरीयता। मुझे इसे हार्डकोडिंग में बहुत अधिक बिंदु नहीं दिख रहा है (जब तक कि आपके पास कक्षाएं नहीं हैं जो इसे उप-वर्गीकृत करती हैं), खासकर जब कुछ स्थानों को अभी भी इसकी आवश्यकता होती है (सुपर कॉल)। वैसे भी बदलना आसान है। लेकिन मैंने गैर-हार्डकोड संस्करण के साथ-साथ प्रति अनुरोध भी जोड़ा है। –

+1

मैं @ जॉन डी के साथ सहमत हूं। मैं इसे गंभीर के रूप में नहीं देखता जब आपको सुपर() कॉल के लिए क्लास नाम का स्पष्ट रूप से उपयोग करने की आवश्यकता होती है। लेकिन हाँ यह थोड़ा और गतिशील है। – jdi