Python и словарь как объект

Мне нужна функция глубокого обновления python 3.1 для словарей (функция, которая будет рекурсивно обновлять дочерние словари, находящиеся внутри родительского словаря).

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

Но утиная печать является частью философии Python, так как я могу проверить, является ли объект похожим на словарь?

Спасибо!

Изменить: Спасибо всем за ответы. На всякий случай, закодированную функцию я можно найти в этом месте: http://blog.cafeaumiel.com/public/python/dict_deep_update.py

Ответы

Ответ 1

Изучите абстрактные базовые классы (новые в 3.x) (ABC) в модуле коллекций:

http://docs.python.org/3.1/library/collections.html

Я бы рассмотрел проверку с isststance против Mapping, как в следующем:

>>> import collections
>>> isinstance({},collections.Mapping)
True

Затем, если вы создаете свой собственный диктоподобный класс, создайте коллекции. Сопоставляя одну из своих баз.

Другой маршрут пытается и улавливает все исключения для операций с словарем, но с рекурсией, о которой вы говорите, я бы предпочел сначала проверять базовый тип, чем описать, какой dict или subdict или другой элемент dict было или не было, чтобы выбросить исключение.

Редактирование, чтобы добавить: Преимущество проверки с помощью ABC сопоставления, а не против dict, заключается в том, что тот же тест будет работать для диктоподобных классов, независимо от того, является ли он подклассом, и поэтому он более гибкий, на всякий случай.

Ответ 2

используйте isinstance, в этом нет ничего плохого и он обычно используется в коде, требующем рекурсии.

Если с помощью словарного типа вы подразумеваете, что класс объекта наследуется от dict, isinstance также возвращает True.

>>> class A(dict):
    pass

>>> a = A()
>>> isinstance(a, dict)
True

Ответ 3

Утиная печать - это то, где вы делаете то, что хотите, и справляетесь с последствиями, если ваши объекты не ведут себя так, как вы ожидали.

Вы хотите проверить, что-то вроде dict-like, и обновить его, если это так, правильно? Просто вызовите метод обновления объекта и обработайте Исключение, которое вы получите, если такого метода нет.

Конечно, это будет падать, если вы имеете дело с пользовательскими объектами класса, которые имеют методы обновления, которые делают что-то совсем другое - я не совсем уверен, как с этим бороться.

Ответ 4

Ну, чтобы обновить рекурсивно словарь, вы должны вызвать метод "items" для его итерации.

Итак, я предлагаю, вы просто выполните:

try :
    for key, value in data.items() :
         # recursive call
except AttributeError :
    # handling the trouble

Ответ 5

Мне нравится проверять магический метод __ setitem __... это то, что позволяет поведение foo ['bar'] = baz.

if getattr(obj, '__setattr__'):
    obj[key] = val

Вот python 2.7 docs

Ответ 6

Если вам также нужно обрабатывать пользовательские классы, которые ведут себя как словари, но не подклассифицированы из dict, вы можете использовать getattr для получения требуемой функции.

# loop
# ... more code
someObject = getObject(..)
try:
    getattr(someObject, "update")("someValue")
except AttributeError:
    # Wasn't a type we can handle