2010-12-14 2 views
0

У меня есть класс, называемый nesteddict производный от collections.defaultdict, которые держат вложенную набор словарей:Как преобразовать производный рекурсивный тип данных в базовый тип данных?

import collections 

class nesteddict(collections.defaultdict): 
    """Nested dictionary structure. 

    Based on Stack Overflow question 635483 
    """ 
    def __init__(self): 
     collections.defaultdict.__init__(self, nesteddict) 
     self.locked = False 

Я хотел бы быть в состоянии выполнить операцию экземпляр, который преобразует все объекты nesteddict к python- родные объекты диктата.

Один из способов сделать это, чтобы иметь метод:

def todict(self): 
    for (key,val) in self.iteritems(): 
     if isinstance(val,nesteddict): 
      val.todict() 
      self[key] = dict(val) 
    self = dict(self) 

Это успех при замене всех внутренних объектов отображения с типами Dict, но последнее утверждение в методе, очевидно, не будет работать.

Вот пример:

In [93]: a = pyutils.nesteddict() 

In [94]: a[1][1] = 'a' 

In [95]: a[1][2] = 'b' 

In [96]: a[2][1] = 'c' 

In [97]: a[2][2] = 'd' 

In [98]: print a 
defaultdict(<class 'pyutils.nesteddict'>, {1: defaultdict(<class 'pyutils.nesteddict'>, {1: 'a', 2: 'b'}), 2: defaultdict(<class 'pyutils.nesteddict'>, {1: 'c', 2: 'd'})}) 

In [99]: a.todict() 

In [100]: print a 
defaultdict(<class 'pyutils.nesteddict'>, {1: {1: 'a', 2: 'b'}, 2: {1: 'c', 2: 'd'}}) 

Есть ли способ сделать это в Python? Есть метод, который преобразует его объект в другой тип? Если нет, то что является хорошей альтернативой этому. Обратите внимание, что тип данных на практике может быть большим, поэтому было бы предпочтительнее не просто делать копию, а затем возвращать ее.

Спасибо!
Uri

+3

«Я бы например, чтобы иметь возможность выполнить операцию экземпляр, который преобразует все объекты nesteddict в объекты python-native dict. «Почему? Это уже объект 'dict'. Вам ничего не нужно конвертировать. Это подкласс 'defaultdict', что означает, что ** ** является' dict'. –

+0

После загрузки данных в него я хочу «заблокировать» его.Один из способов реализации этого - сделать метод default_factory функцией, которая вызывает KeyError, которая, кажется, работает нормально. Тем не менее, у меня возникла проблема с сериализацией этого класса с помощью cPickle. Преобразование в чистый dict позволит легко сериализоваться (в том числе с json) и эффективно блокирует словарь аналогичным образом. –

+0

@ S.Lott pickle - распространенная причина, по которой требуется преобразование в чистые словари: в противном случае, чтобы разложить ее, вам нужно привести определение специализированного dict, например. 'infin_defaultdict = lambda: defaultdict (infin_defaultdict)'. –

ответ

5

ли это как свободная функция, и в то время как вы на него, рассмотрим более функциональный подход стиль:

def undefaulted(x): 
    return dict(
    (k, undefaulted(v)) 
    for (k, v) in x.iteritems() 
) if isinstance(x, nesteddict) else x 

a = undefaulted(a) 
+0

Это очень приятно. Благодаря! –

+0

Для будущих посетителей: другой ответ, используя понимание dict, действительно превосходит использование 'dict()'. В дополнение к претензии Джейми, это также быстрее * и * более идиоматично. –

1

dict(a) даст вам Dict по умолчанию из любого объекта, который является производным от defaultdict. То есть, предполагая, что вы не переопределили требуемые специальные методы.

+0

Да, но он не будет рекурсивно переходить во вложенные словари. Он преобразует только объект nesteddict верхнего уровня в dict. –

+0

yah .. полностью забыл о рекурсивной части запроса. Виноват. – dietbuddha

0

Первое, что я замечаю в вашем коде, является то, что вы изменяете (или пытаясь) переменную self. Эта переменная просто указывает на текущий экземпляр вашего класса. Если вы переназначите его, вы просто укажете его на другое значение, но предыдущее значение, указанное self, остается неизменным. Это как раз то, как работает Python.

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

def anothertodict(self): 
    stuff = dict(self) 
    for (key,val) in stuff.iteritems(): 
     if isinstance(val,nesteddict): 
      stuff[key] = val.anothertodict() 
    return stuff 

Таким образом, если вы делаете: print a.anothertodict() вы получите то, что вы «ожидаем получить.

PS: Зачем вам нужно конвертировать из defaultdict в dict?

3

Я сам столкнулся с этой проблемой, используя вложенные defaultdicts. Мое решение:

def dictify(d): 
    return {k:dictify(v) for k,v in d.items()} if \ 
     isinstance(d,nesteddict) else d 

Лучше использовать {}, а не Dict(), так как вызов конструктор Dict() ограничивает число ключевых аргументов 255. См: What is a maximum number of arguments in a Python function?

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