2012-02-24 8 views
16

मेरे पास एक कक्षा है जो कई अन्य वर्गों के लिए एक सुपर-क्लास है। मुझे लगता है मैं एक वर्ग विधि के साथ यह पूरा करने की कोशिश की पता (मेरी सुपर वर्ग के init() में करना चाहते हैं तो उपवर्ग एक विशिष्ट विधि अधिरोहित हैपायथन में उपclasses में विधि अधिभार का पता लगाने के लिए कैसे?

, लेकिन परिणाम गलत थे:।

class Super: 
    def __init__(self): 
     if self.method == Super.method: 
     print 'same' 
     else: 
     print 'different' 

    @classmethod 
    def method(cls): 
     pass 

class Sub1(Super): 
    def method(self): 
     print 'hi' 

class Sub2(Super): 
    pass 

Super() # should be same 
Sub1() # should be different 
Sub2() # should be same 

>>> same 
>>> different 
>>> different 

वहाँ एक सुपर वर्ग जानना चाहते हैं कि एक उप-वर्ग एक विधि अधिरोहित है के लिए कोई तरीका है?

+1

की जा सकी:

class Super: def __init__(self): if self.method.__code__ is Super.method.__code__: print('same') else: print('different') @classmethod def method(cls): pass class Sub1(Super): def method(self): print('hi') class Sub2(Super): pass Super() # should be same Sub1() # should be different Sub2() # should be same 

और यहाँ उत्पादन है आप कुछ शब्द कहते हैं * क्यों * आप ऐसा करना चाहते हैं? – NPE

+0

कुछ भी तुरंत दिमाग में नहीं आता है, लेकिन यदि आप अपनी विधियों के लिए दस्तावेज़ों को शामिल करते हैं, तो विधि ओवरराइड होने पर वे ओवरराइट हो जाते हैं। इसलिए आपको इसे 'MyClass.methodname .__ doc__' के साथ ट्रैक करने में सक्षम होना चाहिए।लेकिन मुझे यह समाधान बहुत हैक होने का पता चला है, यही कारण है कि मैं इसे उत्तर के रूप में पोस्ट नहीं कर रहा हूं – inspectorG4dget

+0

असल में मैं चाहता हूं कि सुपर-क्लास में इन विधियों को केवल 'पास' के रूप में परिभाषित किया गया हो और एक अलग विधि (वास्तव में __init__) इन कार्यों को बुलाओ। मैं प्रिंट स्टेटमेंट्स में इनिट रखना चाहता हूं जो कहता है कि हम फ़ंक्शन शुरू या समाप्त कर रहे हैं, लेकिन यदि यह फ़ंक्शन अभी भी शून्य है, तो ये कथन जगह से बाहर दिखते हैं, और मैं उनके साथ हटना चाहता हूं। – Brian

उत्तर

7

आप अपने स्वयं के सजावट का उपयोग कर सकते हैं। लेकिन यह एक चाल है और केवल उन वर्गों पर काम करेगी जहां आप कार्यान्वयन को नियंत्रित करते हैं।

def override(method): 
    method.is_overridden = True 
    return method 

class Super: 
    def __init__(self): 
     if hasattr(self.method, 'is_overridden'): 
     print 'different' 
     else: 
     print 'same' 
    @classmethod 
    def method(cls): 
     pass 

class Sub1(Super): 
    @override 
    def method(self): 
     print 'hi' 

class Sub2(Super): 
    pass 

Super() # should be same 
Sub1() # should be different 
Sub2() # should be same 

>>> same 
>>> different 
>>> same 
+4

मैं थोड़ी अलग दिशा में गया, @native के साथ अपनी विधि को सजाने, और उप-वर्गों को मानना ​​नहीं होगा। मुझे लगता है कि मैं इसे इस तरह से करूँगा क्योंकि मेरे पास उप-वर्गों पर अधिक नियंत्रण नहीं है। यह अच्छी तरह से काम करता है, आपकी मदद के लिए धन्यवाद! – Brian

+0

या यहां तक ​​कि सरल 'सुपर। Method._original = True'' सुपर() 'वर्ग का शरीर है, और तब जांचें कि क्या हैशर (self.method,' _original ') '। –

3

आप तुलना कर सकते हैं जो कुछ भी विधि आप से प्राप्त कर सकते हैं अंदर समारोह के साथ वर्ग के __dict__ में है ऑब्जेक्ट - "detect_overriden" functionbel कम करता है - यह चाल को "मूल श्रेणी" के नाम से पास करने के लिए है, जैसा कि कोई व्यक्ति "सुपर" - पर कॉल करता है, अन्यथा इसके बजाय पेरेंटक्लास से से विशेषताओं को पुनर्प्राप्त करना आसान नहीं है उपवर्ग:

# -*- coding: utf-8 -*- 
from types import FunctionType 

def detect_overriden(cls, obj): 
    res = [] 
    for key, value in cls.__dict__.items(): 
     if isinstance(value, classmethod): 
      value = getattr(cls, key).im_func 
     if isinstance(value, (FunctionType, classmethod)): 
      meth = getattr(obj, key) 
      if not meth.im_func is value: 
       res.append(key) 
    return res 


# Test and example 
class A(object): 
    def __init__(self): 
     print detect_overriden(A, self) 

    def a(self): pass 
    @classmethod 
    def b(self): pass 
    def c(self): pass 

class B(A): 
    def a(self): pass 
    #@classmethod 
    def b(self): pass 

संपादित बदली हुई कोड के रूप में अच्छी classmethods के साथ ठीक काम करने के लिए: अगर यह माता पिता के वर्ग पर एक classmethod का पता लगाता है, आगे बढ़ने से पहले अंतर्निहित समारोह निकालता है।

- मुश्किल कोड को वर्ग के नाम बिना यह कर, का एक अन्य तरीका है, उदाहरण के की क्लास (self.__class__) विधि संकल्प आदेश (__mro__ विशेषता के आधार पर दिया गया है) का पालन करें और तरीकों की डुप्लीकेट की खोज करना होगा और विरासत श्रृंखला के साथ प्रत्येक वर्ग में परिभाषित गुण।

+1

पायथन 3 में यह '__func__' विशेषता है। –

4

ऐसा लगता है सबसे आसान और एक उदाहरण के शब्दकोशों के आम सबसेट और आधार वर्ग ही है, जैसे की तुलना द्वारा ऐसा करने के लिए पर्याप्त:

def detect_overridden(cls, obj): 
    common = cls.__dict__.keys() & obj.__class__.__dict__.keys() 
    diff = [m for m in common if cls.__dict__[m] != obj.__class__.__dict__[m]] 
    print(diff) 

def f1(self): 
    pass 

class Foo: 
    def __init__(self): 
    detect_overridden(Foo, self) 
    def method1(self): 
    print("Hello foo") 
    method2=f1 

class Bar(Foo): 
    def method1(self): 
    print("Hello bar") 
    method2=f1 # This is pointless but not an override 
# def method2(self): 
# pass 

b=Bar() 
f=Foo() 

चलाता है और देता है:

['method1'] 
[] 
4

https://stackoverflow.com/a/9437273/1258307 उत्तर के जवाब में, क्योंकि मेरे पास अभी तक टिप्पणी करने के लिए पर्याप्त क्रेडिट नहीं हैं, यह तब तक पायथन 3 के तहत काम नहीं करेगा जब तक आप im_func को प्रतिस्थापित नहीं करते __func__ के साथ और पायथन 3.4 (और सबसे अधिक संभावना है) में भी काम नहीं करेगा क्योंकि फ़ंक्शंस में __func__ विशेषता नहीं है, केवल बाध्य विधियां हैं।

संपादित करें: यहाँ मूल प्रश्न का हल है (जो 2.7 और 3.4 पर काम किया है, और मैं के बीच में अन्य सभी संस्करण मान):

same 
different 
same 
+0

बस ध्यान दें: साइथन में (कम से कम पायथन 3.4 में), 'self.method .__ code__' अनुपस्थित है, लेकिन साफ ​​पायथन में काम करता है। किसी कारण से, '__code__'' dir (self.method) 'में गायब है – socketpair