2012-10-19 17 views
5

जब पर अनिवार्य रूप से एक कस्टम प्रगणित प्रकार कार्यान्वयन काम कर रहा है, मैं एक स्थिति है जहाँ ऐसा लगता है मैं अलग int और long दोनों से अभी तक लगभग समान उपवर्गों प्राप्त करने के लिए, क्योंकि वे अजगर में अलग वर्गों रहे था में भाग गया। यह बहुत विडंबनापूर्ण लगता है क्योंकि दोनों के उदाहरण आमतौर पर एक दूसरे के लिए उपयोग किए जा सकते हैं क्योंकि अधिकांश भाग के लिए जब भी आवश्यक हो, वे केवल स्वचालित रूप से बनाए जाते हैं।दो अलग संख्यात्मक उपclass (int और long) होने से बचें?

जो मैंने ठीक काम किया है, लेकिन डीआरवाई की भावना में (स्वयं को दोहराएं मत), मैं यह सोचने में मदद नहीं कर सकता कि क्या कोई बेहतर नहीं है, या कम से कम एक संक्षिप्त, इसे पूरा करने का तरीका । लक्ष्य उप-वर्ग उदाहरण होना है जिसका उपयोग हर जगह किया जा सकता है - या जितना संभव हो उतना करीब - उनके आधार वर्गों के उदाहरण हो सकते थे। आदर्श रूप से यह स्वचालित रूप से int() के तरीके के समान ही होना चाहिए जब भी यह पता चलता है कि किसी को आवश्यक है तो long देता है।

यहाँ मेरी वर्तमान कार्यान्वयन है:

class NamedInt(int): 
    """Subclass of type int with a name attribute""" 
    __slots__ = "_name" # also prevents additional attributes from being added 

    def __setattr__(self, name, value): 
     if hasattr(self, name): 
      raise AttributeError(
       "'NamedInt' object attribute %r is read-only" % name) 
     else: 
      raise AttributeError(
       "Cannot add attribute %r to 'NamedInt' object" % name) 

    def __new__(cls, name, value): 
     self = super(NamedInt, NamedInt).__new__(cls, value) 
     # avoid call to this subclass's __setattr__ 
     super(NamedInt, self).__setattr__('_name', name) 
     return self 

    def __str__(self): # override string conversion to be name 
     return self._name 

    __repr__ = __str__ 


class NamedLong(long): 
    """Subclass of type long with a name attribute""" 
    # note: subtypes of variable length 'long' type can't have __slots__ 

    def __setattr__(self, name, value): 
     if hasattr(self, name): 
      raise AttributeError(
       "NamedLong object attribute %r is read-only" % name) 
     else: 
      raise AttributeError(
       "Cannot add attribute %r to 'NamedLong' object" % name) 

    def __new__(cls, name, value): 
     self = super(NamedLong, NamedLong).__new__(cls, value) 
     # avoid call to subclass's __setattr__ 
     super(NamedLong, self).__setattr__('_name', name) 
     return self 

    def __str__(self): 
     return self._name # override string conversion to be name 

    __repr__ = __str__ 

class NamedWholeNumber(object): 
    """Factory class which creates either a NamedInt or NamedLong 
    instance depending on magnitude of its numeric value. 
    Basically does the same thing as the built-in int() function 
    does but also assigns a '_name' attribute to the numeric value""" 
    class __metaclass__(type): 
     """NamedWholeNumber metaclass to allocate and initialize the 
      appropriate immutable numeric type.""" 
     def __call__(cls, name, value, base=None): 
      """Construct appropriate Named* subclass.""" 
      # note the int() call may return a long (it will also convert 
      # values given in a string along with optional base argument) 
      number = int(value) if base is None else int(value, base) 

      # determine the type of named numeric subclass to use 
      if -sys.maxint-1 <= number <= sys.maxint: 
       named_number_class = NamedInt 
      else: 
       named_number_class = NamedLong 

      # return instance of proper named number class 
      return named_number_class(name, number) 

उत्तर

2

यहाँ कैसे आप एकाधिक वंशानुक्रम के माध्यम से सूखी मुद्दे को हल कर सकते हैं। दुर्भाग्यवश, यह __slots__ के साथ अच्छी तरह से खेल नहीं आता है (यह संकलन-समय TypeError एस का कारण बनता है) इसलिए मुझे इसे छोड़ना पड़ा। उम्मीद है कि __dict__ मूल्य आपके उपयोग के मामले के लिए बहुत अधिक स्मृति बर्बाद नहीं करेंगे।

class Named(object): 
    """Named object mix-in. Not useable directly.""" 
    def __setattr__(self, name, value): 
     if hasattr(self, name): 
      raise AttributeError(
       "%r object attribute %r is read-only" % 
       (self.__class__.__name__, name)) 
     else: 
      raise AttributeError(
       "Cannot add attribute %r to %r object" % 
       (name, self.__class__.__name__)) 

    def __new__(cls, name, *args): 
     self = super(Named, cls).__new__(cls, *args) 
     super(Named, self).__setattr__('_name', name) 
     return self 

    def __str__(self): # override string conversion to be name 
     return self._name 

    __repr__ = __str__ 

