क्या पायथन में एक तरीका है उदाहरण के स्तर पर एक वर्ग विधि को ओवरराइड करना? उदाहरण के लिए:
class Dog:
def bark(self):
print "WOOF"
boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
boby.bark() # WoOoOoF!!
क्या पायथन में एक तरीका है उदाहरण के स्तर पर एक वर्ग विधि को ओवरराइड करना? उदाहरण के लिए:
class Dog:
def bark(self):
print "WOOF"
boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
boby.bark() # WoOoOoF!!
जवाबों:
कृपया ऐसा न करें जैसा दिखाया गया है। जब आप क्लास से अलग होने का उदाहरण देते हैं तो आप कोड अपठनीय हो जाते हैं।
आप बंदरों के कोड को डीबग नहीं कर सकते।
जब आप में एक बग मिल 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!!
हाँ, यह मुमकिन है:
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"
funcTypeकरता है और क्यों आवश्यक है।
funcType = types.MethodType(आयात करने के बाद types) उपयोग करके थोड़ा सरल और अधिक स्पष्ट किया जा सकता है funcType = type(Dog.bark)।
__get__इसे उदाहरण पर बाँधने के लिए फ़ंक्शन पर भी कॉल कर सकते हैं ।
आपको मॉड्यूल से MethodType का उपयोग करने की आवश्यकता है types। उद्देश्य का उद्देश्य MethodTypeउदाहरण के तरीकों को अधिलेखित करना है (ताकि यह selfअधिलेखित विधियों में उपलब्ध हो सके)।
नीचे दिए गए उदाहरण देखें।
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!!
@ कोडेलोगिक के उत्कृष्ट उत्तर की व्याख्या करने के लिए, मैं एक अधिक स्पष्ट दृष्टिकोण का प्रस्ताव करता हूं। यह वही तकनीक है जो .ऑपरेटर पूरी तरह से एक क्लास पद्धति को बांधने के लिए जाता है जब आप इसे एक उदाहरण विशेषता के रूप में एक्सेस करते हैं, सिवाय इसके कि आपका तरीका वास्तव में एक क्लास के बाहर परिभाषित फ़ंक्शन होगा।
@ कोडेलिक कोड के साथ काम करना, एकमात्र अंतर यह है कि विधि कैसे बाध्य है। मैं इस तथ्य का उपयोग कर रहा हूं कि पायथन में फ़ंक्शन और विधियाँ गैर-डेटा विवरणक हैं , और __get__विधि को लागू कर रहे हैं । विशेष रूप से ध्यान दें कि मूल और प्रतिस्थापन दोनों में समान हस्ताक्षर हैं, जिसका अर्थ है कि आप प्रतिस्थापन को एक पूर्ण वर्ग विधि के रूप में लिख सकते हैं, सभी उदाहरण विशेषताओं के माध्यम से पहुंच सकते हैं self।
क्लास डॉग:
डीप बार्क (स्व):
"Woof" प्रिंट करें
def new_bark (स्व):
"Woof Woof" प्रिंट करें
फू = कुत्ता ()
# "वूफ़"
foo.bark ()
# बार्क को केवल इस ऑब्जेक्ट के लिए new_bark से बदलें
foo.bark = new_bark .__ get __ (फू, डॉग)
foo.bark ()
# "वूफ वूफ"
एक उदाहरण विशेषता को बाध्य विधि निर्दिष्ट करके, आपने एक विधि को ओवरराइड करने का लगभग पूर्ण अनुकरण बनाया है। एक आसान सुविधा जो अनुपलब्ध है, वह नहीं के arg संस्करण तक पहुँच है super, क्योंकि आप एक वर्ग परिभाषा में नहीं हैं। एक और बात यह है कि __name__आपके बाउंड मेथड की विशेषता उस फ़ंक्शन का नाम नहीं लेगी जो इसे ओवरराइड कर रहा है, क्योंकि यह कक्षा की परिभाषा में होगा, लेकिन आप अभी भी इसे मैन्युअल रूप से सेट कर सकते हैं। तीसरा अंतर यह है कि आपकी मैन्युअल-बाउंड विधि एक सादे विशेषता संदर्भ है जो कि केवल एक फ़ंक्शन होता है। .ऑपरेटर कुछ नहीं करता है लेकिन यह है कि संदर्भ से लाएं। दूसरी ओर एक उदाहरण से एक नियमित विधि को लागू करते समय, बाध्यकारी प्रक्रिया हर बार एक नई बाध्य विधि बनाती है।
एकमात्र कारण यह है कि इस तरह से काम करता है, उदाहरण है कि गैर-डेटा विवरणों को ओवरराइड करता है । डेटा डिस्क्रिप्टर में __set__विधियाँ हैं, जो विधियाँ (सौभाग्य से आपके लिए) नहीं हैं। कक्षा में डेटा डिस्क्रिप्टर वास्तव में किसी भी उदाहरण विशेषताओं पर प्राथमिकता लेते हैं। इसीलिए आप किसी प्रॉपर्टी को असाइन कर सकते हैं: __set__जब आप असाइनमेंट बनाने की कोशिश करते हैं, तो उनका तरीका लागू हो जाता है। मैं व्यक्तिगत रूप से इसे एक कदम आगे ले जाना और उदाहरण में अंतर्निहित विशेषता के वास्तविक मूल्य को छिपाना पसंद करता हूं __dict__, जहां यह सामान्य तरीके से दुर्गम है क्योंकि संपत्ति इसे छाया देती है।
आपको यह भी ध्यान रखना चाहिए कि यह जादू (डबल अंडरस्कोर) तरीकों के लिए व्यर्थ है । जादू के तरीकों को इस तरह से ओवरराइड किया जा सकता है, लेकिन इनका उपयोग करने वाले ऑपरेशन केवल प्रकार को देखते हैं। उदाहरण के लिए, आप __contains__अपने उदाहरण में कुछ विशेष करने के लिए सेट कर सकते हैं , लेकिन कॉलिंग x in instanceकी अवहेलना और type(instance).__contains__(instance, x)इसके बजाय उपयोग करना होगा। यह पायथन डेटा मॉडल में निर्दिष्ट सभी जादू विधियों पर लागू होता है ।
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।
patchingऔर यह इसे करने का सही तरीका है (जैसे boby = Dog()और boby.bark = new_bark)। यह नियंत्रण के लिए इकाई परीक्षण में अविश्वसनीय रूप से उपयोगी है । अधिक स्पष्टीकरण के लिए देखें tryolabs.com/blog/2013/07/05/run-time-method-patching-python (उदाहरण) - नहीं मैं लिंक की गई साइट या लेखक से संबद्ध नहीं हूं।
चूँकि यहाँ कोई उल्लेख नहीं कर रहा है functools.partial:
from functools import partial
class Dog:
name = "aaa"
def bark(self):
print("WOOF")
boby = Dog()
boby.bark() # WOOF
def _bark(self):
print("WoOoOoF!!")
boby.bark = partial(_bark, boby)
boby.bark() # WoOoOoF!!
चूंकि पायथन में फ़र्स्ट क्लास ऑब्जेक्ट हैं, आप अपनी क्लास ऑब्जेक्ट को इनिशियलाइज़ करते समय उन्हें पास कर सकते हैं या किसी दिए गए क्लास के उदाहरण के लिए इसे कभी भी ओवरराइड कर सकते हैं:
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
यद्यपि मुझे एस। लोट से विरासत का विचार पसंद आया और 'प्रकार (ए)' की बात से सहमत हूं, लेकिन चूंकि कार्यों में भी सुलभ गुण हैं, मुझे लगता है कि इसे इस तरह से प्रबंधित किया जा सकता है:
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
प्रिय यह ओवरराइडिंग नहीं है आप केवल एक ही फ़ंक्शन को ऑब्जेक्ट के साथ दो बार कॉल कर रहे हैं। मूल रूप से ओवरराइडिंग एक से अधिक वर्ग से संबंधित है। जब एक ही हस्ताक्षर विधि अलग-अलग वर्गों में मौजूद होती है, तो आपके कौन से फ़ंक्शन इसे कॉल कर रहे हैं, यह उस ऑब्जेक्ट को तय करता है जो इसे कॉल करता है। अजगर में ओवरराइडिंग संभव है जब आप एक से अधिक कक्षाएं बनाते हैं तो एक ही फ़ंक्शन लिखता है और एक बात और साझा करने के लिए कि अजगर में ओवरलोडिंग की अनुमति नहीं है
मैंने इसे मूल प्रश्न का सबसे सटीक उत्तर पाया
https://stackoverflow.com/a/10829381/7640677
import a
def _new_print_message(message):
print "NEW:", message
a.print_message = _new_print_message
import b
b.execute()