检查自我.__ class__的目的是什么? - 蟒蛇

时间:2013-12-15 20:27:35

标签: python class oop interface self

检查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

6 个答案:

答案 0 :(得分:22)

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

对于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代替{em>身份测试can be shadowed by a class attribute 1}} operator:

is

class abstract1(object): def __init__(self): if type(self) is abstract1: raise NotImplementedError("Interfaces can't be instantiated") 应优先于type(),因为后者abc

对于自定义类,使用等式测试没有什么意义,self.__class__基本上都是作为身份测试实现的。

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

答案 1 :(得分:1)

你在那里发布的代码是no-op; self.__class__ == c1不是条件的一部分,因此对布尔值进行了求值,但结果没有做任何事情。

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

答案 2 :(得分:1)

我会说有些人会这样做:

class Foo(AbstractBase):
    def __init__(self):
        super(Foo, self).__init__()
        # ...

即使基础是抽象的,你也不希望基数的__init__抛出NotImplementedError。嘿,也许它甚至做了一些有用的事情?

答案 3 :(得分:1)

  

那是什么目的?是要检查这个类是否属于它自己的类型?

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

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

在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__:)

并没有错。