Python 不可标超类

Python 不可标超类,python,superclass,Python,Superclass,因此,我正在编写一个用于连接外部帐户提供商(Twitter、Facebook等)的模块,我有一个超类,它本身是无用的,但包含子类需要调用的通用方法,用于持久化身份验证令牌、获取身份验证令牌和取消对提供商的身份验证。我的问题是,有没有办法让它变得不可辩驳,或者我应该遵循成年人同意的规则,让任何使用它的人在他们认为合适的时候犯错误?除了docstring之外,有没有一种好的方法来表示某人不应该单独使用这个超类 class NoInstantiation: # "class NoInstanti

因此,我正在编写一个用于连接外部帐户提供商(Twitter、Facebook等)的模块,我有一个超类,它本身是无用的,但包含子类需要调用的通用方法,用于持久化身份验证令牌、获取身份验证令牌和取消对提供商的身份验证。我的问题是,有没有办法让它变得不可辩驳,或者我应该遵循成年人同意的规则,让任何使用它的人在他们认为合适的时候犯错误?除了docstring之外,有没有一种好的方法来表示某人不应该单独使用这个超类

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

编辑:如果你真的想表现得好一点,你也可以在
\uu new\uu()
中向stderr打印一条关于它的警告,甚至抛出一个异常

编辑2:如果您选择异常路径,您可能希望在超类的
\uuuuu init\uuu()
方法中引发异常,因为用户很可能会覆盖其子类中的
\uuuuu init\uuuu()


编辑3:还有一个选项,可以将
\uuuuuuuuuuuuu
\uuuuuuu init\uuuuuuu
设置为等于
,尽管结果错误的信息量不大。

基于JAB的答案,编写
\uuuuuuuuuuuuuuuuuuuuuuuu()
可能更方便:

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)
这样,您就不需要在派生类中覆盖
\uuuu new\uuuu()

编辑:我发布了这个答案,作为JAB答案的改进,但我建议不要实际使用上述代码。不知何故,这是故意让你的班级瘫痪。Python通常的方法是清楚地记录类,而不是将其安装。但也许有人找到了一种方法,不管怎样,这是多么有用——你永远不知道人们会以什么方式使用你的库。

我附议:我认为你应该遵循“成年人同意”规则,并在文档字符串中提到该类不应该被实例化

你问题中的关键短语是“我有一个本身无用的超类”,它在实例化时不会调用cthulhu;它不会在程序的其他地方导致灾难性的、难以调试的失败;这只不过是浪费时间而已。我认为,这不值得让全班都瘫痪

您可以使用
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
[1]中的
:导入abc
在[2]中:C类:
…:\uuuu元类\uuuu=abc.ABCMeta
...:     
…:@abc.abstractmethod
…:def my_abstract_方法(self,*args):
…:通过
...:     
...:     
在[3]中:c=c()
---------------------------------------------------------------------------
TypeError回溯(最近一次调用上次)
/家/阿富利亚/在()
TypeError:无法使用抽象方法my_abstract_方法实例化抽象类C

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

1。这在Python2.x中不起作用
\uuuu new\uuuu()
仅对新样式的类调用,因此您必须从
对象
派生。2.您应该引发错误,而不是返回
None
。3.这要求所有派生类都覆盖
\uuuuu new\uuuuuu()
,这似乎不是很方便。@Sven:啊,对了,我记下了Python 2。至于要求所有派生类覆盖
\uuuuu new\uuuuu()
。。。它只需要调用
对象。不过,我会记下另一种方法。@JAB:如果
NoInstantiation
有基类,您可能需要调用其中一个基类的
\uuu new\uu()
方法,这在ar派生类中可能很难理解。我建议您采用引发错误的方法。根据我的经验,打印的警告信息无效。最好在编辑2中提到的
\uuuu init\uuuu
上执行。@JAB:我发布了一个如何改进的建议。我第一次尝试在评论中加入这一点,但没有成功:)如果我必须选择一个“可接受的答案”,我会选择这个!我喜欢所有其他的答案,但它们似乎太不和谐了。我认为@senderle是对的。我会把信息放在文档字符串中,希望人们花时间阅读。我同意,我不认为这是真正的“Pythonic”方法。Python,至少在最初的构思中,非常相信“我们都是同意的成年人”的心态。阅读Von Rossum关于强类型和弱类型的原始陈述——他拒绝类型化参数背后的理由是“如果有人想滥用代码,那就是他们的问题。”我的建议是:在其中放一个print语句,说“这个类本身通常是无用的。使用时要自担风险。”(除了docstring之外)@cWallenPole:Python是强类型的。你的意思可能是“静态类型vs.动态类型”。仅仅用python声明类抽象真的不可能吗?@bjaref:你看过AFoglia的答案吗?你可能是对的,我可能想重新考虑类结构,但我不确定。超类既有需要重写的方法,也有需要重写的方法