webentwicklung-frage-antwort-db.com.de

Wie implementiere ich virtuelle Methoden in Python?

Ich kenne virtuelle Methoden aus PHP oder Java.

Wie können sie in Python implementiert werden?

Oder muss ich eine leere Methode in einer abstrakten Klasse definieren und sie überschreiben?

67
Meloun

Sicher, und Sie müssen nicht einmal eine Methode in der Basisklasse definieren. In Python Methoden sind besser als virtuell - sie sind völlig dynamisch, da die Eingabe in Python ist Duck Typing .

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 und Dog in Python müssen nicht einmal von einer gemeinsamen Basisklasse abgeleitet werden, um dieses Verhalten zuzulassen - Sie erhalten es kostenlos. Einige Programmierer bevorzugen es, ihre Klassenhierarchien strenger zu definieren, um sie besser zu dokumentieren und eine gewisse Strenge der Typisierung aufzuerlegen. Dies ist auch möglich (siehe zum Beispiel) das abc Standardmodul .

92
Eli Bendersky

Python-Methoden sind immer virtuell.

raise NotImplementedError()

Dies ist die empfohlene Ausnahme für "rein virtuelle Methoden" von "abstrakten" Basisklassen, die keine Methode implementieren.

https://docs.python.org/3.5/library/exceptions.html#NotImplementedError sagt:

Diese Ausnahme wird von RuntimeError abgeleitet. In benutzerdefinierten Basisklassen sollten abstrakte Methoden diese Ausnahme auslösen, wenn abgeleitete Klassen zum Überschreiben der Methode erforderlich sind.

Wie bereits erwähnt, handelt es sich meistens um eine Dokumentationskonvention, die nicht erforderlich ist. Auf diese Weise erhalten Sie jedoch eine aussagekräftigere Ausnahme als einen fehlenden Attributfehler.

Z.B.:

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()

gibt:

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

Verwandte: Ist es möglich, abstrakte Klassen in Python zu erstellen?

Tatsächlich stellt in Version 2.6 python) so etwas wie abstrakte Basisklassen bereit, und Sie können virtuelle Methoden wie diese explizit festlegen:

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

Es funktioniert sehr gut, vorausgesetzt, die Klasse erbt nicht von Klassen, die bereits Metaklassen verwenden.

quelle: http://docs.python.org/2/library/abc.html

19
user2795020

Python-Methoden sind immer virtuell

wie Ignacio schon sagte Irgendwie könnte die Klassenvererbung ein besserer Ansatz sein, um das zu implementieren, was Sie wollen.

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

Die Ergebnisse sollten sein:

I am an unknown animal
I am a dog named Rover
Rover has 4 legs
8
Jinzo

Python-Methoden sind immer virtuell.

... sofern sie nicht privat sind! Schade für einen C++ - Typen.

5
dplamp

Etwas wie eine virtuelle Methode in C++ (Aufrufen der Methodenimplementierung einer abgeleiteten Klasse durch einen Verweis oder Zeiger auf die Basisklasse) ist in Python nicht sinnvoll, da Python keine Typisierung hat. (Ich weiß jedoch nicht, wie virtuelle Methoden in Java und PHP funktionieren.)

Aber wenn Sie mit "virtuell" die unterste Implementierung in der Vererbungshierarchie bezeichnen, dann erhalten Sie das immer in Python, wie mehrere Antworten zeigen.

Na ja, fast immer ...

Wie dplamp hervorhob, verhalten sich nicht alle Methoden in Python. Dunder-Methode nicht. Und ich denke, das ist eine nicht so bekannte Funktion.

Betrachten Sie dieses künstliche Beispiel

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

Jetzt

>>> B().prop_b()
20
>>> A().prob_b()
10

Betrachten Sie jedoch dieses

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

Jetzt

>>> B().prop_b()
10
>>> A().prob_b()
10

Das einzige, was wir geändert haben, war, prop_a() zu einer Dunder-Methode zu machen.

Ein Problem mit dem ersten Verhalten kann sein, dass Sie das Verhalten von prop_a() in der abgeleiteten Klasse nicht ändern können, ohne das Verhalten von prop_b() zu beeinflussen. This very Nice talk von Raymond Hettinger gibt ein Beispiel für einen Anwendungsfall, bei dem dies unpraktisch ist.

2
Konstantin