2012-06-05 3 views
0

Хорошо, у меня есть словарь под названием food. еда имеет два элемента, оба из которых являются самими словарями, овощами и молочными продуктами. veg имеет два элемента: корень: репа и стебель: спаржа. молочный сыр: Чеддер и йогурт: клубника. У меня также есть новый фруктовый словарь, который имеет красный цвет: вишневый и желтый: банан.Мне нужно добавить словарь в словарь словарей

food['veg']['root'] == 'Turnip' 
food['dairy']['cheese'] == 'Cheddar' 

и т.д., и

fruit['red'] == 'Cherry' 

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

food['fruit']['red'] == 'Cherry' 

Я знаю, что я мог бы сделать что-то вроде этого:

food['fruit'] = fruit 

Но это кажется неуклюжим. Я хотел бы сделать что-то вроде

food.Append(fruit) 

Но это не делает то, что мне нужно.

(Ред удаленных начальных капиталов из имен переменных, так что казалось, что вызывает отвлечение.)

+0

Если «не делает то, что мне нужно» означает «не поддерживается языком и выдает ошибку», это правильно. Это может показаться вам «неуклюжим», но вы уже определили правильное решение. – larsks

+0

'Food ['Fruit'] = Fruit' кажется правильным путем. Словари предназначены для индексирования ключами. В этом случае у вас есть Food, который является словарем строковых ключей и значениями словаря. Почему бы вам не захотеть установить в нем ключ? –

+1

В Python и даже на большинстве языков ваши переменные должны начинаться с нижнего регистра. Заглавная первая буква зарезервирована для имен классов. – Soviut

ответ

7

Food['Fruit'] = Fruit является правильным и надлежащим образом (кроме заглавной буквы имен).

Как замечает @kindall в комментарии, может быть несколько имен, ссылающихся на один и тот же словарь, поэтому невозможно построить функцию, которая сопоставляет объект с его именем и использует это как новый ключ в вашем food ДИКТ.

+0

Я бы предпочел не удвоить свои плоды. У словаря уже есть имя, я бы хотел, чтобы оно использовалось в append, если это вообще возможно. –

+3

'a = {}; b = a'. Является ли название словаря 'b' или' a'? – kindall

1

Вы не можете добавить приложение, потому что словарь не является списком: у него нет порядка. То, что вы хотите сделать, - это обновить словарь с помощью новой пары ключ/значение. Вы должны использовать:

Food['Fruit'] = Fruit 

или, в качестве альтернативы:

Food.update({'Fruit': Fruit}) 

неродственного примечание: это не Python стиль кодирования для записи переменных с капителями. Fruit будет написано как fruit.

+0

начальные капиталы удален. –

2

Есть ли причина, по которой вы используете квадратные скобки? Потому что вы можете представить эту структуру данных с вложенными буквальным словарями:

food = { 
    'veg': { 
     'red': 'tomato', 
     'green': 'lettuce', 
    }, 

    'fruit': { 
     'red': 'cherry', 
     'green': 'grape', 
    }, 
} 
+0

лично я считаю, что квадратные скобки легче читать. То, что я использую в своем фактическом коде, зависит от приложения. –

+0

@SkipHuffman Не являются квадратными скобками для списков, а не словарей? –

+0

Нет, словарь может быть создан с помощью {}, но он обновляется квадратными скобками. –

0

Вы, вероятно, ищете defaultdict. Он работает, добавляя новый пустой словарь всякий раз, когда вы запрашиваете новый тип первого уровня. Пример приведен ниже:

from collections import defaultdict 

basic_foods = {'Veg' : {'Root' : 'Turnip'}, 'Dairy' : {'Cheese' : 'Cheddar'}} 

foods = defaultdict(dict, basic_foods) 
foods['Fruit']['Red'] = "Cherry" 
print foods['Fruit'] 
+1

возможно, хотя это не то, что ОП просит – ninjagecko

4

