Я знаю виртуальные методы из PHP или Java.
Как их можно реализовать в Python?
Или мне нужно определить пустой метод в абстрактном классе и переопределить его?
python
virtual-functions
Мелун
источник
источник
raise NotImplementedError()
Это рекомендуемое исключение для «чистых виртуальных методов» «абстрактных» базовых классов, которые не реализуют метод.
https://docs.python.org/3.5/library/exceptions.html#NotImplementedError говорит:
Как говорили другие, это в основном соглашение о документации и не требуется, но таким образом вы получаете более значимое исключение, чем ошибка отсутствия атрибута.
Например:
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
Связанный: Можно ли создавать абстрактные классы в Python?
источник
Методы Python всегда виртуальны.
источник
Фактически, в версии 2.6 python предоставляет нечто, называемое абстрактными базовыми классами, и вы можете явно установить виртуальные методы следующим образом:
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
источник
как сказал Игнасио, но каким-то образом наследование классов может быть лучшим подходом для реализации того, что вы хотите.
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 ++ (реализация метода вызова производного класса через ссылку или указатель на базовый класс) не имеет смысла в Python, поскольку Python не имеет типизации. (Однако я не знаю, как виртуальные методы работают в Java и PHP.)
Но если под «виртуальным» вы подразумеваете вызов самой нижней реализации в иерархии наследования, то это то, что вы всегда получаете в Python, как указано в нескольких ответах.
Ну почти всегда ...
Как указал dplamp, не все методы в Python ведут себя так. Метод Дандера - нет. И я думаю, что это не очень известная особенность.
Рассмотрим этот искусственный пример
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()
. В этом прекрасном выступлении Раймонда Хеттингера приводится пример использования, в котором это неудобно.источник