Перевірте, чи змінною є список чи кортеж


234

У python, який найкращий спосіб перевірити, чи змінна містить список чи кортеж? (тобто колекція)

Невже isinstance()таке зло, як запропоновано тут? http://www.canonical.org/~kragen/isinstance/

Оновлення: найпоширеніша причина, по якій я хочу відрізнити список від рядка, - це те, що у мене є невизначено глибоке вкладене дерево / структура даних списків списків списків рядків і т. Д., Які я вивчаю за допомогою рекурсивного алгоритму, і мені потрібно щоб знати, коли я потрапив у «листові» вузли.


72
Широко відмовляючись від перевірки типу, оскільки зло є трохи сприятливим. Це частина мови. Якщо це так зло, хтось повинен написати PEP, щоб зняти його.
Адам Кросленд

4
@Adam Crossland: "Це частина мови". Так само, як поділ на нуль. Це можна уникнути. У цьому випадку без додаткової інформації це, мабуть, абсолютно непотрібно. Перевірка більшості типів у Python не потрібна. Оскільки не все є непотрібним, потрібно перевірити тип. Але це не означає, що це корисна, цінна або навіть гарна ідея.
S.Lott

11
Отже, ви говорите, що потрібна певна перевірка типу, але, незважаючи на це, вона марна, нікчемна і погана ідея. Вибачте, це просто не має сенсу.
Гленн Мейнард

18
"XXX є злом" погано продуманий, вводячи в оману скорочення "так, як ви просите зробити XXX, передбачає, що ви не розумієте, коли його насправді слід використовувати, і ви майже напевно хочете чогось іншого". Це, швидше за все, так і тут.
Гленн Мейнард

2
Я не відкидав це як зло. Я написав короткий нарис про те, коли це зло і коли це виправдано. Цей твір може бути багатьма речами - правильним, неправильним, зрозумілим, розпливчастим, приємним, нудним - але одне це не є широким звільненням від методики.
Краген Хав'єр Сітакер

Відповіді:


101

Ідіть і використовуйте, isinstanceякщо вам це потрібно. Це дещо зло, оскільки виключає спеціальні послідовності, ітератори та інші речі, які вам можуть знадобитися насправді. Однак іноді потрібно поводитись інакше, якщо хтось, наприклад, передає рядок. Мої переваги полягають у тому, щоб явно перевірити strчи unicodeтак:

import types
isinstance(var, types.StringTypes)

Примітка : не плутайте types.StringTypeдля types.StringTypes. Останній включає strі unicodeоб'єкти.

typesМодуль розглядається багатьма застарілими на користь просто перевірка безпосередньо проти типу об'єкта, так що якщо ви не хочете використовувати вище, ви можете альтернативно перевірити явно проти strі unicode, як це:

isinstance(var, (str, unicode)):

Редагувати:

Ще краще:

isinstance(var, basestring)

Закінчити редагування

Після будь-якого з них ви можете повернутися до поведінки так, ніби отримуєте нормальну послідовність, дозволяючи не послідовності створювати відповідні винятки.

Дивіться, що "зло" щодо перевірки типів - це не те, що ви можете поводитись по-різному для певного типу об'єктів, це те, що ви штучно обмежуєте свою функцію в тому, щоб робити правильну справу з несподіваними типами об'єктів, які в іншому випадку зробили б правильно. Якщо у вас є остаточна резервна копія, яка не перевірена типом, ви видалите це обмеження. Слід зазначити, що занадто велика перевірка типу - це запах коду, який вказує на те, що ви можете зробити якийсь рефакторинг, але це не обов'язково означає, що слід уникати цього з Getgo.


2
Модуль типів - трохи історичний артефакт. Як вже згадувалося на docs.python.org/dev/library/types.html#module-types, якщо ви дійсно повинні перевірити strтип, ви повинні просто використовувати це безпосередньо, замість того, щоб використовувати types.StringTypeдля нього лише псевдонім. Але я не думаю, що ця відповідь відповідає на запитання, як було задано, бо мова йшла про "колекцію". Якщо ви не використовуєте python, достатньо новий, щоб мати abcмодуль, який ви не можете використовувати isinstanceдля перевірки, і навіть тоді я рекомендую уникати перевірки, якщо це можливо.
mzz

1
assert isinstance(u'abc', str) == False. Я погоджуюсь, що краще перевірити тип безпосередньо, а не використовувати typesмодуль, але types.StringTypesробить щось, що strні: він повертає True для strта unicodeоб'єкти. Я відредагую свою відповідь, щоб запропонувати подвійну перевірку як альтернативу.
jcdyer