Я знаю, что вы пытаетесь сделать. Вы пытаетесь избежать DRY в python. Печально питон, и многие другие языки, очень плохо в этом.

Основная проблема заключается в том, что Вы смешиваете имена своих переменных со значениями в своей программе. Это обычный faux pas на многих языках программирования.

Если вы действительно хотели это сделать, то, что вы связали с переменной fruit=..., нужно будет узнать ее имя.

  • Вы пытаетесь сказать, что в python «пересаживайте этот dict на этот другой dict».
  • Python требует, чтобы вы произносили это как «трансформировать этот dict на этот другой dict, прикрепляя его к "Fruit"»
  • Единственный способ обойти это, что имя «Фрукты» уже существует где-то. Но это не так: он существует только в имени переменной, которого нет в вашей программе.

Есть два решения:

  • Вы могли бы избежать когда-либо создать fruit=... переменные, и вместо того, чтобы непосредственно прививать это только "Fruit" имени. Поэтому вам нужно будет только один раз набрать «Фрукты», но вместо того, чтобы не печатать somedict["Fruit"], как вы хотите, мы избегаем ввода имени переменной. Это достигается путем программирования в анонимном стиле:

    somedict["Fruit"] = {'red':'apple', 'yellow':'banana'} 
    

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

  • Вы могли бы создать функцию, которая делает это для вас:

    graft(somedict, "Fruit", {'red':'apple', 'yellow':'banana'}) 
    

К сожалению, это тоже не будет работать, если строительство требуется какое-либо заявление. Вы можете создать переменную x={'red':...} или что-то, но это победит всю цель. Третий способ, который вы не должны использовать, - locals(), но это все еще требует от вас ссылки на имя.

В заключение, если вы требуете значительных для циклов и функций, и если утверждения, то, что вы пытаетесь сделать, невозможно в python, если вы не измените весь способ, которым вы строите словарь fruit=.... Это было бы возможно с комбинациями многострочных лямбда, пониманием словаря (dict((k,v) for k,v in ...)), inline IFTRUE if EXPR else IFFALSE и т. Д. Опасность этого стиля в том, что его очень быстро становится трудно читать.

Это возможно, если вы можете выразить словарь как литерал буквального словаря или понимание словаря или выход функции, которую вы уже написали. На самом деле это довольно просто (см. Другие ответы). К сожалению, исходный вопрос не говорит о том, как вы строите эти словари.

Предполагая, что эти ответы не отвечают на ваш вопрос (т. Е. Вы строите их по-настоящему сложным образом), вы можете написать код «мета»: код, который сделает ваш словарь для вас, и злоупотреблять отражением. Однако лучшим решением в python является просто попытка сделать словарь с итерацией. Например:

foods = { 
    "Fruit": {...}, 
    "Meats": makeMeats(), 
} 
for name,data in ...: 
    foods[name] = someProcessing(data) 
foods.update(dataFromSomeFile) #almost same as last two lines 
+0

Отличное обобщение проблемы, которую я пытаюсь решить. –

1

Основная проблема заключается в том, что ваш словарь не знает своего имени. Это нормально; как правило, любое количество имен может быть привязано к объекту Python, и ни одно имя никоим образом не может быть привилегированным по сравнению с другими.Другими словами, в a = {}; b = a оба a и b являются именами одного и того же словаря, а a не является «настоящим» именем словаря только потому, что он был назначен первым. И на самом деле, словарь не имеет возможности даже знать, какое имя находится в левой части переменной.

Таким образом, один из вариантов заключается в том, чтобы словарь содержал свое собственное имя в качестве ключа. Например:

fruit = {"_name": "fruit"} 
fruit["red"] = "cherry" 

food[fruit["_name"]] = fruit 

Ну, это не помогло, не так ли? Это было сделано так, потому что fruit теперь уже не является строкой в ​​вложении в словарь food, поэтому, по крайней мере, Python предоставит вам сообщение об ошибке, если вы его обманете. Но вы на самом деле печатаете «фрукты» еще больше, чем раньше: теперь вы должны вводить его, когда вы создаете словарь в дополнение к тому, когда вы присоединяете его к другому словарю. И в мире есть еще более типичный набор.

