Я хочу проверить, является ли объект экземпляром класса, и только этот класс (без подклассов). Я мог бы сделать это с помощью:
obj.__class__ == Foo
obj.__class__ is Foo
type(obj) == Foo
type(obj) is Foo
Есть ли причины выбирать один за другим? (различия в производительности, ловушки и т.д.)
Другими словами: а) существует ли какая-либо практическая разница между использованием __class__
и type(x)
? b) являются объектами класса, всегда безопасными для сравнения, используя is
?
Обновление: Спасибо всем за отзыв. Я все еще озадачен тем, являются ли объекты класса одиночными, мой здравый смысл говорит, что это так, но было действительно сложно получить подтверждение (попробуйте googling для "python", "class" и "unique" или "singleton" ).
Я также хотел бы пояснить, что для моих конкретных нужд лучшее "дешевое" решение, которое работает, является лучшим, поскольку я пытаюсь оптимизировать большинство из нескольких специализированных классов (почти достигая точки где разумная задача - сбросить Python и развить этот конкретный модуль на C). Но причина этого вопроса заключалась в том, чтобы лучше понять язык, поскольку некоторые из его функций немного неясны для меня, чтобы легко найти эту информацию. Вот почему я позволяю дискуссиям немного расшириться, а не поселиться за __class__ is
, поэтому я могу услышать мнение более опытных людей. Пока это было очень плодотворно!
Я провел небольшой тест, чтобы сравнить производительность 4 альтернатив. Результаты профилировщика были:
Python PyPy (4x)
type() is 2.138 2.594
__class__ is 2.185 2.437
type() == 2.213 2.625
__class__ == 2.271 2.453
Неудивительно, что is
работает лучше, чем ==
для всех случаев. type()
лучше работает на Python (на 2% быстрее) и __class__
лучше работает в PyPy (на 6% быстрее). Интересно отметить, что __class__ ==
лучше работает в PyPy, чем type() is
.
Обновление 2: многие люди, похоже, не понимают, что я имею в виду, когда "класс является одноэлементным", поэтому я приведу пример:
>>> class Foo(object): pass
...
>>> X = Foo
>>> class Foo(object): pass
...
>>> X == Foo
False
>>> isinstance(X(), Foo)
False
>>> isinstance(Foo(), X)
False
>>> x = type('Foo', (object,), dict())
>>> y = type('Foo', (object,), dict())
>>> x == y
False
>>> isinstance(x(), y)
False
>>> y = copy.copy(x)
>>> x == y
True
>>> x is y
True
>>> isinstance(x(), y)
True
>>> y = copy.deepcopy(x)
>>> x == y
True
>>> x is y
True
>>> isinstance(x(), y)
True
Не имеет значения, есть ли N объектов типа type
, заданных объектом, только один будет его классом, поэтому в этом случае безопасно сравнивать для справки. И поскольку сравнение ссылок всегда будет дешевле сравнения значений, я хотел бы знать, действительно ли мое утверждение выше. Я пришел к выводу, что это так, если только кто-то не докажет доказательства.