class NamedInt(Named, int): 
    """NamedInt class. Constructor will return a NamedLong if value is big.""" 
    def __new__(cls, name, *args): 
     value = int(*args) # will raise an exception on invalid arguments 
     if isinstance(value, int): 
      return super(NamedInt, cls).__new__(cls, name, value) 
     elif isinstance(value, long): 
      return NamedLong(name, value) 

class NamedLong(Named, long): 
    """Nothing to see here.""" 
    pass 
+0

अच्छा जवाब, लेकिन 'नामांकित' ('हेक्सबेस', 'डेडबीफ', 16) को संभाल नहीं करता है। – martineau

+0

हम्म, अच्छा बिंदु। मुझे लगता है कि इसे varargs के साथ तय किया जा सकता है। मैं ऐसा करने के लिए संपादित करूँगा। – Blckknght

+0

फिक्स के लिए धन्यवाद। इस और @ एरिक्सन के जवाब के बीच फैसला करना मुश्किल था, क्योंकि दोनों डीआरवाई मुद्दे को बहुत अच्छी तरह से संबोधित करते थे - लेकिन आखिरकार इसे चुना क्योंकि यह सबसे सरल और समझने योग्य आईएमएचओ है। बीटीडब्लू, ''__slots__' विशेषता को केवल' नामांकित 'उप-वर्ग (जैसे एरिक्सन ने किया) में जोड़ना संभव है, जो उस पते को संबोधित करता है जिसकी संभावना अधिक सामान्य' int' केस (और _is_ उपयोग के लिए एक महत्वपूर्ण विशेषता है) की आवश्यकता है। – martineau

2

ओवरराइड the allocator आप उचित प्रकार का एक ऑब्जेक्ट प्रदान करने देगा।

class NamedInt(int): 
    def __new__(...): 
    if should_be_NamedLong(...): 
     return NamedLong(...) 
    ... 
+0

दी इस 'NamedWholeNumber' वर्ग की आवश्यकता को समाप्त (और शायद लायक कर हो) होगा, लेकिन यह कोड के सबसे कि किया गया था की तरह लगता है इसमें बस 'NamedInt .__ नई __()' विधि में स्थानांतरित हो जाएगा और मुझे अभी भी एक अलग 'नामांकित लोंग' हैबक्लास होना चाहिए - या क्या मुझे कुछ याद आ रहा है? – martineau

+0

यह सही के बारे में लगता है, लेकिन याद रखें कि पायथन 2.x में 'int()' के लिए दिए गए मान के बावजूद अलग 'int' और 'long' कक्षाएं हैं। –

2

यहां कक्षा डेकोरेटर संस्करण है:

def named_number(Named): 

    @staticmethod 
    def __new__(cls, name, value, base=None): 
     value = int(value) if base is None else int(value, base) 
     if isinstance(value, int): 
      NamedNumber = Named # NamedInt/NamedLong 
     else: 
      NamedNumber = cls = NamedLong 
     self = super(NamedNumber, cls).__new__(cls, value) 
     super(NamedNumber, self).__setattr__('_name', name) 
     return self 

    def __setattr__(self, name, value): 
     if hasattr(self, name): 
      raise AttributeError(
       "'%r' object attribute %r is read-only" % (Named, name)) 
     else: 
      raise AttributeError(
       "Cannot add attribute %r to '%r' object" % (name, Named)) 

    def __repr__(self): 
     return self._name 

    __str__ = __repr__ 

    for k, v in locals().items(): 
     if k != 'Named': 
      setattr(Named, k, v) 

    return Named 

@named_number 
class NamedInt(int): 
    __slots__ = '_name' 

@named_number 
class NamedLong(long): pass 
+0

निश्चित रूप से पैक IMHO अग्रणी। मैं इसके बीच और @ ब्लैकनगेट के बीच फैसला करने की कोशिश कर रहा हूं। मुझे यह तथ्य पसंद है कि आपका '__slots__' अनुकूलन, गैर-दशमलव आधारित स्ट्रिंग मानों का समर्थन करता है, और केवल एक विरासत की आवश्यकता होती है। – martineau

+0

दुर्भाग्य से मैंने इसमें शामिल टिप्पणी में बताए गए कारणों के कारण @ ब्लैकनघट के उत्तर के साथ जाने का निर्णय लिया है।यह एक कठिन विकल्प था, और फिर भी, आपका दृष्टिकोण पूरी तरह से व्यवहार्य लगता है और अधिकांश उपायों से अच्छा है। मुझे कक्षा सजावट करने वालों को बहुत चालाक लागू करने के लिए भी आपका दृष्टिकोण मिला - और इससे कुछ नई तकनीकें सीखीं। धन्यवाद! – martineau