Какова цель проверки self.__ class__? - python

Какова цель проверки 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

Ответ 1

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 другом месте вашего кода, это защищает вас от глупых ошибок.

Обратите внимание, что питонический способ проверки типа экземпляра состоит в том, чтобы вместо этого использовать функцию type() вместе с проверкой идентичности с оператором is:

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

type() должен быть предпочтительнее, чем self.__class__ поскольку последний может быть self.__class__ атрибутом class.

Здесь нет смысла использовать тест на равенство, как для пользовательских классов, в __eq__ в основном реализован как тест на идентичность.

Python также включает в себя стандартную библиотеку для определения абстрактных базовых классов, которая называется abc. Он позволяет пометить методы и свойства как абстрактные и откажется создавать экземпляры любого подкласса, который еще не переопределил эти имена.

Ответ 2

В коде, который вы там разместили, нет-op; self.__class__ == c1 не является частью условного выражения, поэтому логическое значение вычисляется, но результат не выполняется.

Вы можете попытаться создать абстрактный базовый класс, который проверяет, соответствует ли self.__class__ абстрактному классу, а не гипотетическому дочернему элементу (через оператор if), чтобы предотвратить создание абстрактного базового класса из-за ошибки разработчика.

Ответ 3

Я бы сказал, что некоторые будут делать:

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

Даже когда база абстрактна, вы не хотите, чтобы база __init__ бросала NotImplementedError. Эй, может, он даже делает что-то полезное?

Ответ 4

Какова цель этого? Нужно ли проверять, является ли этот класс самим типом?

Да, если вы попытаетесь построить объект типа Abstract1, он выкинет это исключение, сообщив вам, что вам не разрешено это делать.

Ответ 5

Ключи находятся в имени класса, "abstract1" и в ошибке. Это предназначено для абстрактного класса, означающего тот, который предназначен для подкласса. Каждый подкласс будет обеспечивать свое собственное поведение. Сам абстрактный класс служит для документирования интерфейса, то есть методов и аргументов, которые, как ожидается, будут иметь классы, реализующие интерфейс. Он не предназначен для создания самого себя, и тест используется для определения того, находимся ли мы в самом классе или подклассе.

См. раздел "Абстрактные классы" в этой статье статьи от Julien Danjou.

Ответ 6

В Python 3 либо использование type() для проверки типа, либо __class__ вернет тот же результат.

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

Недавно я проверил реализацию декоратора @dataclass (Раймон Хеттингер непосредственно участвует в этом проекте), и они используют __class__ для ссылки на тип.

Так что это не неправильно использовать __class__ :)