2008-12-27 11 views

उत्तर

22

हैं कृपया दिखाए गए अनुसार ऐसा मत करो। जब आप क्लास से अलग होने के लिए एक उदाहरण बंद कर देते हैं तो कोड अपठनीय हो जाता है।

आप बंदरगाह कोड डीबग नहीं कर सकते हैं।

जब आपको boby और print type(boby) में कोई बग मिलती है, तो आप देखेंगे कि (ए) यह एक कुत्ता है, लेकिन (बी) कुछ अस्पष्ट कारणों से यह सही ढंग से छाल नहीं करता है। यह एक बुरा सपना है। ऐसा मत करो।

कृपया इसके बजाय ऐसा करें।

class Dog: 
    def bark(self): 
     print "WOOF" 

class BobyDog(Dog): 
    def bark(self): 
     print "WoOoOoF!!" 

otherDog= Dog() 
otherDog.bark() # WOOF 

boby = BobyDog() 
boby.bark() # WoOoOoF!! 
+6

@arivero: मैंने सोचा था कि "कृपया इसे दिखाए गए अनुसार नहीं करें" जो पूरी तरह स्पष्ट है। आप यह और अधिक स्पष्ट करने के लिए क्या अन्य या अलग शब्द देखना चाहते हैं कि यह उस प्रश्न का उत्तर नहीं दे रहा है, लेकिन यह सलाह दे रहा है कि यह एक बुरा विचार क्यों है? –

+17

मैं सलाह में असहमत नहीं हूं, न ही ओपी जैसा लगता है। लेकिन मुझे लगता है कि लोगों से पूछने के कारण हैं। या यहां तक ​​कि अगर ओपी नहीं है, तो अन्य भविष्य के आगंतुक भी कर सकते हैं। तो, आईएमएचओ, एक उत्तर और एक झगड़ा बेहतर है कि सिर्फ एक झगड़ा। – arivero

+7

@arivero: उसने मेरे प्रश्न का उत्तर नहीं दिया। –

120

हाँ, यह संभव है:

class Dog: 
    def bark(self): 
     print "Woof" 

def new_bark(self): 
    print "Woof Woof" 

foo = Dog() 

funcType = type(Dog.bark) 

# "Woof" 
foo.bark() 

# replace bark with new_bark for this object only 
foo.bark = funcType(new_bark, foo, Dog) 

foo.bark() 
# "Woof Woof" 
+1

एक छोटी सी टिप्पणी, जब आप funcType (new_bark, foo, कुत्ता) करते हैं तो इसका नाम == छाल और उदाहरण विधि dog.new_bark foo .__ dict__ में सही जोड़ रहा है? इसलिए, जब आप दोबारा कॉल करते हैं तो इसे पहले इंस्टेंस डिक्शनरी में देखें और उस के लिए कॉल करें, –

+5

कृपया बताएं कि यह क्या करता है, विशेष रूप से 'funcType' क्या करता है और यह आवश्यक क्यों है। –

+1

मुझे लगता है कि 'funcType = type.MethodType' (' प्रकार' आयात करने के बाद) 'funcType = type (Dog.bark)' के बजाय इसे थोड़ा सा सरल और अधिक स्पष्ट किया जा सकता है। –

22
class Dog: 
    def bark(self): 
     print "WOOF" 

boby = Dog() 
boby.bark() # WOOF 

# METHOD OVERRIDE 
def new_bark(): 
    print "WoOoOoF!!" 
boby.bark = new_bark 

boby.bark() # WoOoOoF!! 

आप समारोह के अंदर boby चर का उपयोग कर सकते हैं अगर आप की जरूरत है। चूंकि आप इस एक इंस्टेंस ऑब्जेक्ट के लिए विधि को ओवरराइड कर रहे हैं, इसलिए यह तरीका सरल है और self का उपयोग करने के समान ही प्रभाव है।

+1

मूल हस्ताक्षर का उपयोग करके IMHO पठनीयता में जोड़ता है, विशेष रूप से यदि फ़ंक्शन को कोड में कहीं और परिभाषित किया गया है, उदाहरण के नजदीक नहीं। अपवाद वह मामला होगा जहां ओवरराइडिंग विधि को फ़ंक्शन के रूप में स्वतंत्र रूप से भी उपयोग किया जाता है। बेशक, इस सरल उदाहरण में, इससे कोई फर्क नहीं पड़ता। – codelogic

+1

