检查 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__ 的目的是啥?的主要内容,如果未能解决你的问题,请参考以下文章