具有相同键的(嵌套)字典的 Pythonic 替代方案?

Posted

技术标签:

【中文标题】具有相同键的(嵌套)字典的 Pythonic 替代方案?【英文标题】:Pythonic alternative to (nested) dictionaries with the same keys? 【发布时间】:2014-12-27 04:25:01 【问题描述】:

我发现自己避免使用字典,因为通常有近一半的代码是重复的。我通常在嵌套字典中执行此操作,其中所有子字典都包含相同的键,但值不同。

我手动创建了一个大型父字典,其中每个键都包含一个嵌套字典,以在外部模块中使用。嵌套字典都使用相同的键来定义配置参数。这种用法是明确的并且有效,但是为我手动创建的每个嵌套字典重新键入或复制/粘贴键感觉很愚蠢。我并不太关心优化内存或性能,只是想知道我是否应该以另一种更 Pythonic 的方式来做这件事。

作为一个常见的例子和模式:

people_dict = 
    "Charles Lindberg": "address": "123 St.", 
                         "famous": True, 
    "Me": "address": "456 St.",
           "famous": False
    

>>>people_dict["Charles Lindberg"]["address"]
"123 St."

虽然字典支持显式代码,但定义具有重复键的嵌套字典既繁琐又容易出错。在此示例中,嵌套字典的一半是所有嵌套字典共有的代码重复代码。 我曾尝试使用元组来消除重复键,但发现这会导致代码脆弱 - 任何位置更改(而不是字典键)都会失败。这也会导致代码不明确且难以遵循。

people_dict = 
        "Charles Lindberg": ("123 St.", True), 
        "Me": ("456 St.", False),
            

>>>people_dict["Charles Lindberg"][0]
"123 St."

相反,我编写了一个类来封装相同的信息: 成功减少重复代码...

class Person(object):
    def __init__(self, address, famous=False):
        self.address = address
        self.famous = famous

people_dict = [
    "Charles Lindberg": Person("123 St.", famous=False), 
    "Me": Person("456 St."), 
    ]

>>>people_dict["Charles Lindberg"].address
"123 St." 

创建一个类似乎有点矫枉过正……标准数据类型似乎太基础了……

我想在 Python 中有更好的方法来做到这一点,而不必编写自己的类?

在使用公共键创建嵌套字典时,避免重复代码的最佳方法是什么?

【问题讨论】:

你为什么要担心不同字典中的重复键? 要扩展上述内容,您无需担心嵌套字典中重复的字符串键(内存使用)。 Python 将字符串存储在内存中一次,然后使用指向同一字符串的指针/引用。 我创建的每个子词典都有 15 个相同的键。为了定义父字典,我最终复制并粘贴了一个 TON。这样做感觉不对,但我不知道有什么好的替代方案或最佳做法.. 如果您更多地从性能的角度来看待它,那么 namedtuples docs.python.org/2/library/… 可能就是您所追求的。如果您能详细说明为什么您认为字典不是一个好的解决方案,它将帮助您找到更适合您情况的解决方案。 你想要的是一个命名元组。它们就像你的小类,只是它们包含更多功能并且需要更少的代码来定义。 【参考方案1】:

听起来你有一个数据矩阵,因为每个“行”都有相同的键(列),所以我会使用 NumPy 数组:

import numpy as np

dtype = [('name', object), ('address', object), ('famous', bool)]
people = np.array([
        ("Charles Lindberg", "123 St.", True),
        ("Me", "456 St.", False),
        ], dtype)

charlie = people[people['name'] == 'Charles Lindberg'][0]
print charlie['address']

或者使用更高级的 Pandas:

import pandas as pd
people = pd.DataFrame(people_dict)
print people['Charles Lindberg']['address']

这很容易将您的原始dict-of-dicts people_dict 直接加载到矩阵中,并为您提供类似的查找功能。

【讨论】:

我推荐这种方法,因为我经常发现自己处于同样的情况。虽然,我看不到 people_dict 是如何重复的?我认为您在定义 Person 类时是正确的,通过密钥访问查找它是一种标准的、可接受的方式。 Namedtuples 比 python 对象更轻量级,但在设计工作方面并不会真正为您节省太多。您还可以将 people_dict 变成一个行为类似于具有更多自定义功能的 dic 的类。 @AdamHughes 这是一个有用的细分——在 NamedTuple 的轻量级特性与类对象之间肯定存在权衡。对于问题中定义的具体用法,我认为 NamedTuple 就足够了,另外它还支持 tuple 方法。为什么你支持 NamedTuple 上的 numpy 方法? 我支持 pandas 是因为在我的应用程序中,我几乎总是需要在这样的框架上构建,最终我经常需要基本容器类型无法提供的功能。这取决于项目,我猜。另外,我真的是 pandas 的拥护者,它是基于 numpy 的,但不推荐纯粹的 numpy 方法,只是为了让 OP 清楚。 为了清楚起见,从约翰指出的两种方法来看,我只会打扰 Pandas 方法。在 Pandas 中确实可以完成很多 numpy 操作,所以我会避免直接使用 numpy。【参考方案2】:

首先,您可以阅读上面的链接以获取有关名称元组的更多信息:https://docs.python.org/2/library/collections.html#collections.namedtuple

NamedTuples 可以帮助您避免“重复代码”。您可以为地址创建一个命名元组并使用它来定义。 我特别喜欢对象。 OO 对这个问题有更好的解决方案。您可以创建一个方法将对象导出到字典。

对于函数式范式,最好使用列表、数组和字典,因为有很多方法/函数可以帮助处理这种结构(map、reduce 等)。如果您不假装在您的应用程序中使用某些功能,请转到 OO(面向对象)解决方案。

问候 安德烈

【讨论】:

【参考方案3】:

如果您想要一个所有值都是具有相同或相似键的 dicts 的 dict,您可以定义一个函数来获取值并返回其中一个内部 dicts。

def hash(address, famous): return "address": address, "famous": famous

people_dict = 
    "Charles Lindberg": hash("123 St.", true),
    "Me": hash("456 St.", false)

【讨论】:

以上是关于具有相同键的(嵌套)字典的 Pythonic 替代方案?的主要内容,如果未能解决你的问题,请参考以下文章

从嵌套字典结构列表(具有两个级别)创建数据框的 Pythonic 方法是啥?

列表理解以收集具有最内层键的嵌套字典项目

在没有 NoneType 错误的情况下访问嵌套字典的 pythonic 方法是啥

服务器与本地机器上dict键的随机顺序[重复]

具有相同键的多个条目的字典[重复]

如何使用映射或过滤器而不是列表推导过滤特定值的嵌套字典(pythonic 方式)?