Je connais les méthodes virtuelles de PHP ou Java.
Comment peuvent-ils être implémentés en Python?
Ou dois-je définir une méthode vide dans une classe abstraite et la remplacer?
la source
Je connais les méthodes virtuelles de PHP ou Java.
Comment peuvent-ils être implémentés en Python?
Ou dois-je définir une méthode vide dans une classe abstraite et la remplacer?
Bien sûr, et vous n'avez même pas besoin de définir une méthode dans la classe de base. En Python, les méthodes sont meilleures que virtuelles - elles sont complètement dynamiques, car le typage en Python est un typage canard .
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
et Dog
en Python, vous n'avez même pas besoin de dériver d'une classe de base commune pour autoriser ce comportement - vous l'obtenez gratuitement. Cela dit, certains programmeurs préfèrent définir leurs hiérarchies de classes de manière plus rigide pour mieux les documenter et imposer une certaine rigueur de frappe. Ceci est également possible - voir par exemple le abc
module standard .
raise NotImplementedError()
C'est l'exception recommandée à lever sur les «méthodes virtuelles pures» des classes de base «abstraites» qui n'implémentent pas de méthode.
https://docs.python.org/3.5/library/exceptions.html#NotImplementedError dit:
Comme d'autres l'ont dit, il s'agit principalement d'une convention de documentation et n'est pas obligatoire, mais de cette façon, vous obtenez une exception plus significative qu'une erreur d'attribut manquante.
Par exemple:
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()
donne:
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
Connexes: Est-il possible de créer des classes abstraites en Python?
la source
Les méthodes Python sont toujours virtuelles.
la source
En fait, dans la version 2.6, python fournit quelque chose appelé classes de base abstraites et vous pouvez définir explicitement des méthodes virtuelles comme celle-ci:
from abc import ABCMeta from abc import abstractmethod ... class C: __metaclass__ = ABCMeta @abstractmethod def my_abstract_method(self, ...):
Cela fonctionne très bien, à condition que la classe n'hérite pas des classes qui utilisent déjà des métaclasses.
source: http://docs.python.org/2/library/abc.html
la source
comme Ignacio l'a encore dit, l'héritage de classe peut être une meilleure approche pour implémenter ce que vous voulez.
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
Les résultats doivent être:
I am an unknown animal I am a dog named Rover Rover has 4 legs
la source
Quelque chose comme une méthode virtuelle en C ++ (appelant l'implémentation de méthode d'une classe dérivée via une référence ou un pointeur vers la classe de base) n'a pas de sens en Python, car Python n'a pas de typage. (Je ne sais pas comment les méthodes virtuelles fonctionnent en Java et PHP.)
Mais si par «virtuel» vous entendez appeler l'implémentation la plus basse dans la hiérarchie d'héritage, alors c'est ce que vous obtenez toujours en Python, comme le soulignent plusieurs réponses.
Eh bien, presque toujours ...
Comme dplamp l'a souligné, toutes les méthodes de Python ne se comportent pas comme ça. La méthode Dunder ne le fait pas. Et je pense que ce n'est pas une fonctionnalité très connue.
Prenons cet exemple artificiel
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
Maintenant
>>> B().prop_b() 20 >>> A().prob_b() 10
Cependant, considérez celui-ci
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
Maintenant
>>> B().prop_b() 10 >>> A().prob_b() 10
La seule chose que nous avons
prop_a()
modifiée a été de créer une méthode dunder.Un problème avec le premier comportement peut être que vous ne pouvez pas modifier le comportement de
prop_a()
dans la classe dérivée sans affecter le comportement deprop_b()
. Cette très belle présentation de Raymond Hettinger donne un exemple de cas d'utilisation où cela n'est pas pratique.la source