Znam metody wirtualne z PHP lub Java.
Jak można je zaimplementować w Pythonie?
A może muszę zdefiniować pustą metodę w klasie abstrakcyjnej i zastąpić ją?
python
virtual-functions
Meloun
źródło
źródło
raise NotImplementedError()
Jest to zalecany wyjątek dotyczący „czystych metod wirtualnych” „abstrakcyjnych” klas podstawowych, które nie implementują żadnej metody.
https://docs.python.org/3.5/library/exceptions.html#NotImplementedError mówi:
Jak powiedzieli inni, jest to głównie konwencja dokumentacji i nie jest wymagana, ale w ten sposób otrzymujesz bardziej znaczący wyjątek niż błąd brakującego atrybutu.
Na przykład:
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()
daje:
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
Powiązane: Czy można tworzyć klasy abstrakcyjne w Pythonie?
źródło
Metody Pythona są zawsze wirtualne.
źródło
W rzeczywistości w wersji 2.6 python udostępnia coś, co nazywa się abstrakcyjnymi klasami bazowymi i możesz jawnie ustawić metody wirtualne, takie jak ta:
from abc import ABCMeta from abc import abstractmethod ... class C: __metaclass__ = ABCMeta @abstractmethod def my_abstract_method(self, ...):
Działa bardzo dobrze, pod warunkiem, że klasa nie dziedziczy po klasach, które już używają metaklas.
źródło: http://docs.python.org/2/library/abc.html
źródło
jak Ignacio powiedział jeszcze, że dziedziczenie klas może być lepszym podejściem do implementacji tego, co chcesz.
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
Wyniki powinny być:
I am an unknown animal I am a dog named Rover Rover has 4 legs
źródło
Coś w rodzaju metody wirtualnej w C ++ (wywołanie implementacji metody klasy pochodnej przez odniesienie lub wskaźnik do klasy bazowej) nie ma sensu w Pythonie, ponieważ w Pythonie nie ma pisania. (Nie wiem jednak, jak działają metody wirtualne w Javie i PHP).
Ale jeśli przez „wirtualny” masz na myśli wywołanie najniższej implementacji w hierarchii dziedziczenia, to jest to to, co zawsze otrzymujesz w Pythonie, jak wskazuje kilka odpowiedzi.
Cóż, prawie zawsze ...
Jak zauważył dplamp, nie wszystkie metody w Pythonie zachowują się w ten sposób. Metoda Dunder nie. Myślę, że to niezbyt znana funkcja.
Rozważmy ten sztuczny przykład
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
Teraz
>>> B().prop_b() 20 >>> A().prob_b() 10
Jednak rozważ to
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
Teraz
>>> B().prop_b() 10 >>> A().prob_b() 10
Jedyną rzeczą, którą zmieniliśmy, było zrobienie
prop_a()
głupiej metody.Problem z pierwszym zachowaniem może polegać na tym, że nie można zmienić zachowania
prop_a()
w klasie pochodnej bez wpływu na zachowanieprop_b()
. Ta bardzo miła przemowa Raymonda Hettingera stanowi przykład zastosowania, w którym jest to niewygodne.źródło