Как реализовать виртуальные методы в Python?


Я знаю виртуальные методы из PHP или Java.

как они могут быть реализованы в Python?

или я должен определить пустой метод в абстрактном классе и переопределить его?

6 52

6 ответов:

конечно, и вам даже не нужно определять метод в базовом классе. В Python методы лучше, чем виртуальные - они полностью динамичны, так как ввод в Python утиной типизацией.

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 в Python даже не нужно выводить из общего базового класса, чтобы разрешить это поведение - вы получаете его бесплатно. Тем не менее, некоторые программисты предпочитают определять свои иерархии классов более жестким способом, чтобы лучше документировать его и накладывать некоторые строгость типизации. Это также возможно-см. например abc стандартный модуль.

методы 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

NotImplementedError

это рекомендуемое исключение для создания "чистых виртуальных методов" "абстрактных" базовых классов, которые не реализуют метод.

как говорили другие, это в основном соглашение о документации и не требуется, но таким образом вы получаете более значимое исключение, чем ошибка отсутствующего атрибута.

https://docs.python.org/3.5/library/exceptions.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

по теме: можно ли сделать абстрактные классы в Python?

методы Python всегда виртуальны

как Игнасио сказал еще Каким-то образом наследование классов может быть лучшим подходом к реализации того, что вы хотите.

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

методы Python всегда виртуальны.

...при условии, что они не являются частными ! Слишком плохо для парня с++.