मैं PHP या जावा से आभासी तरीकों को जानता हूं।
उन्हें पायथन में कैसे लागू किया जा सकता है?
या मुझे एक अमूर्त वर्ग में एक खाली पद्धति को परिभाषित करना और इसे ओवरराइड करना है?
जवाबों:
ज़रूर, और आपको आधार वर्ग में एक विधि को परिभाषित करने की आवश्यकता नहीं है। पायथन तरीकों में वर्चुअल से बेहतर है - वे पूरी तरह से गतिशील हैं, क्योंकि पायथन में टाइपिंग बतख टाइपिंग है ।
class Dog:
def say(self):
print "hau"
class Cat:
def say(self):
print "meow"
pet = Dog()
pet.say() # prints "hau"
another_pet = Cat()
another_pet.say() # prints "meow"
my_pets = [pet, another_pet]
for a_pet in my_pets:
a_pet.say()
Cat
और Dog
पायथन को इस व्यवहार की अनुमति देने के लिए एक सामान्य आधार वर्ग से प्राप्त करने की आवश्यकता नहीं है - आप इसे मुफ्त में प्राप्त करते हैं। उस ने कहा, कुछ प्रोग्रामर अपनी कक्षा की पदानुक्रमों को और अधिक कठोर तरीके से परिभाषित करना पसंद करते हैं ताकि वे इसे बेहतर ढंग से लिख सकें और टाइपिंग की कुछ सख्ती लगा सकें । यह भी संभव है - उदाहरण के लिए abc
मानक मॉड्यूल देखें ।
raise NotImplementedError()
यह "अमूर्त" आधार वर्गों के "शुद्ध आभासी तरीकों" को बढ़ाने के लिए अनुशंसित अपवाद है जो एक विधि को लागू नहीं करते हैं।
https://docs.python.org/3.5/library/exception.html#NotImplementedError कहता है:
यह अपवाद से लिया गया है
RuntimeError
। उपयोगकर्ता परिभाषित आधार वर्गों में, अमूर्त विधियों को इस अपवाद को उठाना चाहिए जब उन्हें विधि को ओवरराइड करने के लिए व्युत्पन्न वर्ग की आवश्यकता होती है।
जैसा कि दूसरों ने कहा, यह ज्यादातर एक दस्तावेजी सम्मेलन है और इसकी आवश्यकता नहीं है, लेकिन इस तरह से आपको एक लापता विशेषता त्रुटि की तुलना में अधिक सार्थक अपवाद मिलता है।
उदाहरण के लिए:
class Base(object):
def virtualMethod(self):
raise NotImplementedError()
def usesVirtualMethod(self):
return self.virtualMethod() + 1
class Derived(Base):
def virtualMethod(self):
return 1
print Derived().usesVirtualMethod()
Base().usesVirtualMethod()
देता है:
2
Traceback (most recent call last):
File "./a.py", line 13, in <module>
Base().usesVirtualMethod()
File "./a.py", line 6, in usesVirtualMethod
return self.virtualMethod() + 1
File "./a.py", line 4, in virtualMethod
raise NotImplementedError()
NotImplementedError
पायथन तरीके हमेशा आभासी होते हैं।
वास्तव में, संस्करण 2.6 अजगर कुछ सार आधार कक्षाएं नामक कुछ प्रदान करता है और आप स्पष्ट रूप से इस तरह से आभासी तरीके सेट कर सकते हैं:
from abc import ABCMeta
from abc import abstractmethod
...
class C:
__metaclass__ = ABCMeta
@abstractmethod
def my_abstract_method(self, ...):
यह बहुत अच्छी तरह से काम करता है, बशर्ते वर्ग उन कक्षाओं से विरासत में न मिले जो पहले से ही मेटाक्लासेस का उपयोग करते हैं।
पायथन तरीके हमेशा आभासी होते हैं
इग्नासियो की तरह अभी भी किसी तरह वर्ग विरासत एक बेहतर तरीका है जो आप चाहते हैं को लागू करने के लिए हो सकता है।
class Animal:
def __init__(self,name,legs):
self.name = name
self.legs = legs
def getLegs(self):
return "{0} has {1} legs".format(self.name, self.legs)
def says(self):
return "I am an unknown animal"
class Dog(Animal): # <Dog inherits from Animal here (all methods as well)
def says(self): # <Called instead of Animal says method
return "I am a dog named {0}".format(self.name)
def somethingOnlyADogCanDo(self):
return "be loyal"
formless = Animal("Animal", 0)
rover = Dog("Rover", 4) #<calls initialization method from animal
print(formless.says()) # <calls animal say method
print(rover.says()) #<calls Dog says method
print(rover.getLegs()) #<calls getLegs method from animal class
परिणाम होना चाहिए:
I am an unknown animal
I am a dog named Rover
Rover has 4 legs
C ++ में वर्चुअल विधि की तरह कुछ (एक संदर्भ या आधार वर्ग के लिए सूचक के माध्यम से एक व्युत्पन्न वर्ग का कॉलिंग कार्यान्वयन) पायथन में समझ में नहीं आता है, क्योंकि पायथन में टाइपिंग नहीं है। (मुझे नहीं पता कि जावा और PHP में वर्चुअल तरीके कैसे काम करते हैं।)
लेकिन अगर "आभासी" से आपका तात्पर्य विरासत में पदानुक्रम में नीचे-सबसे अधिक कार्यान्वयन को बुलावा देना है, तो यह वही है जो आपको हमेशा पायथन में मिलता है, क्योंकि कई उत्तर इंगित करते हैं।
खैर, लगभग हमेशा ...
जैसा कि dplamp ने बताया, पायथन में सभी तरीके उस तरह से व्यवहार नहीं करते हैं। Dunder विधि नहीं है। और मुझे लगता है कि यह एक प्रसिद्ध विशेषता नहीं है।
इस कृत्रिम उदाहरण पर विचार करें
class A:
def prop_a(self):
return 1
def prop_b(self):
return 10 * self.prop_a()
class B(A):
def prop_a(self):
return 2
अभी
>>> B().prop_b()
20
>>> A().prob_b()
10
हालाँकि, इस पर विचार करें
class A:
def __prop_a(self):
return 1
def prop_b(self):
return 10 * self.__prop_a()
class B(A):
def __prop_a(self):
return 2
अभी
>>> B().prop_b()
10
>>> A().prob_b()
10
केवल एक चीज जो हम बदल रहे हैं वह prop_a()
एक कठिन विधि थी।
पहले व्यवहार के साथ एक समस्या यह हो सकती है कि आप के व्यवहार prop_a()
को प्रभावित किए बिना व्युत्पन्न वर्ग के व्यवहार को बदल नहीं सकते हैं prop_b()
। रेमंड हेटिंगर की यह बहुत अच्छी बात एक उपयोग के मामले के लिए एक उदाहरण देती है जहां यह असुविधाजनक है।