15

因此,我正在编写一个用于连接到外部帐户提供程序(Twitter、Facebook 等)的模块,并且我有一个自身无用的超类,但包含需要由子类调用以保留身份验证令牌的通用方法,获得验证令牌并取消对提供者的授权。我的问题是,有没有办法让它无法实例化,或者我应该遵循成年人同意的规则,让任何使用它的人犯他们认为合适的错误?除了文档字符串之外,还有一个好方法来表示某人不应该单独使用这个超类吗?

4

4 回答 4

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

如果他们愿意,这不会阻止人们重写该功能,但它应该是防止意外实例化的相当不错的方法。如果有人不小心调用了它,那么他们不能说你没有警告他们。

编辑:如果你真的想变得很好,你也可以向 stderr 打印一个__new__()关于它的警告,甚至抛出一个异常。

编辑2:如果你走异常路线,你可能想__init__()在超类的方法中引发异常,因为用户可能会__init__()在他们的子类中重写。

编辑 3:还有设置__new____init__等于的选项None,尽管由此产生的错误不会提供太多信息。

于 2011-06-06T18:51:19.407 回答
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 方法是清楚地记录类并不意味着被实例化。但也许有人会找到一种方法,这无论如何都是有用的——你永远不知道人们会以什么方式使用你的图书馆。

于 2011-06-06T19:07:42.317 回答
7

支持 Sven Marnach 的编辑:我认为您应该遵循“同意的成年人”规则并在文档字符串中提到该类不应该被实例化。

您问题中的关键词是“我有一个单独无用的超类”。实例化时不会调用 cthulhu;它不会在程序的其他地方导致某种灾难性的、难以调试的故障;这只是浪费时间。我认为,这不值得削弱班级。

于 2011-06-06T19:42:41.030 回答
4

您可以使用模块中的装饰abstractmethodabc将所有派生类覆盖的方法之一标记为抽象。

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

不过,我确实质疑班级组织。如果这个“超类”只不过是需要由子类调用的函数,为什么它不只是不同机制可以使用的模块呢?如果它是派生类完全实现的接口的定义(可能作为模板方法模式),那么抽象方法表示需要由派生类实现的函数。在那种情况下,我什至不会费心使基础不可构造,要么让人们通过工厂方法获得必要的派生,要么让用户在调用失败的函数时弄清楚。(不过,请在文档字符串中添加注释。)

于 2011-06-06T19:49:53.683 回答