python关于class:检查self.__ class__的目的是什么?

What is the purpose of checking self.__class__ ? - python

检查self.__class__的目的是什么?我发现了一些创建抽象接口类的代码,然后检查它的self.__class__是否是自己的,例如。

1
2
3
4
class abstract1 (object):
  def __init__(self):
    if self.__class__ == abstract1:
      raise NotImplementedError("Interfaces can't be instantiated")

这样做的目的是什么?是否检查类是否是其自身的类型?

代码来自nltk的http://nltk.googlecode.com/svn/trunk/doc/api/nltk.probability pysrc.html probdisti


self.__class__是对当前实例类型的引用。

对于Abstract1的实例,这将是Abstract1类本身,这是抽象类所不需要的。抽象类只用于子类,而不是直接创建实例:

1
2
3
4
5
>>> abstract1()
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
  File"<stdin>", line 4, in __init__
NotImplementedError: Interfaces can't be instantiated

对于Abstract1的一个子类,self.__class__将是对特定子类的引用:

1
2
3
4
5
6
7
>>> class Foo(abstract1): pass
...
>>> f = Foo()
>>> f.__class__
<class '__main__.Foo'>
>>> f.__class__ is Foo
True

在这里抛出异常就像在代码的其他地方使用assert语句,它可以保护您不犯愚蠢的错误。

注意,测试实例类型的方法是使用type()函数,并使用is运算符进行身份测试:

1
2
3
4
class abstract1(object):
    def __init__(self):
        if type(self) is abstract1:
            raise NotImplementedError("Interfaces can't be instantiated")

应优先选择type()而不是self.__class__,因为后者可以由类属性隐藏。

对于自定义类,在这里使用相等测试没有什么意义,__eq__基本上是作为身份测试实现的。

python还包括一个定义抽象基类的标准库,称为abc。它允许您将方法和属性标记为抽象的,并拒绝创建尚未重新定义这些名称的任何子类的实例。


What is the purpose of that? Is it to check whether the class is a type of itself?

是的,如果您试图构造一个Abstract1类型的对象,它会抛出一个异常,告诉您不允许这样做。


我想说有些人会这样做:

1
2
3
4
class Foo(AbstractBase):
    def __init__(self):
        super(Foo, self).__init__()
        # ...

即使基是抽象的,也不希望基的__init__抛出NotImplementedError。嘿,也许它还能起到什么作用?


您在那里发布的代码没有操作;self.__class__ == c1不是条件的一部分,因此将对布尔值进行计算,但不会对结果进行任何处理。

您可以尝试创建一个抽象基类,该类检查self.__class__是否等于抽象类,而不是假设的子类(通过if语句),以防止由于开发人员错误而实例化抽象基类本身。


线索在类的名称"abstract1"和错误中。这是一个抽象类,意思是一个打算被子类化的类。每个子类将提供自己的行为。抽象类本身用于记录接口,即实现接口的类应该具有的方法和参数。它并不打算被实例化,测试用来判断我们是在类本身中还是在子类中。

参见Julien Danjou在本文中关于抽象类的部分。