2014-10-18 4 views
1

Как я понимаю, я могу использовать модуль abc в Python для создания абстрактных классов, которые не могут быть созданы (среди других приятных свойств). Я попытался использовать это, чтобы создать иерархию классов Exception для представления различных кодов выхода для моего приложения, но я все еще могу создать экземпляр базового класса, хотя я не хочу, чтобы это произошло. Вот код, который демонстрирует проблему:Почему я могу создать экземпляр базового класса в Python?

#!/usr/bin/env python3 

import abc 

class ExitCodeException(Exception): 
    __metaclass__ = abc.ABCMeta 

    def __init__(self, message): 
     super().__init__() 
     self._message = message 

    @abc.abstractmethod 
    def getExitCode(self): 
     """Return the exit code for this exception""" 
     return 

class FatalException(ExitCodeException): 
    def getExitCode(self): 
     return 1 

raise ExitCodeException("Oh no!") 

я ожидал мою программу, чтобы бросить курить с исключением, говоря, что ExitCodeException не может быть реализована, но вместо этого я просто получить стандартные трассировки стеки, я бы ожидать, если ExitCodeException weren 't аннотация:

Traceback (most recent call last) 
    File "./email2pdf_classexception", line 21, in <module> 
    raise ExitCodeException("Oh no!") 
__main__.ExitCodeException 

Как это исправить?

+3

В Python3 вы должны использовать синтаксис ключевых слов: 'class ExitCodeException (Exception, metaclass = abc.ABCMeta):'. Однако этого недостаточно, чтобы исправить вашу проблему. Базовый класс «Исключение» делает возможным создание экземпляра - без него все работает так, как ожидалось. Но я полагаю, что это не решает вашу проблему, так как вы хотите получить исключающие исключения из этого базового класса. – BartoszKP

+2

Во-первых, синтаксис определения метакласса был изменен в Python3. Он должен быть передан как аргумент ключевого слова (называемый «метакласс») для определения класса (ref: https://docs.python.org/3.3/reference/datamodel.html#customizing-class-creation). Во-вторых, у меня ABC не может быть базовый класс, который не является ABC. Таким образом, вы не можете иметь «Исключение» (которое не является ABC) в качестве базового класса «ExitCodeException», если вы хотите сделать «ExitCodeException» ABC. Итак, я не думаю, что есть прямой способ заставить ваш код работать. –

+1

Почему важно не создавать экземпляр базового класса? Если вы не хотите создавать экземпляр, просто не создавайте экземпляр. Это похоже на попытку написать Java в Python. –

ответ

2

Как обсуждалось в комментариях @BartoszKP и @Debanshu Kundu выше, кажется, что конкретный суперкласс Exception является причиной этой проблемы. Таким образом, я придумал несколько иного узор, который, кажется, работает (как я понимаю, это старый-стиль шаблона из Python 2, но по-прежнему кажется действительным):

#!/usr/bin/env python3 

class ExitCodeException(Exception): 
    def __new__(cls, *args, **kwargs): 
     if cls is ExitCodeException: 
      raise NotImplementedError("Base class may not be instantiated") 
     return Exception.__new__(cls, *args, **kwargs) 

    def __init__(self, message): 
     super().__init__() 
     self._message = message 

    def getExitCode(self): 
     """Return the exit code for this exception""" 
     return 

class FatalException(ExitCodeException): 
    def getExitCode(self): 
     return 1 

raise FatalException("Oh no!") 

это работает как предполагалось; если я изменил код, чтобы создать экземпляр ExitCodeException, он не работает.