Невероятный суперкласс - PullRequest
15 голосов
/ 06 июня 2011

Итак, я пишу модуль для подключения к внешним поставщикам учетных записей (Twitter, Facebook и т. Д.), И у меня есть суперкласс, который сам по себе бесполезен, но содержит общие методы, которые должны вызываться подклассами для сохранения аутентификации. токены, получение авторизационных токенов и деавторизация провайдера. Мой вопрос заключается в том, есть ли способ сделать его неосуществимым или я должен следовать правилу взрослых по обоюдному согласию и просто позволять любому, кто его использует, делать ошибки по своему усмотрению? Кроме строки документации, есть ли хороший способ указать, что кто-то не должен использовать этот суперкласс сам по себе?

Ответы [ 4 ]

7 голосов
/ 06 июня 2011

Основываясь на ответе JAB, было бы удобнее написать __new__(), например:

class NoInstantiation(object):
    def __new__(cls, *args, **kwargs):
        if cls is NoInstantiation:
            raise RuntimeError(
                "NoInstantiation isn't meant to be instantiated")
        else:
            return super(NoInstantiation, cls).__new__(cls, *args, **kwargs)

Таким образом, вам не нужно перезаписывать __new__() в производных классах.

Редактировать : я опубликовал этот ответ как улучшение ответа JAB, но я бы рекомендовал не использовать приведенный выше код.Это как-то намеренно наносит вред вашему классу.Обычный способ Python - четко документировать класс, который не предназначен для создания экземпляра.Но, возможно, кто-то найдет способ, как это полезно в любом случае - вы никогда не знаете, как люди будут использовать вашу библиотеку.

7 голосов
/ 06 июня 2011

Я поддерживаю Правка Свена Марнача : Я думаю, что вы должны следовать правилу "согласие взрослых" и упомянуть в документации, что класс не предназначен для создания экземпляра.

Ключевая фраза в вашем вопросе: «У меня есть суперкласс , который сам по себе бесполезен ».Он не призовет ктулху, когда будет создан экземпляр;это не вызовет какой-то катастрофический, трудно отлаживаемый сбой где-то еще в вашей программе;это будет просто пустая трата времени.Думаю, это не стоит наносить вред классу.

7 голосов
/ 06 июня 2011
class NoInstantiation:    # "class NoInstantiation(object):" in Python 2.2+ or whatever
    def __new__(cls):
        "This class is not meant to be instantiated, so __new__ returns None."
        return None

Это не остановит людей от переопределения этой функциональности, если они этого захотят, но это должен быть довольно приличный метод предотвращения случайной реализации.Если кто-то случайно позвонит, ну, они не могут сказать, что вы их не предупреждали.

РЕДАКТИРОВАТЬ: Если вы действительно хотите быть милым, вы можете также напечатать предупреждение для stderr в __new__() оэто или даже выбросить исключение.

РЕДАКТИРОВАТЬ 2: Если вы идете по маршруту исключения, вы можете вместо этого вызвать исключение в методе __init__() суперкласса, так как пользователи, вероятно, будут переопределять __init__()в любом случае в их подклассах.

РЕДАКТИРОВАТЬ 3: Существует также возможность установки __new__ или __init__ равной None, хотя результирующая ошибка не будет очень информативной.

4 голосов
/ 06 июня 2011

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

In [1]: import abc

In [2]: class C:
   ...:     __metaclass__ = abc.ABCMeta
   ...:     
   ...:     @abc.abstractmethod
   ...:     def my_abstract_method(self, *args) :
   ...:         pass
   ...:     
   ...:     

In [3]: c = C()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/home/afoglia/<ipython console> in <module>()

TypeError: Can't instantiate abstract class C with abstract methods my_abstract_method

Я делаювопрос организации класса, хотя.Если этот «суперкласс» есть не что иное, как функции, которые должны вызываться подклассами, почему это не просто модуль, который может использовать другой механизм?Если это определение интерфейса, который полностью реализуют производные классы (возможно, в виде шаблона шаблонного метода), то абстрактные методы представляют функции, которые должны быть реализованы производным классом.В этом случае я бы даже не стал делать базовую неконструктивную, и либо попросил бы людей получить необходимые производные с помощью фабричного метода, либо позволил бы пользователю выяснить это, когда он вызывает функцию, которая дает сбой.(Поместите комментарий в строки документации.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...