因此,我正在编写一个用于连接到外部帐户提供程序(Twitter、Facebook 等)的模块,并且我有一个自身无用的超类,但包含需要由子类调用以保留身份验证令牌的通用方法,获得验证令牌并取消对提供者的授权。我的问题是,有没有办法让它无法实例化,或者我应该遵循成年人同意的规则,让任何使用它的人犯他们认为合适的错误?除了文档字符串之外,还有一个好方法来表示某人不应该单独使用这个超类吗?
4 回答
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
,尽管由此产生的错误不会提供太多信息。
基于 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 方法是清楚地记录类并不意味着被实例化。但也许有人会找到一种方法,这无论如何都是有用的——你永远不知道人们会以什么方式使用你的图书馆。
我支持 Sven Marnach 的编辑:我认为您应该遵循“同意的成年人”规则并在文档字符串中提到该类不应该被实例化。
您问题中的关键词是“我有一个单独无用的超类”。实例化时不会调用 cthulhu;它不会在程序的其他地方导致某种灾难性的、难以调试的故障;这只是浪费时间。我认为,这不值得削弱班级。
您可以使用模块中的装饰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
不过,我确实质疑班级组织。如果这个“超类”只不过是需要由子类调用的函数,为什么它不只是不同机制可以使用的模块呢?如果它是派生类完全实现的接口的定义(可能作为模板方法模式),那么抽象方法表示需要由派生类实现的函数。在那种情况下,我什至不会费心使基础不可构造,要么让人们通过工厂方法获得必要的派生,要么让用户在调用失败的函数时弄清楚。(不过,请在文档字符串中添加注释。)