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