Кроме того, имея имя в, словарь является своего рода неудобным; когда вы повторяете словарь, вам нужно написать код, чтобы пропустить его.

Вы могли бы написать функцию, чтобы сделать приложение для вас:

def attach(main, other): 
    main[other["_name"]] = other 

Тогда вам не придется повторять себя, когда вы присоедините к югу от словаря к главному:

fruit = {"_name": "fruit"} 
fruit["red"] = "cherry" 

attach(food, fruit) 

И, конечно же, теперь вы можете создать словарь подкласс, который знает свое имя и может прикрепить именованный подзадач. В качестве бонуса мы можем сделать имя атрибутом словаря, а не хранить его в словаре, в котором будет храниться настоящий словарь.

class NamedDict(dict): 

    def __init__(self, name="", seq=(), **kwargs): 
     dict.__init__(self, seq, **kwargs) 
     self.__name__ = name 

    def attach(self, other): 
     self[other.__name__] = other 

food = NamedDict("food") 

fruit = NamedDict("fruit") 
fruit["red"] = "cherry" 

food.attach(fruit) 

Но у нас еще есть одно повторение, когда NamedDict изначально определен: food = NamedDict("food"), например. Как нам обойтись без этого?

Это является возможно, хотя и громоздким и, вероятно, не стоит проблем. Python имеет два типа объектов, которые имеют «внутреннее» имя: классы и функции. Другими словами:

class Foo: 
    pass 

выше не только создает переменную с именем Foo в текущем пространстве имен, имя класса также удобно хранится в атрибуте класса __name__. (Функции делают что-то подобное.) Из-за злоупотребления классами и метаклассами мы можем полностью использовать базовый механизм , избегая повторения самих себя: минус Недостаток необходимости писать наши словари, как если бы они были классами!

class NamedDict(dict): 

    class __metaclass__(type): 

     def __new__(meta, name, bases, attrs): 
      if "NamedDict" not in globals(): # we're defining the base class 
       return type.__new__(meta, name, bases, attrs) 
      else: 
       attrs.pop("__module__", None) # Python adds this; do not want! 
       return meta.NamedDict(name, **attrs) 

     class NamedDict(dict): 
      def __init__(self, name, seq=(), **kwargs): 
       dict.__init__(self, seq, **kwargs) 
       self.__name__ = name 

      def attach(self, other): 
       self[other.__name__] = other 

     __call__ = NamedDict  

Теперь, вместо определения наших словарей обычного способа, мы объявляем их как подклассы NamedDict. Благодаря метаклассу подклассификация внешнего класса NamedDict фактически создает экземпляры внутреннего класса NamedDict (который аналогичен предыдущему). Атрибуты подкласса, который мы определяем, если таковые имеются, становятся элементами в словаре, такими как аргументы ключевого слова dict().

class food(NamedDict): pass 

class fruit(NamedDict): red = "cherry" 

# or, defining each item separately: 

class fruit(NamedDict): pass 
fruit["red"] = "cherry" 

food.attach(fruit) 

В качестве бонуса, вы можете определить NamedDict на «регулярный» путь, по инстанцировании его как класс:

fruit = NamedDict("fruit", red="cherry") 

быть предупрежден, хотя: «класс, который действительно словарь» это довольно нестандартная идиома для Python, и я бы предположил, что вы никогда на самом деле этого не делаете, поскольку другие программисты не найдут ее совершенно ясной. Тем не менее, это то, как это можно сделать в Python.

+0

Я думаю, что подклассификация словаря именно то, что мне нужно, и на самом деле то, что я делаю в любом случае. Этот вопрос был ранее вчера днем: http://stackoverflow.com/questions/10901048/i-want-to-subclass-dict-and-set-default-values ​​Это вторая половина той же проблемы, что и я пытаясь решить. Благодаря! –

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