2009-05-07 17 views
16

मैं str उपclass करने की कोशिश कर रहा हूं, लेकिन इसकी अपरिवर्तनीयता के कारण कुछ कठिनाइयों का सामना करना पड़ रहा है।विस्तारित पायथन के बिल्टिन स्ट्र

class DerivedClass(str): 

    def __new__(cls, string): 
     ob = super(DerivedClass, cls).__new__(cls, string) 
     return ob 

    def upper(self): 
     #overridden, new functionality. Return ob of type DerivedClass. Great. 
     caps = super(DerivedClass, self).upper() 
     return DerivedClass(caps + '123') 

derived = DerivedClass('a') 

print derived.upper() #'A123' 
print type(derived.upper()) #<class '__main__.DerivedClass'> 
print derived.lower() #'a' 
print type(derived.lower()) #<type 'str'> 

विरासत में मिला तरीकों है कि किसी भी नई कार्यक्षमता की आवश्यकता नहीं है के लिए, ऐसे derived.lower() के रूप में, वहाँ एक सरल, pythonic प्रकार DerivedClass (str के बजाय) की एक वस्तु लौटने के लिए तरीका है? या मैं मैन्युअल रूप से प्रत्येक str.method() को ओवरराइड कर रहा हूं, जैसा कि मैंने derived.upper() के साथ किया था?

संपादित करें:

#Any massive flaws in the following? 

class DerivedClass(str): 
    def __new__(cls, string): 
     ob = super(DerivedClass, cls).__new__(cls, string) 
     return ob 

    def upper(self): 
     caps = super(DerivedClass, self).upper() 
     return DerivedClass(caps + '123') 

    def __getattribute__(self, name): 
     att = super(DerivedClass, self).__getattribute__(name) 

     if not callable(att): 
      return att 

     def call_me_later(*args, **kwargs): 
      result = att(*args, **kwargs) 
      if isinstance(result, basestring): 
       return DerivedClass(result) 
      return result 
     return call_me_later 
+0

** यह भी देखें: ** http://stackoverflow.com/questions/tagged/python+monkeypatching – dreftymac

+0

** यह भी देखें: ** http://stackoverflow.com/questions/tagged/python+method-missing – dreftymac

उत्तर

5

आप के रूप Zr40 पता चलता है __getattribute__ अधिभावी करके ऐसा कर सकते हैं, लेकिन आप getAttribute एक प्रतिदेय समारोह लौटने की आवश्यकता होगी। नीचे दिया गया नमूना आपको जो चाहिए वो देना चाहिए; यह, जीवन को आसान बनाने के लिए functools.partial आवरण का उपयोग करता है, हालांकि आप इसे आंशिक बिना लागू सकता है अगर आप की तरह:

from functools import partial 

class DerivedClass(str): 

    def __new__(cls, string): 
     ob = super(DerivedClass, cls).__new__(cls, string) 
     return ob 

    def upper(self): 
     #overridden, new functionality. Return ob of type DerivedClass. Great. 
     caps = super(DerivedClass, self).upper() 
     return DerivedClass(caps + '123') 

    def __getattribute__(self, name): 
     func = str.__getattribute__(self, name) 
     if name == 'upper': 
      return func 

     if not callable(func): 
      return func 

     def call_me_later(*args, **kwargs): 
      result = func(*args, **kwargs) 
      # Some str functions return lists, ints, etc 
      if isinstance(result, basestring: 
       return DerivedClass(result) 
      return result 

     return partial(call_me_later) 
-2

आप __getattribute__ अधिभावी द्वारा ऐसा करने के लिए सक्षम हो सकता है।

+0

क्या आपका मतलब str .__ getattribute__ नहीं है? और DerivedClass .__ dict__ आपको बताएगा कि कौन से नाम व्युत्पन्न वर्ग में हैं। –

+0

ऐसा लगता है कि टाइपरर फेंकना है। प्रिंट derived.lower() टाइप एरर: 'DerivedClass' ऑब्जेक्ट कॉल करने योग्य नहीं है – user102975

+0

हाँ, मेरा मानना ​​है कि यह str होना चाहिए .__ getattribute__। अभी भी TypeError प्राप्त करें। – user102975

5

आप दोनों करीब हैं, लेकिन प्रत्येक के लिए जाँच कई तरीके अधिभावी के लिए अच्छी तरह से लागू नहीं होती है।

from functools import partial 

class DerivedClass(str): 
    def __new__(cls, string): 
     ob = super(DerivedClass, cls).__new__(cls, string) 
     return ob 

    def upper(self): 
     caps = super(DerivedClass, self).upper() 
     return DerivedClass(caps + '123') 

    def __getattribute__(self, name): 
     if name in ['__dict__', '__members__', '__methods__', '__class__']: 
      return object.__getattribute__(self, name) 
     func = str.__getattribute__(self, name) 
     if name in self.__dict__.keys() or not callable(func): 
      return func 

     def call_me_later(*args, **kwargs): 
      result = func(*args, **kwargs) 
      # Some str functions return lists, ints, etc 
      if isinstance(result, basestring): 
       return DerivedClass(result) 
      return result 

     return partial(call_me_later) 

(सुधार टिप्पणी में jarret hardie ने सुझाव दिया।)

+0

क्या नाम के लिए स्वयं .__ dict __। कुंजी() की जांच करना आवश्यक है? Str .__ getattribute __ (self, name) पर कॉल अपेक्षित होने पर अपेक्षित (ओवरराइड या नहीं) और 'call_me_later' उप-वर्ग के उदाहरणों को कॉल करने के तरीके को कॉल करता है। मुझे लगता है कि कॉल करने योग्य (func) डेटा सदस्यों तक पहुंचने के किसी भी प्रयास को पकड़ना है। मैंने थोड़ा योगदान संशोधित किया है, और सवाल संपादित किया है। सादगी के लिए, क्योंकि मैं अभी तक इसके बारे में परिचित नहीं हूं, आंशिक उपयोग नहीं किया जाता है। विचार? धन्यवाद फिर से :) – user102975

+0

@trigue - __getattribute__ में एक प्रिंट स्टेटमेंट दें। आप देखेंगे कि इसे हर बार बुलाया जाता है। – tghw

7

एक वर्ग डेकोरेटर के लिए अच्छा उपयोग - मोटे तौर पर (अपरीक्षित कोड):

@do_overrides 
class Myst(str): 
    def upper(self): 
    ...&c... 

और

def do_overrides(cls): 
    done = set(dir(cls)) 
    base = cls.__bases__[0] 
    def wrap(f): 
    def wrapper(*a, **k): 
     r = f(*a, **k) 
     if isinstance(r, base): 
     r = cls(r) 
     return r 
    for m in dir(base): 
    if m in done or not callable(m): 
     continue 
    setattr(cls, m, wrap(getattr(base, m))) 
संबंधित मुद्दे