不可安装的超类

时间:2011-06-06 18:48:16

标签: python superclass

所以,我正在编写一个连接外部帐户提供程序(Twitter,Facebook等)的模块,我有一个单独使用的超类,但包含需要由子类调用以保持身份验证的泛型方法令牌,获取身份验证令牌和取消授权提供商。我的问题是,有没有办法让它不可安装,或者我应该遵循同意的成年人规则,只是让任何使用它的人在他们认为合适时犯错误?除了文档字符串之外,还有一种很好的方法可以表明某人不应该单独使用这个超类吗?

4 个答案:

答案 0 :(得分:7)

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

如果他们愿意,这不会阻止人们覆盖该功能,但它应该是一种防止意外实例化的相当不错的方法。如果有人不小心打电话给他们,他们就不能说你没有警告他们。

编辑:如果你真的想要变得更好,你也可以在__new__()中向stderr发出警告,甚至抛出异常。

编辑2:如果你去了异常路由,你可能想要在超类的__init__()方法中引发异常,因为用户可能会在子类中覆盖__init__()。< / p>

编辑3:还可以选择将__new____init__设置为None,但产生的错误信息不会很丰富。

答案 1 :(得分:7)

在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方法是清楚地记录该类并不意味着实现。但也许有人找到了一种方法,无论如何这都是有用的 - 你永远不知道人们将以何种方式使用你的图书馆。

答案 2 :(得分:7)

我正在考虑Sven Marnach's edit:我认为你应该遵循“同意大人”的规则,并在文档字符串中提到该类不是要实例化的。

你问题中的关键词是“我有一个超级,它本身没用”。“实例化时不会调用cthulhu;它不会在你的程序中的其他地方造成某种灾难性的,难以调试的失败;这只是浪费时间。我认为,这不值得为这个课程造成严重损失。

答案 3 :(得分:4)

您可以使用abc模块中的abstractmethod decorator来标记所有派生类重写为抽象的方法之一。

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

我确实质疑班级组织。如果这个“超类”只是需要由子类调用的函数,为什么它不仅仅是一个不同机制可以使用的模块?如果它是派生类完全实现的接口的定义(可能作为模板方法模式),那么抽象方法表示需要由派生类给出实现的函数。在这种情况下,我甚至不打算使基础不可构造,并且让人们通过工厂方法得到必要的派生,或让用户在调用失败的函数时弄清楚它。 (尽管在文档字符串中发表评论。)