मुझे समझ में नहीं आता कि यह स्वीकार्य उत्तर क्यों नहीं है। इसे 'पैचिंग' कहा जाता है और यह करने का सही तरीका है (उदा। 'Boby = dog() 'और' boby.bark = new_bark')। नियंत्रण के लिए यूनिट * परीक्षण * में यह अविश्वसनीय रूप से उपयोगी है। अधिक स्पष्टीकरण के लिए https://tryolabs.com/blog/2013/07/05/run-time-method-patching-python/ (उदाहरण) देखें - नहीं, मैं लिंक की गई साइट या लेखक से संबद्ध नहीं हूं। – Geoff

+2

new_bark विधि में स्वयं (उदाहरण) तक पहुंच नहीं है, इसलिए उपयोगकर्ता को new_bark में इंस्टेंस गुणों तक पहुंचने का कोई तरीका नहीं है। इसके बजाय किसी को टाइप मॉड्यूल से विधि टाइप का उपयोग करने की आवश्यकता है (नीचे मेरा उत्तर देखें)। –

0

के बाद से कार्यों अजगर में प्रथम श्रेणी वस्तुओं रहे हैं अपने वर्ग वस्तु आरंभ करते हुए आप उन्हें पास या किसी वर्ग उदाहरण के लिए किसी भी समय इसे ओवरराइड कर सकते हैं:

class Dog: 
    def __init__(self, barkmethod=None): 
     self.bark=self.barkp 
     if barkmethod: 
      self.bark=barkmethod 
    def barkp(self): 
     print "woof" 

d=Dog() 
print "calling original bark" 
d.bark() 

def barknew(): 
    print "wooOOOoof" 

d1=Dog(barknew) 
print "calling the new bark" 
d1.bark() 

def barknew1(): 
    print "nowoof" 

d1.bark=barknew1 
print "calling another new" 
d1.bark() 

और परिणाम

calling original bark 
woof 
calling the new bark 
wooOOOoof 
calling another new 
nowoof 
-4

हालांकि मैं एस लोट से विरासत विचार पसंद आया और 'प्रकार (क)' बात से सहमत हैं, लेकिन जब से कार्यों भी सुलभ गुण, मुझे लगता है कि यह इस तरह से नियंत्रित किया जा सकता:

class Dog: 
    def __init__(self, barkmethod=None): 
     self.bark=self.barkp 
     if barkmethod: 
      self.bark=barkmethod 
    def barkp(self): 
     """original bark""" 
     print "woof" 

d=Dog() 
print "calling original bark" 
d.bark() 
print "that was %s\n" % d.bark.__doc__ 

def barknew(): 
    """a new type of bark""" 
    print "wooOOOoof" 

d1=Dog(barknew) 
print "calling the new bark" 
d1.bark() 
print "that was %s\n" % d1.bark.__doc__ 

def barknew1(): 
    """another type of new bark""" 
    print "nowoof" 

d1.bark=barknew1 
print "another new" 
d1.bark() 
print "that was %s\n" % d1.bark.__doc__ 

और आउटपुट है:

calling original bark 
woof 
that was original bark 

calling the new bark 
wooOOOoof 
that was a new type of bark 

another new 
nowoof 
that was another type of new bark 
+2

यदि इसे "प्रबंधित" होना चाहिए, तो - मेरे लिए - कुछ गलत है। विशेष रूप से जब पहली श्रेणी की भाषा सुविधा होती है जो पहले से ही नौकरी करता है। –

-4

प्रिय इस अधिभावी नहीं है तुम बस वस्तु के साथ दो बार एक ही समारोह बुला रहे हैं। असल में ओवरराइडिंग एक से अधिक वर्ग से संबंधित है। जब विभिन्न वर्गों में एक ही हस्ताक्षर विधि मौजूद होती है तो आप जो काम करते हैं, उसे कॉल करने वाले ऑब्जेक्ट का निर्णय लेते हैं। पाइथन में ओवरराइडिंग संभव है जब आप एक से अधिक कक्षाएं एक ही कार्य लिखते हैं और एक और बात यह साझा करने के लिए अधिक होती है कि पाइथन

12

में ओवरलोडिंग की अनुमति नहीं है, आपको टाइप मॉड्यूल से विधि टाइप का उपयोग करने की आवश्यकता है। विधि प्रकार का उद्देश्य उदाहरण स्तर विधियों को ओवरराइट कर रहा है (ताकि स्वयं ओवरराइट विधि में उपलब्ध हो)।

उदाहरण के नीचे देखें।

import types 

class Dog: 
    def bark(self): 
     print "WOOF" 

boby = Dog() 
boby.bark() # WOOF 

def _bark(self): 
    print "WoOoOoF!!" 

boby.bark = types.MethodType(_bark, boby) 