1
Я усвідомлюю, що не відповів на запитання перевірки колекцій безпосередньо, але актуальним питанням було "Чи isinstanceзло?" І я наводив зустрічний приклад, який (1) є isinstanceнедоброзичливим використанням , тому що наявність резервної системи означає, що це не зламає каченя, і (2) є хорошим рішенням для дуже поширеної мотивації, яку люди хочуть перевірити, чи щось є listабо tuple(тобто роз'єднувати їх від рядків).
jcdyer

Я погоджуюсь із застереженням про те, що часто корисно, щоб користувацькі типи поводилися також як рядки. Але ОО Python тільки йде так далеко ...
Краген Хав'єр Сітакер

Робиш class Foo(str): passте, що ти хочеш?
jcdyer

567
if type(x) is list:
    print 'a list'
elif type(x) is tuple:
    print 'a tuple'
else:
    print 'neither a tuple or a list'

1
Здається, не працює: введіть ([]) ==> список; type ([]) is list ===> False
sten

3
У Python 2.7.5: type([]) is listповерненняTrue
Девід Гейгер

54
type(x) in [list,tuple]коротше.
Алекс Холкомб

якщо x і введіть (x) список: щоб уникнути невідповідності []
Кенічі Шибата

Мені довелося так прокрутити вниз. : D
Рітвік

38

У використанні немає нічого поганого isinstance, якщо це не є зайвим. Якщо змінною має бути лише список / кортеж, тоді документуйте інтерфейс і просто використовуйте його як такий. Інакше перевірка цілком розумна:

if isinstance(a, collections.Iterable):
    # use as a container
else:
    # not a container!

Цей тип перевірки має деякі добрі випадки використання, наприклад, зі стандартними рядковими методами startwith / endwith (хоча для точності вони реалізовані в C у CPython, використовуючи явну перевірку, щоб переконатися, що це кортеж - існує більше ніж один спосіб щоб вирішити цю проблему, про що йдеться у статті, на яку ви посилаєтесь).

Явна перевірка часто краще, ніж намагатися використовувати об'єкт як контейнер і обробляти виняток - це може спричинити всілякі проблеми з тим, що код працює частково або без потреби.


15
Це хороший спосіб перевірити, чи є змінною ітерабельна. Однак це, мабуть, не спрацює для цілей цього питання. Зауважте, що рядок також є ітерабельним і, ймовірно, створить помилковий позитив.
Корі О.

setОб'єкт також итератор, який означає , що в той час як ви можете , звичайно , поп - елементи, але це не гарантує певний порядок, який є дуже небезпечною річчю для деяких алгоритмів. У тих випадках, коли впорядкування елементів має значення, алгоритм, що використовує цей фрагмент, може потенційно створювати різні результати на різних пробігах!
коо


12

Як щодо hasattr(a, "__iter__"):?

Він повідомляє, чи можна повернути повернутий об'єкт як генератор. За замовчуванням кортежі та списки можуть, але не типи рядків.


я вважав це дійсно корисним.
javadba

8
Також результати True для рядків (принаймні, на Python 3).
SzieberthAdam

2
Це неправильна відповідь. Оскільки тип "str" ​​також має метод " iter ". @SzieberthAdam мав рацію. Тип "набір" також є ітерабельним, але не підлягає впорядкуванню.
ПАДИМКО

Також дикти є __iter__.
thet

Якщо ви продовжите, будь-який користувацький тип може __iter__з якихось причин мати ...
Олександр Ірбіс

10

На type(list) is listповерненнях Python 2.8 false
я б запропонував порівняти тип таким жахливим чином:

if type(a) == type([]) :
  print "variable a is a list"

(ну принаймні в моїй системі, використовуючи анаконду на Mac OS X Yosemite)


1
Чи список "а" також оцінюється як хибний?
Дмитро Сінцов

4
Ви мали на увазі Python 2.7.8? python.org/dev/peps/pep-0404/#official-pronouncement
Карл

Привіт, мені цікаво: Чому ви вважаєте ваш приклад "жахливим"?
Сет Коннелл

type(list) is listповертається, Falseбо type(list)є type, ні list. type(list()) is listабо з будь-яким іншим екземпляром списку повернеться True.
Майкл Грін

8

Python використовує "Duck typeping", тобто якщо змінна kwaks схожа на качку, вона повинна бути качкою. У вашому випадку ви, ймовірно, хочете, щоб це було ітерабельним, або ви хочете отримати доступ до елемента з певним індексом. Ви повинні просто зробити це: тобто використовувати об'єкт вfor var: блоці або var[idx]всередині нього try, і якщо ви отримаєте виняток, це не була качка ...


7
Проблема з цим полягає в тому, що якщо varвідбудеться ітерація рядків з імовірно несподіваними результатами.
Брайан М. Хант

Незважаючи на факт, який заявив Брайан М. Хант, його є досить пітонічним рішенням, з точки зору прохання пробачення, а не дозволу.
Géza Török


3

Якщо вам просто потрібно знати, чи можна використовувати foo[123]позначення зі змінною, ви можете перевірити наявність __getitem__атрибуту (який називає python, коли ви звертаєтесь за індексом) за допомогоюhasattr(foo, '__getitem__')


2

Має бути складнішим тестом, якщо ви дійсно хочете обробляти майже що-небудь як аргумент функції.

type(a) != type('') and hasattr(a, "__iter__")

Хоча, як правило, достатньо лише вказати, що функція очікує ітерабельність, а потім лише перевірити type(a) != type('') .

Також може трапитися, що для рядка у вас є простий шлях обробки, або вам буде добре і зробити спліт тощо, тому ви не хочете кричати на рядках, і якщо хтось надсилає вам щось дивне, просто дайте йому виняток.


2

Ще один простий спосіб дізнатися, чи є змінною або список, або кортеж, або загалом перевірити тип змінної:

    def islist(obj):

        if ("list" in str(type(obj)) ): return True

        else : return False

1

В принципі, я згоден з Ігнасіо вище, але ви також можете використовувати тип, щоб перевірити, чи є щось із кортежу чи списку.

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.