पायथन में आभासी तरीकों को कैसे लागू किया जाए?


88

मैं PHP या जावा से आभासी तरीकों को जानता हूं।

उन्हें पायथन में कैसे लागू किया जा सकता है?

या मुझे एक अमूर्त वर्ग में एक खाली पद्धति को परिभाषित करना और इसे ओवरराइड करना है?

जवाबों:


104

ज़रूर, और आपको आधार वर्ग में एक विधि को परिभाषित करने की आवश्यकता नहीं है। पायथन तरीकों में वर्चुअल से बेहतर है - वे पूरी तरह से गतिशील हैं, क्योंकि पायथन में टाइपिंग बतख टाइपिंग है

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मानक मॉड्यूल देखें


35
एक उदाहरण के लिए +1। किस तरह से कुत्तों को "हौ" कहा जाता है?
जेरेमीप

5
@ जेरेमीप: हम्म, अच्छी बात :-) मुझे लगता है कि भाषाओं में "एच" को "हिप्पी" के पहले अक्षर या स्पेनिश में "जेवियर" की तरह ध्वनि बनाने के रूप में समझा जाता है।
एली बेंडरस्की

5
@ एलि: क्षमा करें, लेकिन मुझे सवाल के जवाब में गंभीरता से दिलचस्पी थी। अंग्रेजी में वे कहते हैं "वूफ", अच्छी तरह से वे नहीं करते हैं, लेकिन यह शब्द है कि हम बिल्लियों के लिए "म्याऊ" और गायों के लिए "मू" के अनुरूप हैं। क्या "हौ" स्पेनिश है?
जेरेमीप

9
@JeremyP मुझे पता है कि पोलिश कुत्तों का क्या कहना है;)
j_kubik

2
@JeremyP हां मैं कुत्तों की पुष्टि करता हूं कि स्पेनिश में "जौ" कहते हैं और जब अंग्रेजी में "हाऊ" लिखा जाएगा :) hth
स्काईवल्कर

71

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

संबंधित: क्या पायथन में अमूर्त कक्षाएं बनाना संभव है?


55

पायथन तरीके हमेशा आभासी होते हैं।


सिवाय बौने तरीकों के।
Konstantin

1
यह उत्तर वास्तव में इंटरफ़ेस कक्षाओं को लागू करने के उद्देश्य में मदद नहीं कर रहा है जो कि आभासी तरीकों का उपयोग करने का एक मुख्य कारण है।
जीन-मार्क वोले

21

वास्तव में, संस्करण 2.6 अजगर कुछ सार आधार कक्षाएं नामक कुछ प्रदान करता है और आप स्पष्ट रूप से इस तरह से आभासी तरीके सेट कर सकते हैं:

from abc import ABCMeta
from abc import abstractmethod
...
class C:
    __metaclass__ = ABCMeta
    @abstractmethod
    def my_abstract_method(self, ...):

यह बहुत अच्छी तरह से काम करता है, बशर्ते वर्ग उन कक्षाओं से विरासत में न मिले जो पहले से ही मेटाक्लासेस का उपयोग करते हैं।

स्रोत: http://docs.python.org/2/library/abc.html


क्या इस निर्देश के लिए एक अजगर 3 बराबर है?
लोके

9

पायथन तरीके हमेशा आभासी होते हैं

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

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

4

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()। रेमंड हेटिंगर की यह बहुत अच्छी बात एक उपयोग के मामले के लिए एक उदाहरण देती है जहां यह असुविधाजनक है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.