我需要在字典词典中附加字典

时间:2012-06-05 19:32:30

标签: python dictionary

好的,我有一本名为food的字典。食物有两个元素,都是字典本身,蔬菜和乳制品。蔬菜有两个元素根:萝卜和茎:芦笋。乳制品有奶酪:切达干酪和酸奶:草莓。我还有一个新的字典水果,有红色:樱桃和黄色:香蕉。

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

等和

fruit['red'] == 'Cherry'

现在我想将“水果”词典全部添加到“食物”词典中,以便我能够:

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

我知道我可以这样做:

food['fruit'] = fruit

但这看起来很笨拙。我想做点什么

food.Append(fruit)

但这并不能满足我的需要。

(编辑从变量名中删除了初始大写字母,因为这似乎引起了分心。)

6 个答案:

答案 0 :(得分:7)

Food['Fruit'] = Fruit是正确的方式(除大写名称外)

正如@kindall在评论中明智地指出的那样,可能有几个名称引用相同的字典,这就是为什么人们无法构建将对象映射到其名称并将其用作{{{{ 1}} dict。

答案 1 :(得分:4)

我知道你要做什么。你试图在python中避免DRY。可悲的是,python和许多其他语言都非常糟糕。

主要问题是您正在将变量的名称与程序中的值混合。它是许多编程语言中的常见错误。

如果你真的想这样做,你绑定到fruit=...变量的东西需要知道它的名字。

  • 你试图说,在python中“将这个字典移植到另一个字典上”。
  • Python要求你说它“把这个字典移植到另一个字典上,附在"Fruit"
  • 解决这个问题的唯一方法就是“Fruit”这个名字已经存在。但事实并非如此:它只存在于变量名中,而不在程序中。

有两种解决方案:

  • 您可以避免创建fruit=...变量,而只是直接删除"Fruit"名称。所以你只需要输入一次“Fruit”,但不要输入你想要的somedict["Fruit"],而是避免输入变量名。这是通过匿名编程实现的:

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

可悲的是,如果你的构造需要声明,python不会让你这样做;如果你只有一个文字,你只能逃避这一点。另一种解决方案是:

  • 您可以创建一个为您执行此操作的功能:

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

可悲的是,如果你的建筑需要任何声明,这也行不通。您可以创建变量x={'red':...}或其他东西,但这会破坏整个目的。第三种方法,你不应该使用locals(),但仍然需要你引用这个名字。

总之,如果你需要重要的for循环和函数以及if语句,你在python中想要做的事情是不可能的,除非你改变你构造fruit=...字典的整个方式。使用多行lambda,字典理解(dict((k,v) for k,v in ...)),内联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

答案 2 :(得分:2)

你有没有理由使用方括号?因为您可以使用嵌套的文字词典来表示此数据结构:

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

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

答案 3 :(得分:1)

你不能做追加,因为字典不是一个列表:它没有订单。您要做的是使用新的键/值对更新字典。你需要使用:

Food['Fruit'] = Fruit

或者,或者:

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

一个不相关的注释:用大写字母编写变量不是Python编码风格。 Fruit将改写为fruit

答案 4 :(得分:1)

您遇到的基本问题是您的词典不知道自己的名字。这是正常的;通常,任何数量的名称都可以绑定到Python对象,并且任何单个名称都不会以任何方式享有特权。换句话说,在a = {}; b = a中,ab都是同一字典的名称,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__属性中。 (函数做类似的事情。)通过滥用类和元类,我们可以利用底层机制完全避免重复自己 - 使用 minor 的缺点,即必须将我们的字典写成虽然他们是上课!

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中完成的。

答案 5 :(得分: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']