Як перевірити, чи є змінною словник у Python?


214

Як би ви перевірили, чи є змінною словник у python?

Наприклад, я хотів би, щоб він проглядав значення в словнику, поки не знайде словник. Потім проведіть курсор через той, який він знаходить:

dict = {'abc': 'abc', 'def': {'ghi': 'ghi', 'jkl': 'jkl'}}
for k, v in dict.iteritems():
    if ###check if v is a dictionary:
        for k, v in v.iteritems():
            print(k, ' ', v)
    else:
        print(k, ' ', v)

Також stackoverflow.com/questions/378927/… (який позначений як дублікат вищевказаного).
NPE


40
Ні, це не те саме питання. Відповіді на це запитання та на інші перелічені тут питання містять фактично однакову інформацію. Але відповідь на тему "Як перевірити, чи є змінна словником у python" - це "Use type () or isin substance ()", що призводить до нового питання, у чому полягає різниця між type () та isin substance () . Але людина, яка задає перше запитання, не може цього знати, поки не буде відповісти на перше питання. Ерго, різні питання, що важливо, коли ви шукаєте своє питання на сайті.

13
Я згоден з @mbakeranalecta. Я прийшов сюди, шукаючи відповідь на питання "Як перевірити, чи змінна є словник в Python?" і я б ніколи не думав шукати свою відповідь на "Різниці між isin substance () та type () у python".
lodebari

5
Для перевірки, чи є змінна зокрема словником, ви, ймовірно, повинні використовувати isinstance(v, collections.abc.Mapping). Іншими словами, це не є точним дублікатом "Різниці між isin substance () та type ()."
Джош Келлі

Відповіді:


279

Ви можете використовувати if type(ele) is dictабо використовувати те, isinstance(ele, dict)що спрацювало б, якщо ви підкласифікували dict:

d = {'abc':'abc','def':{'ghi':'ghi','jkl':'jkl'}}
for ele in d.values():
    if isinstance(ele,dict):
       for k, v in ele.items():
           print(k,' ',v)

70
Я вниз проголосував цей відповідь , тому що правильна відповідь на загальне питання: isinstance(ele, collections.Mapping). Вона працює dict(), collections.OrderedDict()і collections.UserDict(). Приклад у питанні є досить конкретним для відповіді Падріака на роботу, але це недостатньо добре для загальної справи.
Олександр Рижов

3
Я відповів на цю відповідь, тому що якщо ви збираєтесь викликати, ele.items()чому ви перевіряєте тип? ЕСПЦ / качок-типування працює тут, просто обернути for k,v in ele.items()в try...except (AttributeError, TypeError). Якщо буде винято виняток, ви знаєте, що eleце не itemsдає результату ...
коуберт

@Padraic Cunningham Ваш гіпотетичний крайній випадок вимагає, щоб у вашому індивідуальному класі "100% не диктант" був items()метод 2. який так і стався, щоб отримати ітерабельний і 3. де кожен елемент цього ітерабельного може бути представлений як 2 -турі. На даний момент ваш власний об’єкт вже реалізував половину дикта. Для цілей переліченого коду ми дбали лише про умовне розширення вкладеного елемента, а ваш власний об’єкт вже реалізує це. (Трохи іронічно, що ви критикуєте коментар @Alexander Ryzhov за те, що він занадто загальний, але зараз піднімаєте загальну справу)
cowbert

1
@PadraicCunningham Я б краще не навчав людей, які не є надмірно знайомими з Python анти-шаблонам для початку. У Python дуже мало випадків використання, які потребують явної перевірки типу - більшість походить від успадковування поганої реалізації для початку («об’єкт бога», переосмислення стандартних бібліотечних / мовних конструкцій тощо). Початкове питання саме по собі є проблемою XY. Чому ОП потрібно перевірити тип? Тому що, відповідно до їх коду, те, що вони насправді хочуть зробити, це перевірити, чи поводиться елемент у їх колекції як колекція (засоби, items()які дають вкладений ітерабельний).
коуберт

4
@AlexanderRyzhov Чому б не опублікувати такий підхід як відповідь? До речі, як Джош Келлі прокоментував вище, припускаючи collections.abc.Mapping, може бути доречною примітка про те, що вони однакові, але collections.abcвона недоступна до Python 3.3. collections.Mappingпсевдонім все ще доступний в Python 3.6, але не задокументований, тому, напевно, слід віддати перевагу collections.abc.Maping.
Юшин Вашио,

5

Як би ви перевірили, чи є змінною словник у Python?

Це хороше запитання, але, на жаль, більшість upvoted відповідь веде з поганою рекомендацією type(obj) is dict.

(Зверніть увагу, що ви також не повинні використовувати dictяк ім'я змінної - це ім'я вбудованого об'єкта.)

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

Я настійно пропоную з метою правильності, ремонтопридатності та гнучкості майбутнім користувачам, ніколи не маючи менш гнучких унідіоматичних виразів у своєму коді, коли є більш гнучкі, ідіоматичні вирази.

isє тестом на ідентичність об'єкта . Він не підтримує успадкування, він не підтримує жодної абстракції і не підтримує інтерфейс.

Тож я надам декілька варіантів, які можна зробити.

Підтримуюча спадщина:

Це перша рекомендація я хотів би зробити, тому що вона дозволяє користувачам поставити свій власний підклас Dict, або OrderedDict, defaultdictабо Counterз колекції модуля:

if isinstance(any_object, dict):

Але є ще більш гнучкі варіанти.

Підтримуючі абстракції:

from collections.abc import Mapping

if isinstance(any_object, Mapping):

Це дозволяє користувачеві вашого коду використовувати власну власну реалізацію абстрактного картографування, яка також включає будь-який підклас dictта все ж отримувати правильну поведінку.

Використовуйте інтерфейс

Ви часто чуєте поради OOP, "програма на інтерфейс".

Ця стратегія використовує перевагу поліморфізму Python або типізації качок.

Тому просто спробуйте отримати доступ до інтерфейсу, зафіксувавши конкретні очікувані помилки ( AttributeErrorу випадку, якщо таких немає, .itemsі TypeErrorу випадку, якщо itemsїх не можна викликати), з розумним відпадом - і тепер будь-який клас, який реалізує цей інтерфейс, передасть вам свої елементи (примітка .iteritems()відсутня в Python 3):

try:
    items = any_object.items()
except (AttributeError, TypeError):
    non_items_behavior(any_object)
else: # no exception raised
    for item in items: ...

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

Висновок

Не використовуйте isдля перевірки типів для стандартного потоку управління. Використовуйте isinstance, розглядайте такі абстракції, як Mappingі MutableMapping, і взагалі уникайте перевірки типу, використовуючи інтерфейс безпосередньо.


3

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

Дотримуючись рекомендованого чистого Python (3.8) способу перевірити словник у вищезазначених коментарях.

from collections.abc import Mapping

dict = {'abc': 'abc', 'def': {'ghi': 'ghi', 'jkl': 'jkl'}}

def parse_dict(in_dict): 
    if isinstance(in_dict, Mapping):
        for k, v in in_dict.items():
            if isinstance(v, Mapping):
                for k, v in v.items():
                    print(k, v)
            else:
                print(k, v)

parse_dict(dict)

dict.iteritems()не існує в Python 3, ви повинні використовувати його dict.items()замість цього.
Аркеліс

@Arkelis На жаль, просто скопіював / вставив цю частину, дякую, що вказав на неї - виправлено зараз.
CodeMantle
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.