Мимические Python (чистые) виртуальные функции, такие как C #

Как лучше всего в Python имитировать виртуальные и чистые виртуальные функции, например, в C #?

В настоящее время я использую схему типа:

class AbstractClass(object): '''Abstract class''' def __init__(self): assert False, 'Class cannot be instantiated' def _virtual_init(self): print 'Base "constructor"' def pure_virtual_function(self): assert False, 'Pure virtual function should be derived' def virtual_function(self): print 'Base: virtual function' class Derived1(AbstractClass): '''All functions derived''' def __init__(self): print 'Derived1: constructor' AbstractClass._virtual_init(self) def pure_virtual_function(self): print 'Derived1: pure virtual function' def virtual_function(self): print 'Derived1: virtual function' class Derived2(AbstractClass): '''Pure virtual method missing.''' def __init__(self): print 'Derived2: constructor' AbstractClass._virtual_init(self) def virtual_function(self): print 'Derived3: virtual function' class Derived3(AbstractClass): '''Virtual method missing (use base class)''' def __init__(self): print 'Derived3: constructor' AbstractClass._virtual_init(self) def pure_virtual_function(self): print 'Derived3: pure virtual function' # ab = AbstractClass() # Gives error -> OK print 'DERIVED 1' dv1 = Derived1() dv1.pure_virtual_function() dv1.virtual_function() print 'DERIVED 2' dv2 = Derived2() # dv2.pure_virtual_function() # Gives error: Pure virtual function should be derived -> OK dv2.virtual_function() print 'DERIVED 3' dv3 = Derived3() # dv3.pure_virtual_function() # Gives error: Pure virtual function should be derived -> OK dv3.virtual_function() 

Я получаю вывод:

 DERIVED 1 Derived1: constructor Base "constructor" Derived1: pure virtual function Derived1: virtual function DERIVED 2 Derived2: constructor Base "constructor" Derived3: virtual function DERIVED 3 Derived3: constructor Base "constructor" Derived3: pure virtual function Base: virtual function 

Однако мои конкретные вопросы:

  1. Есть ли более элегантный способ определения абстрактного базового класса в Python (2.7)? Вышеприведенное решение дает ошибку во время выполнения (например, с pylint). В Python afaik нет ключевого слова abstract.
  2. Есть ли более элегантный способ определения чистого виртуального метода в Python (2.7)? Опять же, приведенное выше решение дает только ошибку во время выполнения.
  3. Есть ли более элегантный способ определения виртуального метода в Python (2.7)? Проверка не требуется, но в Python afaik нет ключевого слова типа «virtual».

Заранее спасибо.

Я не уверен, что именно вы имеете в виду, когда вы спрашиваете о виртуальных методах, как в Python все методы являются виртуальными. И я также не уверен, почему вы используете _virtual_init вместо __init__ … просто переименование метода купите вам что-то?

Обновление: Ах, у меня есть идея. Вероятно, вы сделали это, чтобы запретить создание базового класса, сохраняя при этом инициализацию. Ответ здесь: форсирование вещей не является питоническим . Просто напишите, что этот класс является абстрактным (и, вероятно, называть его AbstractSmth ).

Говоря о ошибках времени выполнения. Python – динамический язык, так что, вот как это работает. Общая идиома поднимает NotImplementedError в __init__ чтобы показать, что ваш класс является абстрактным (и то же самое верно для абстрактных (чисто виртуальных) методов). Вы также можете взглянуть на abc поскольку он делает то, что вы хотите: он запрещает создание абстрактных классов. Но я также настоятельно рекомендую прочитать PEP-3119, чтобы понять, что такое абстрактные базовые классы , а какие нет .

AFAIK, повышение NotImplementedError достаточно для pylint, чтобы понять, что ваш класс / метод является абстрактным.

 class AbstractBaseClass(object): def __init__(self): if self.__class__.__name__ == 'AbstractBaseClass': raise NotImplementedError("Can't instantiate AbstractBaseClass") class DerivedClass(AbstractBaseClass): def __init__(self): super().__init__() # ... 

В этом примере показано, что производные классы (имеющие другой __class__.__name__ ) могут быть созданы и наследовать атрибуты, предоставленные AbstractBaseClass. Но если AbstractBaseClass получает экземпляр напрямую, исключение NotImplementedError будет NotImplementedError .