2014-02-19 5 views
21

Вопрос о семантике, действительно.isinstance (foo, bar) vs type (foo) is bar

До недавнего времени, если бы мне пришлось выполнять какую-либо проверку типов на структуре, я бы использовал type(obj) is list et. и др. Однако после вступления в СО я заметил всех (и я имею в виду EVERYONE) вместо этого использует isinstance(obj,list). Кажется, они синонимы, и timeit показывает почти ИДЕНТИЧНУЮ скорость между ними.

def a(): return type(list()) is list 
def b(): return isinstance(list(),list) 

from timeit import timeit 
timeit(a) 
# 0.5239454597495582 
timeit(b) 
# 0.5021292075273176 

Действительно, даже dis соглашается они синонимичны, за исключением type is «s COMPARE_OP

from dis import dis 

dis(a) 
# 2   0 LOAD_GLOBAL    0 (type) 
#    3 LOAD_GLOBAL    1 (list) 
#    6 CALL_FUNCTION   0 (0 positional, 0 keyword pair) 
#    9 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
#   12 LOAD_GLOBAL    1 (list) 
#   15 COMPARE_OP    8 (is) 
#   18 RETURN_VALUE 

dis(b) 
# 2   0 LOAD_GLOBAL    0 (isinstance) 
#    3 LOAD_GLOBAL    1 (list) 
#    6 CALL_FUNCTION   0 (0 positional, 0 keyword pair) 
#    9 LOAD_GLOBAL    1 (list) 
#   12 CALL_FUNCTION   2 (2 positional, 0 keyword pair) 
#   15 RETURN_VALUE 

Я искренне считаю его более читаемым сказать if type(foo) is list: чем if isinstance(foo,list):, первый в основном только псевдо- код, а второй вызывает некоторую функцию (которую я должен искать каждый раз, чтобы быть isinstance или instanceof) с некоторыми аргументами. Это не похоже на листинг типов, и нет явного способа узнать, проверяет ли isinstance(a,b), является ли b экземпляром a или наоборот.

Я понимаю от this question, что мы используем isinstance, потому что это приятнее о наследовании. type(ClassDerivedFromList) is list не удастся, а isinstance(ClassDerivedFromList,list) преуспеет. Но если я проверю, что ВСЕГДА БЫТЬ БАЗОВЫМ ОБЪЕКТОМ, что я действительно теряю от выполнения type is?

ответ

13

Если я проверяю, что должно ВСЕГДА БЫТЬ БАЗОВЫМ ОБЪЕКТОМ, что я действительно теряю от типа?

хорошо, хорошо ли вы дать полный документированный ответ на свой вопрос, так что ваш ответ не потерять ничего! Единственное время, когда isinstance() необходимо, - это проверять наследование данного класса по сравнению с другим, как вы сказали и ссылаетесь. type() должен использоваться только для проверки того, является ли экземпляр точно данного базового типа.

+0

Я специально задумываюсь о реорганизации функции, которую я написал около 6 месяцев назад, которая принимает либо строку, либо список строк. Единственный вход для этой функции будет EVER быть 'str' или' list', поэтому делает 'if type (foo) is str: _handle_str (foo) else: _handle_list (foo)' действительно плохая практика? –

+3

@adsmith: вы используете Python 3? Если нет, ваш код просто сломался, если вы закончите строку с юникодом. – DSM

+0

@ DSM Я так понимаю, но я ценю подводные камни 'unicode' vs' str'. –

6

Помимо проблемы с наследованием вы также теряете способность тестировать несколько типов при использовании isinstance. Например:

def chk(typ): 
    if not isinstance(typ, (str, int)): 
     raise ValueError('typ must be string or int') 
    ... 
+8

Вы всегда можете использовать 'type (x) in (str, int)'. – pradyunsg

-1

Ответ на ваш вопрос:
Нет, учитывая, что вы проверяете для определенного базового класса, как вы теряете способность испытать для унаследованных классов.

И IMO isinstance приятнее читать и на Python: читаемость подсчитывается.

PS: Я получаю значительную разницу в таймингах (на Python 3.3)

 type: 0.5241982917936874 
isinstance: 0.46066255811928847 
+3

Вы считаете 'isinstance (foo, list)' более легким для чтения, чем 'type (foo) is list' ?? –

+0

@adsmith Да ... – pradyunsg

-2

Python Docs for the built-in type function дать четкие указания о разнице между типом (с одним аргом) и isinstance.

С помощью одного аргумента верните тип объекта. Возвращаемое значение представляет собой объект типа и, как правило, тот же объект, который возвращается объекту. класс. Встроенная функция isinstance() рекомендуется для тестирования типа объекта, поскольку он учитывает подклассы.

Для иллюстрации, посмотрите на иерархии наследования ниже в модуле алмаза:

enter image description here

Затем взглянуть на выходе консоли питона ниже на основе модуля алмаза:

enter image description here

Согласно документации, он более универсален и может охватывать более широкий спектр сценариев. Что касается первоначального вопроса OP - характеристики производительности не были указаны в качестве веской причины одобрения одного над другим. Не было читаемости.

Для более подробного обсуждения, которое включает объяснение (по словам ответчика) «Почему проверка равенства типов является еще более худшей практикой в ​​последних версиях Python, чем она уже была«, пожалуйста см. этот рейтинг проголосовали answer

+0

Я ценю ответ, но единственная часть вопроса, о котором вы говорите, - это тот, на который я отвечаю в своем вопросе. «Я понимаю ... что мы используем' isinstance', потому что это лучше для наследования. 'Type (ClassDerivedFromList) является list', а' isinstance (ClassDerivedFromList, list) 'будет успешным" –

+0

@AdamSmith - как указано в моем ответе , документы ясно объясняют разницу. «Встроенная функция isinstance() рекомендуется для тестирования типа объекта, поскольку он учитывает подклассы». Я уточняю вашу неуверенность - и почему вы заметили, что это было в подавляющем большинстве популярным выбором. Он более универсален и может охватывать более широкий спектр сценариев - type() будет достаточным, если вы знаете точный тип. Также хотел бы проиллюстрировать этот ответ некоторыми примерами кода, чтобы уточнить для других. – arcseldon

+0

Если вы проголосуете, я был бы признателен, если бы вы могли предложить объяснение, чтобы я мог изменить/улучшить ответ, если сочтет это необходимым. Благодаря! – arcseldon

Смежные вопросы