检查 self.__class__ 的目的是啥?

Posted

技术标签:

【中文标题】检查 self.__class__ 的目的是啥?【英文标题】:What is the purpose of checking self.__class__?检查 self.__class__ 的目的是什么? 【发布时间】:2014-01-03 03:53:40 【问题描述】:

检查self.__class__ 的目的是什么?我找到了一些创建抽象接口类的代码,然后检查它的self.__class__ 是否是它本身,例如

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

【问题讨论】:

我认为这需要更多的上下文。您在哪里“找到”此代码?它基本上坏了。 @Iguananaut:为什么坏了?当按预期使用时,它工作很好;作为一个抽象基类。 我很确定之前它是不同的东西?我不知道——我同意,现在那里的东西没有损坏。 【参考方案1】:

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

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

【讨论】:

尽管对于较新版本的 Python,应该只使用 abc.ABCMeta 的抽象基类。 ABC 仍然可以直接实例化。【参考方案2】:

线索在类名“abstract1”和错误中。这旨在成为一个抽象类,这意味着一个旨在被子类化的类。每个子类都将提供自己的行为。抽象类本身用于记录接口,即实现接口的类预期具有的方法和参数。它本身并不意味着实例化,并且测试用于判断我们是在类本身还是子类中。

请参阅 Julien Danjou 撰写的 article 中有关抽象类的部分。

【讨论】:

【参考方案3】:

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

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

【讨论】:

【参考方案4】:

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

对于abstract1 的实例,那将是abstract1本身,这是抽象类所不希望的。抽象类只是为了被子类化,而不是直接创建实例:

>>> 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__ 将是对特定子类的引用:

>>> class Foo(abstract1): pass
... 
>>> f = Foo()
>>> f.__class__
<class '__main__.Foo'>
>>> f.__class__ is Foo
True

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

请注意,测试实例类型的 pythonic 方法是使用 type() function,以及带有 is 运算符的 identity 测试:

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

type() 应该优先于self.__class__,因为后者是can be shadowed by a class attribute。

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

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

【讨论】:

【参考方案5】:

在 Python 3 中,使用 type() 检查类型或 __class__ 将返回相同的结果。

class C:pass
ci=C()
print(type(ci)) #<class '__main__.C'>
print(ci.__class__) #<class '__main__.C'>

我最近检查了implementation 中的@dataclass 装饰器(Raymond Hettinger 直接参与了该项目),他们使用__class__ 来指代类型。

所以使用__class__ 没有错 :)

【讨论】:

以上是关于检查 self.__class__ 的目的是啥?的主要内容,如果未能解决你的问题,请参考以下文章

python中的__init__(self)是啥意思呢

这个 Rnn 函数的最后一行是啥意思?

__init__(self) 在 Python 中是啥意思? [复制]

python class, __init__,self.

`__metaclass__ = type` 的目的是啥?

HexRays - “__OFSUB__()”的目的是啥?