Почему тип (classInstance) возвращает «экземпляр»?

У меня есть метод, который принимает параметр, который может быть нескольких типов, и должен делать то или иное действие в зависимости от типа, но если я проверю тип указанного параметра, я не получу "настоящий" тип, я всегда получаю <type 'instance'>, и это мешает моим сравнениям.

У меня есть что-то вроде:

from classes import Class1
from classes import Class2
# Both classes are declared in the same file.
# I don't know if that can be a problem         #
# ... #
def foo(parameter)
    if (type(parameter) == type(Class1()):
    # ... #
    elif (type(parameter) == type(Class2()):
    # ... #

А так как type(parameter) возвращает <type 'instance'>, а type(Class1()) также равно <type 'instance'>, получается, что даже если параметр является экземпляром Class2, он попадает в первое сравнение...

Кстати, str(parameter.__class__) правильно показывает classes.Class1 . Я думаю, что всегда мог бы использовать это, но я хотел бы понять, что происходит... Я сделал десятки подобных сравнений, и все они работали правильно...

Спасибо!! :)


person BorrajaX    schedule 24.06.2010    source источник


Ответы (3)


Классы старого стиля делают это. Выведите свои классы из object в их определениях.

person Ignacio Vazquez-Abrams    schedule 24.06.2010
comment
Ууу... Это работает! :) Теперь я попытаюсь выяснить, почему... :D - person BorrajaX; 24.06.2010
comment
Это связано с тем, что классы нового стиля имеют больше метаданных, включая то, что касается type(). - person Ignacio Vazquez-Abrams; 24.06.2010
comment
Еще раз спасибо, я читал это: cafepy.com/article/python_types_and_objects/ И я как бы (вроде) понял, что что-то вроде этого должно быть причиной - person BorrajaX; 24.06.2010

вы действительно должны использовать isinstance:

In [26]: def foo(param):
   ....:     print type(param)
   ....:     print isinstance(param, Class1)
   ....:

In [27]: foo(x)
<type 'instance'>
True

Тип лучше для встроенных типов.

person Wayne Werner    schedule 24.06.2010
comment
Ву! Спасибо за очень быстрый ответ... Я думал об этом, но потом прочитал это: canonical. org/~kragen/isinstance И я струсил... :S Хотя должен сказать, что, с другой стороны, 'isinstance' может подойти для моих нужд... - person BorrajaX; 24.06.2010
comment
isinstance, безусловно, обычно предпочтительнее прямой проверки type(), и определенно форма проверки типов, которую вы используете, где вы фактически создаете экземпляр Class1() для каждой проверки, нежелательна. Однако в этой статье говорится, что во многих случаях проверка типов вообще (какой бы метод вы для этого ни использовали) является признаком плохой практики кодирования. IMO, статья бесполезно религиозна, и для проверки типов все еще есть допустимые способы использования, но если вы выполняете «десятки» проверок своих собственных определенных типов, это звучит как потенциальный «недостаточно объектно-ориентированный» запах кода. - person bobince; 24.06.2010
comment
Вы можете ясно видеть в коде Ops, почему проверка типов означает, что вы не делаете ООП: какой бы код ни следовал после if isinstace( obj, Cls), он должен быть в методе Cls. Это может показаться религиозным, но если вы хотите использовать ООП (не то, чтобы вы должны это делать), вы должны правильно по крайней мере это понять. - person Jochen Ritzel; 24.06.2010
comment
Ну... То, что я написал, было простым примером, чтобы было как можно понятнее, но дело в том, что я действительно могу получить (в качестве параметра) объект Class1 или список объектов Class1 (а затем пройтись по list и рекурсивно вызвать метод, чтобы он вел себя так, как если бы был получен один объект) или объект, который не является Class1, но имеет значения, которые позволяют мне инициализировать объект Class1 и снова вызывать метод с этим экземпляром Class1 и т. д. Это почему мне нужно проверить тип - person BorrajaX; 24.06.2010
comment
@BorrajaX это не лучше, вместо этого этот метод и все подобные должны всегда принимать и возвращать списки Class1. Иногда в списках есть только один элемент, поэтому они могут выглядеть бессмысленными, но интерфейс остается прежним, и в этом суть ООП. - person Jochen Ritzel; 25.06.2010
comment
Но могу ли я иметь два метода с одинаковыми именами в одном классе в Python? Поскольку у него нет четко определенных типов, я понимаю, что я не могу сделать, как в Java: class foo{ void method(int a){} void method(String b){} } и единственный способ, которым я нашел получить аналогичное поведение - выполнить проверку типа вручную внутри метода - person BorrajaX; 25.06.2010
comment
@BorrajaX, это довольно старо, но если вы хотите перегрузить функцию, вы можете сделать это, взяв **kwargs, или вы можете сделать комбинацию *args и **kwargs. Однако это довольно хакерски, когда вы действительно хотите, вероятно, просто сделать что-то еще... - person Wayne Werner; 05.08.2014

Тот факт, что type(x) возвращает объект одного и того же типа для всех экземпляров x устаревших классов, также известных как классы старого стиля, является одним из многих приводящих в бешенство дефектов таких классов — к сожалению, они должны остаться (и использоваться по умолчанию для класса без base) в Python 2.* по соображениям обратной совместимости.

Тем не менее, не используйте классы в старом стиле, если только вы не вынуждены поддерживать кучу старого, унаследованного кода (без хорошего набора тестов, который даст вам уверенность, чтобы попытаться переключиться на другие классы). . Когда класс не имеет «естественных» оснований, создайте подкласс из object, а не из ничего. Кроме того, ваш модуль вверху может установить

__metaclass__ = type

который изменяет значение по умолчанию с грубых, устаревших классов старого стиля на блестящие яркие классы нового стиля — хотя явное наследование от object обычно предпочтительнее («явное лучше, чем неявное»), глобальная настройка модуля __metaclass__ может чувствовать себя «менее инвазивным» по отношению к существующим старым модулям, где вы переключаетесь со старых на новые классы, поэтому это предлагается как возможность.

person Alex Martelli    schedule 24.06.2010
comment
Спасибо! Тоже хороший ответ! Я уже использовал тот, который предложил Игнасио. но ладно... в конце концов, если я правильно понимаю, они очень похожи, верно? - person BorrajaX; 25.06.2010
comment
@Borrajax, конечный результат явного наследования от object по сравнению с отсутствием наследования и наличием глобального модуля __metaclass__=type точно такой же - очень разные стили, неотличимые результаты. - person Alex Martelli; 26.06.2010