boby.bark() # WoOoOoF!! 
1

@ codelogic उत्तम जवाब की व्याख्या करने के लिए सबसे सटीक उत्तर हो सकता है, मैं एक और अधिक स्पष्ट दृष्टिकोण का प्रस्ताव।यह वही तकनीक है जो . ऑपरेटर एक क्लास विधि को बाध्य करने के लिए पूरी तरह से चला जाता है जब आप इसे आवृत्ति विशेषता के रूप में एक्सेस करते हैं, सिवाय इसके कि आपकी विधि वास्तव में कक्षा के बाहर परिभाषित एक फ़ंक्शन होगी।

@ कोडेलोगिक कोड के साथ काम करना, केवल अंतर यह है कि विधि कैसे बाध्य है। मैं इस तथ्य का उपयोग कर रहा हूं कि पाइथन में कार्य और विधियां गैर-डेटा descriptors हैं, और __get__ विधि का आह्वान कर रही हैं। विशेष रूप से ध्यान दें कि मूल और प्रतिस्थापन दोनों के समान हस्ताक्षर होते हैं, जिसका अर्थ है कि आप प्रतिस्थापन को पूर्ण श्रेणी विधि के रूप में लिख सकते हैं, self के माध्यम से सभी इंस्टेंस विशेषताओं तक पहुंच सकते हैं।

 
class Dog: 
    def bark(self): 
     print "Woof" 

def new_bark(self): 
    print "Woof Woof" 

foo = Dog() 

# "Woof" 
foo.bark() 

# replace bark with new_bark for this object only 
foo.bark = new_bark.__get__(foo, Dog) 

foo.bark() 
# "Woof Woof" 

एक उदाहरण विशेषता के लिए बाध्य विधि बताए करके, आप एक विधि अधिभावी के एक लगभग पूरा अनुकरण बनाया है। गायब होने वाली एक आसान सुविधा super के नो-एर्ग संस्करण तक पहुंच है, क्योंकि आप कक्षा परिभाषा में नहीं हैं। एक और बात यह है कि __name__ आपकी बाध्य विधि की विशेषता उस कार्य का नाम नहीं लेगी जो इसे ओवरराइड कर रही है, क्योंकि यह कक्षा परिभाषा में होगी, लेकिन आप इसे मैन्युअल रूप से सेट कर सकते हैं। तीसरा अंतर यह है कि आपकी मैन्युअल रूप से बाध्य विधि एक सादा विशेषता संदर्भ है जो केवल एक कार्य होता है। . ऑपरेटर कुछ भी नहीं करता है लेकिन उस संदर्भ को प्राप्त करता है। दूसरी ओर एक उदाहरण से एक नियमित विधि का आह्वान करते समय, बाध्यकारी प्रक्रिया हर बार एक नई बाध्य विधि बनाता है।

एकमात्र कारण यह है कि यह काम करता है, वैसे ही, उदाहरण विशेषताएँ गैर-डेटा वर्णनकर्ताओं को ओवरराइड करती हैं। डेटा डिस्क्रिप्टर के पास __set__ विधियां हैं, जो विधियां (सौभाग्य से आपके लिए) नहीं हैं। वर्ग में डेटा डिस्क्रिप्टर वास्तव में किसी भी आवृत्ति विशेषताओं पर प्राथमिकता लेते हैं। यही कारण है कि आप किसी संपत्ति को असाइन कर सकते हैं: जब आप असाइनमेंट करने का प्रयास करते हैं तो उनकी __set__ विधि लागू होती है। मैं व्यक्तिगत रूप से इसे एक कदम आगे ले जाना चाहता हूं और उदाहरण के __dict__ में अंतर्निहित विशेषता के वास्तविक मूल्य को छिपाना पसंद करता हूं, जहां यह सामान्य माध्यमों से अप्राप्य है क्योंकि संपत्ति इसे छाया देती है।

आपको यह भी ध्यान में रखना चाहिए कि यह magic (double underscore) methods के लिए व्यर्थ है। जादू तरीकों को निश्चित रूप से इस तरह से ओवरराइड किया जा सकता है, लेकिन उनके द्वारा उपयोग किए जाने वाले संचालन केवल प्रकार को देखते हैं। उदाहरण के लिए, आप अपने उदाहरण में कुछ खास करने के लिए __contains__ सेट कर सकते हैं, लेकिन x in instance पर कॉल करना उस पर ध्यान देगा और इसके बजाय type(instance).__contains__(instance, x) का उपयोग करेगा। यह पाइथन data model में निर्दिष्ट सभी जादू विधियों पर लागू होता है।

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