实现嵌套字典的最佳方法是什么?

2024-12-03 08:44:00
admin
原创
158
摘要:问题描述:我有一个数据结构,它本质上相当于一个嵌套字典。假设它看起来像这样:{'new jersey': {'mercer county': {'plumbers': 3, 'programmers': 81}, ...

问题描述:

我有一个数据结构,它本质上相当于一个嵌套字典。假设它看起来像这样:

{'new jersey': {'mercer county': {'plumbers': 3,
                                  'programmers': 81},
                'middlesex county': {'programmers': 81,
                                     'salesmen': 62}},
 'new york': {'queens county': {'plumbers': 9,
                                'salesmen': 36}}}

现在,维护和创建这个非常痛苦;每当我有一个新的州/县/职业时,我都必须通过令人讨厌的 try/catch 块创建下层字典。此外,如果我想遍历所有值,我必须创建烦人的嵌套迭代器。

我还可以使用元组作为键,如下所示:

{('new jersey', 'mercer county', 'plumbers'): 3,
 ('new jersey', 'mercer county', 'programmers'): 81,
 ('new jersey', 'middlesex county', 'programmers'): 81,
 ('new jersey', 'middlesex county', 'salesmen'): 62,
 ('new york', 'queens county', 'plumbers'): 9,
 ('new york', 'queens county', 'salesmen'): 36}

这使得对值的迭代变得非常简单和自然,但是从语法上讲,执行诸如聚合和查看字典子集之类的操作会更加痛苦(例如,如果我只想逐个状态地进行)。

基本上,有时我想将嵌套字典视为平面字典,有时我想将其视为复杂的层次结构。我可以将其全部包装在一个类中,但似乎有人可能已经这样做了。或者,似乎可能有一些非常优雅的语法结构可以做到这一点。

我怎样才能做得更好?

附录:我知道,setdefault()但这确实不构成清晰的语法。此外,您创建的每个子词典仍需要setdefault()手动设置。


解决方案 1:

在 Python 中实现嵌套字典的最佳方法是什么?

这是个坏主意,不要这么做。相反,使用普通字典并使用dict.setdefaultwhere apropos,这样当正常使用下缺少键时,您就会得到预期的结果KeyError。如果您坚持要得到这种行为,以下是如何搬起石头砸自己的脚:

__missing__在子类上实现dict以设置并返回新实例。

这种方法从 Python 2.5 开始就可用(并且有文档记录) ,并且(对我来说特别有价值)它可以像普通 dict 一样漂亮地打印,而不是自动生成的 defaultdict 的丑陋打印:

class Vividict(dict):
    def __missing__(self, key):
        value = self[key] = type(self)() # retain local pointer to value
        return value                     # faster to return than dict lookup

(注意self[key]在赋值的左边,所以这里没有递归。)

假设你有一些数据:

data = {('new jersey', 'mercer county', 'plumbers'): 3,
        ('new jersey', 'mercer county', 'programmers'): 81,
        ('new jersey', 'middlesex county', 'programmers'): 81,
        ('new jersey', 'middlesex county', 'salesmen'): 62,
        ('new york', 'queens county', 'plumbers'): 9,
        ('new york', 'queens county', 'salesmen'): 36}

这是我们的用法代码:

vividict = Vividict()
for (state, county, occupation), number in data.items():
    vividict[state][county][occupation] = number

现在:

>>> import pprint
>>> pprint.pprint(vividict, width=40)
{'new jersey': {'mercer county': {'plumbers': 3,
                                  'programmers': 81},
                'middlesex county': {'programmers': 81,
                                     'salesmen': 62}},
 'new york': {'queens county': {'plumbers': 9,
                                'salesmen': 36}}}

批评

对这种类型的容器的批评是,如果用户拼错了一个键,我们的代码可能会默默失败:

>>> vividict['new york']['queens counyt']
{}

此外,现在我们的数据中有一个拼写错误的县:

>>> pprint.pprint(vividict, width=40)
{'new jersey': {'mercer county': {'plumbers': 3,
                                  'programmers': 81},
                'middlesex county': {'programmers': 81,
                                     'salesmen': 62}},
 'new york': {'queens county': {'plumbers': 9,
                                'salesmen': 36},
              'queens counyt': {}}}

解释:

每当访问但缺少某个键时,我们都会提供类的另一个嵌套实例Vividict。(返回值分配很有用,因为它避免了我们在字典上额外调用 getter,不幸的是,我们不能在设置它时返回它。)

请注意,这些与获得最多支持的答案的语义相同,但代码行数只有一半——nosklo 的实现:

class AutoVivification(dict):
    """Implementation of perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value

使用演示

下面只是一个例子,说明如何轻松使用此字典动态创建嵌套字典结构。这可以快速创建您想要的深度的分层树结构。

import pprint

class Vividict(dict):
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value

d = Vividict()

d['foo']['bar']
d['foo']['baz']
d['fizz']['buzz']
d['primary']['secondary']['tertiary']['quaternary']
pprint.pprint(d)

输出:

{'fizz': {'buzz': {}},
 'foo': {'bar': {}, 'baz': {}},
 'primary': {'secondary': {'tertiary': {'quaternary': {}}}}}

正如最后一行所示,它打印得非常漂亮,并且便于手动检查。但是,如果您想直观地检查数据,那么将__missing__其类的新实例设置为键并返回它是一种更好的解决方案。

相比之下,其他替代方案如下:

dict.setdefault

尽管提问者认为这并不干净,但我觉得这比Vividict我自己的要好。

d = {} # or dict()
for (state, county, occupation), number in data.items():
    d.setdefault(state, {}).setdefault(county, {})[occupation] = number

现在:

>>> pprint.pprint(d, width=40)
{'new jersey': {'mercer county': {'plumbers': 3,
                                  'programmers': 81},
                'middlesex county': {'programmers': 81,
                                     'salesmen': 62}},
 'new york': {'queens county': {'plumbers': 9,
                                'salesmen': 36}}}

拼写错误会导致错误,并且不会用错误的信息扰乱我们的数据:

>>> d['new york']['queens counyt']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'queens counyt'

此外,我认为 setdefault 在循环中使用时效果很好,而且您不知道要获得什么键,但重复使用会变得非常麻烦,而且我认为没有人愿意继续这样做:

d = dict()

d.setdefault('foo', {}).setdefault('bar', {})
d.setdefault('foo', {}).setdefault('baz', {})
d.setdefault('fizz', {}).setdefault('buzz', {})
d.setdefault('primary', {}).setdefault('secondary', {}).setdefault('tertiary', {}).setdefault('quaternary', {})

另一个批评是,无论是否使用 setdefault,它都需要一个新实例。但是,Python(或至少 CPython)在处理未使用和未引用的新实例方面相当聪明,例如,它重用内存中的位置:

>>> id({}), id({}), id({})
(523575344, 523575344, 523575344)

自动激活的默认字典

这是一个简洁的实现,并且在您不检查数据的脚本中使用它将与实现一样有用__missing__

from collections import defaultdict

def vivdict():
    return defaultdict(vivdict)

但是如果您需要检查数据,则以相同方式填充数据的自动生动的默认字典的结果如下所示:

>>> d = vivdict(); d['foo']['bar']; d['foo']['baz']; d['fizz']['buzz']; d['primary']['secondary']['tertiary']['quaternary']; import pprint; 
>>> pprint.pprint(d)
defaultdict(<function vivdict at 0x17B01870>, {'foo': defaultdict(<function vivdict 
at 0x17B01870>, {'baz': defaultdict(<function vivdict at 0x17B01870>, {}), 'bar': 
defaultdict(<function vivdict at 0x17B01870>, {})}), 'primary': defaultdict(<function 
vivdict at 0x17B01870>, {'secondary': defaultdict(<function vivdict at 0x17B01870>, 
{'tertiary': defaultdict(<function vivdict at 0x17B01870>, {'quaternary': defaultdict(
<function vivdict at 0x17B01870>, {})})})}), 'fizz': defaultdict(<function vivdict at 
0x17B01870>, {'buzz': defaultdict(<function vivdict at 0x17B01870>, {})})})

这个输出非常不雅观,结果也非常难以阅读。通常给出的解决方案是递归地转换回字典以供手动检查。这个非平凡的解决方案留给读者作为练习。

表现

最后,我们来看看性能。我减去了实例化的成本。

>>> import timeit
>>> min(timeit.repeat(lambda: {}.setdefault('foo', {}))) - min(timeit.repeat(lambda: {}))
0.13612580299377441
>>> min(timeit.repeat(lambda: vivdict()['foo'])) - min(timeit.repeat(lambda: vivdict()))
0.2936999797821045
>>> min(timeit.repeat(lambda: Vividict()['foo'])) - min(timeit.repeat(lambda: Vividict()))
0.5354437828063965
>>> min(timeit.repeat(lambda: AutoVivification()['foo'])) - min(timeit.repeat(lambda: AutoVivification()))
2.138362169265747

基于性能,dict.setdefault效果最佳。如果您关心执行速度,我强烈建议您将其用于生产代码。

如果您需要将其用于交互式使用(可能在 IPython 笔记本中),那么性能实际上并不重要 - 在这种情况下,我会选择 Vividict 以提高输出的可读性。与 AutoVivification 对象(使用__getitem__而不是__missing__,这是为此目的而制作的)相比,它要优越得多。

结论

__missing__在子类上实现dict设置并返回新实例比其他方法稍微困难一些,但具有以下好处:

  • 容易实例化

  • 轻松填充数据

  • 轻松查看数据

并且由于它比修改更简单且性能更高__getitem__,因此应该优先于该方法。

然而,它也有缺点:

  • 错误的查找将会悄悄失败。

  • 错误的查找仍会保留在字典中。

因此,我个人更喜欢setdefault其他解决方案,并且在每种需要这种行为的情况下我都会这样做。

解决方案 2:

class AutoVivification(dict):
    """Implementation of perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value

测试:

a = AutoVivification()

a[1][2][3] = 4
a[1][3][3] = 5
a[1][2]['test'] = 6

print a

输出:

{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}}

解决方案 3:

只是因为我还没有见过这么小的字典,这里有一个可以根据需要嵌套的字典,毫不费力:

# yo dawg, i heard you liked dicts                                                                      
def yodict():
    return defaultdict(yodict)

解决方案 4:

您可以创建一个 YAML 文件并使用PyYaml读取它。

步骤 1:创建一个 YAML 文件“employment.yml”:

new jersey:
  mercer county:
    pumbers: 3
    programmers: 81
  middlesex county:
    salesmen: 62
    programmers: 81
new york:
  queens county:
    plumbers: 9
    salesmen: 36

第 2 步:用 Python 读取

import yaml
file_handle = open("employment.yml")
my_shnazzy_dictionary = yaml.safe_load(file_handle)
file_handle.close()

现在my_shnazzy_dictionary已包含所有值。如果您需要即时执行此操作,则可以将 YAML 创建为字符串并将其输入到yaml.safe_load(...)

解决方案 5:

由于您有一个星型模式设计,您可能希望将其结构设计得更像关系表而不是字典。

import collections

class Jobs( object ):
    def __init__( self, state, county, title, count ):
        self.state= state
        self.count= county
        self.title= title
        self.count= count

facts = [
    Jobs( 'new jersey', 'mercer county', 'plumbers', 3 ),
    ...

def groupBy( facts, name ):
    total= collections.defaultdict( int )
    for f in facts:
        key= getattr( f, name )
        total[key] += f.count

这种事情对于创建类似数据仓库的设计而没有 SQL 开销大有帮助。

解决方案 6:

如果嵌套级别数较少,我会使用collections.defaultdict这个:

from collections import defaultdict

def nested_dict_factory(): 
  return defaultdict(int)
def nested_dict_factory2(): 
  return defaultdict(nested_dict_factory)
db = defaultdict(nested_dict_factory2)

db['new jersey']['mercer county']['plumbers'] = 3
db['new jersey']['mercer county']['programmers'] = 81

这样使用defaultdict可以避免很多混乱的setdefault()get()等等。

解决方案 7:

这是一个返回任意深度的嵌套字典的函数:

from collections import defaultdict
def make_dict():
    return defaultdict(make_dict)

使用方式如下:

d=defaultdict(make_dict)
d["food"]["meat"]="beef"
d["food"]["veggie"]="corn"
d["food"]["sweets"]="ice cream"
d["animal"]["pet"]["dog"]="collie"
d["animal"]["pet"]["cat"]="tabby"
d["animal"]["farm animal"]="chicken"

使用类似这样的方法迭代所有内容:

def iter_all(d,depth=1):
    for k,v in d.iteritems():
        print "-"*depth,k
        if type(v) is defaultdict:
            iter_all(v,depth+1)
        else:
            print "-"*(depth+1),v

iter_all(d)

打印出:

- food
-- sweets
--- ice cream
-- meat
--- beef
-- veggie
--- corn
- animal
-- pet
--- dog
---- labrador
--- cat
---- tabby
-- farm animal
--- chicken

您可能最终希望使新项目无法添加到字典中。可以很容易地将所有这些defaultdicts 递归转换为普通dicts。

def dictify(d):
    for k,v in d.iteritems():
        if isinstance(v,defaultdict):
            d[k] = dictify(v)
    return dict(d)

解决方案 8:

正如其他人所建议的那样,关系数据库对您来说可能更有用。您可以使用内存中的 sqlite3 数据库作为数据结构来创建表,然后查询它们。

import sqlite3

c = sqlite3.Connection(':memory:')
c.execute('CREATE TABLE jobs (state, county, title, count)')

c.executemany('insert into jobs values (?, ?, ?, ?)', [
    ('New Jersey', 'Mercer County',    'Programmers', 81),
    ('New Jersey', 'Mercer County',    'Plumbers',     3),
    ('New Jersey', 'Middlesex County', 'Programmers', 81),
    ('New Jersey', 'Middlesex County', 'Salesmen',    62),
    ('New York',   'Queens County',    'Salesmen',    36),
    ('New York',   'Queens County',    'Plumbers',     9),
])

# some example queries
print list(c.execute('SELECT * FROM jobs WHERE county = "Queens County"'))
print list(c.execute('SELECT SUM(count) FROM jobs WHERE title = "Programmers"'))

这只是一个简单的例子。您可以为州、县和职位定义单独的表。

解决方案 9:

我发现它setdefault非常有用;它检查键是否存在,如果不存在则添加它:

d = {}
d.setdefault('new jersey', {}).setdefault('mercer county', {})['plumbers'] = 3

setdefault始终返回相关的键,因此您实际上是在更新“ ”的值d

当谈到迭代时,我相信如果 Python 中还没有生成器,你可以很容易地编写一个:

def iterateStates(d):
    # Let's count up the total number of "plumbers" / "dentists" / etc.
    # across all counties and states
    job_totals = {}

    # I guess this is the annoying nested stuff you were talking about?
    for (state, counties) in d.iteritems():
        for (county, jobs) in counties.iteritems():
            for (job, num) in jobs.iteritems():
                # If job isn't already in job_totals, default it to zero
                job_totals[job] = job_totals.get(job, 0) + num

    # Now return an iterator of (job, number) tuples
    return job_totals.iteritems()

# Display all jobs
for (job, num) in iterateStates(d):
    print "There are %d %s in total" % (job, num)

解决方案 10:

collections.defaultdict可以将其子类化以创建嵌套字典。然后将任何有用的迭代方法添加到该类中。

>>> from collections import defaultdict
>>> class nesteddict(defaultdict):
    def __init__(self):
        defaultdict.__init__(self, nesteddict)
    def walk(self):
        for key, value in self.iteritems():
            if isinstance(value, nesteddict):
                for tup in value.walk():
                    yield (key,) + tup
            else:
                yield key, value


>>> nd = nesteddict()
>>> nd['new jersey']['mercer county']['plumbers'] = 3
>>> nd['new jersey']['mercer county']['programmers'] = 81
>>> nd['new jersey']['middlesex county']['programmers'] = 81
>>> nd['new jersey']['middlesex county']['salesmen'] = 62
>>> nd['new york']['queens county']['plumbers'] = 9
>>> nd['new york']['queens county']['salesmen'] = 36
>>> for tup in nd.walk():
    print tup


('new jersey', 'mercer county', 'programmers', 81)
('new jersey', 'mercer county', 'plumbers', 3)
('new jersey', 'middlesex county', 'programmers', 81)
('new jersey', 'middlesex county', 'salesmen', 62)
('new york', 'queens county', 'salesmen', 36)
('new york', 'queens county', 'plumbers', 9)

解决方案 11:

您可以使用 Addict: https: //github.com/mewwts/addict

>>> from addict import Dict
>>> my_new_shiny_dict = Dict()
>>> my_new_shiny_dict.a.b.c.d.e = 2
>>> my_new_shiny_dict
{'a': {'b': {'c': {'d': {'e': 2}}}}}

解决方案 12:

至于“令人讨厌的 try/catch 块”:

d = {}
d.setdefault('key',{}).setdefault('inner key',{})['inner inner key'] = 'value'
print d

产量

{'key': {'inner key': {'inner inner key': 'value'}}}

您可以使用它将平面字典格式转换为结构化格式:

fd = {('new jersey', 'mercer county', 'plumbers'): 3,
 ('new jersey', 'mercer county', 'programmers'): 81,
 ('new jersey', 'middlesex county', 'programmers'): 81,
 ('new jersey', 'middlesex county', 'salesmen'): 62,
 ('new york', 'queens county', 'plumbers'): 9,
 ('new york', 'queens county', 'salesmen'): 36}

for (k1,k2,k3), v in fd.iteritems():
    d.setdefault(k1, {}).setdefault(k2, {})[k3] = v

解决方案 13:

defaultdict()是你的朋友!

对于二维字典,您可以执行以下操作:

d = defaultdict(defaultdict)
d[1][2] = 3

如需更多维度,您可以:

d = defaultdict(lambda :defaultdict(defaultdict))
d[1][2][3] = 4

解决方案 14:

为了轻松迭代嵌套字典,为什么不编写一个简单的生成器呢?

def each_job(my_dict):
    for state, a in my_dict.items():
        for county, b in a.items():
            for job, value in b.items():
                yield {
                    'state'  : state,
                    'county' : county,
                    'job'    : job,
                    'value'  : value
                }

因此,如果您有复杂的嵌套字典,对它进行迭代就变得简单:

for r in each_job(my_dict):
    print "There are %d %s in %s, %s" % (r['value'], r['job'], r['county'], r['state'])

显然,您的生成器可以产生对您有用的任何格式的数据。

为什么要使用 try catch 块来读取树?在尝试检索键之前查询字典中是否存在该键非常简单(并且可能更安全)。使用保护子句的函数可能如下所示:

if not my_dict.has_key('new jersey'):
    return False

nj_dict = my_dict['new jersey']
...

或者,也许有点冗长的方法是使用 get 方法:

value = my_dict.get('new jersey', {}).get('middlesex county', {}).get('salesmen', 0)

但是,如果想要更简洁一些,您可能需要考虑使用collections.defaultdict,它是自 python 2.5 以来标准库的一部分。

import collections

def state_struct(): return collections.defaultdict(county_struct)
def county_struct(): return collections.defaultdict(job_struct)
def job_struct(): return 0

my_dict = collections.defaultdict(state_struct)

print my_dict['new jersey']['middlesex county']['salesmen']

我在这里对您的数据结构的含义做出了假设,但应该很容易根据您实际想要做的事情进行调整。

解决方案 15:

我喜欢将其包装在一个类中并实现的想法__getitem____setitem__这样他们就实现了一种简单的查询语言:

>>> d['new jersey/mercer county/plumbers'] = 3
>>> d['new jersey/mercer county/programmers'] = 81
>>> d['new jersey/mercer county/programmers']
81
>>> d['new jersey/mercer country']
<view which implicitly adds 'new jersey/mercer county' to queries/mutations>

如果你想要更高级一点,你也可以实现类似这样的功能:

>>> d['*/*/programmers']
<view which would contain 'programmers' entries>

但我认为实现这样的事情会非常有趣 :D

解决方案 16:

除非您的数据集非常小,否则您可能需要考虑使用关系数据库。它将完全满足您的需求:轻松添加计数、选择计数子集,甚至按州、县、职业或这些的任意组合汇总计数。

解决方案 17:

class JobDb(object):
    def __init__(self):
        self.data = []
        self.all = set()
        self.free = []
        self.index1 = {}
        self.index2 = {}
        self.index3 = {}

    def _indices(self,(key1,key2,key3)):
        indices = self.all.copy()
        wild = False
        for index,key in ((self.index1,key1),(self.index2,key2),
                                             (self.index3,key3)):
            if key is not None:
                indices &= index.setdefault(key,set())
            else:
                wild = True
        return indices, wild

    def __getitem__(self,key):
        indices, wild = self._indices(key)
        if wild:
            return dict(self.data[i] for i in indices)
        else:
            values = [self.data[i][-1] for i in indices]
            if values:
                return values[0]

    def __setitem__(self,key,value):
        indices, wild = self._indices(key)
        if indices:
            for i in indices:
                self.data[i] = key,value
        elif wild:
            raise KeyError(k)
        else:
            if self.free:
                index = self.free.pop(0)
                self.data[index] = key,value
            else:
                index = len(self.data)
                self.data.append((key,value))
                self.all.add(index)
            self.index1.setdefault(key[0],set()).add(index)
            self.index2.setdefault(key[1],set()).add(index)
            self.index3.setdefault(key[2],set()).add(index)

    def __delitem__(self,key):
        indices,wild = self._indices(key)
        if not indices:
            raise KeyError
        self.index1[key[0]] -= indices
        self.index2[key[1]] -= indices
        self.index3[key[2]] -= indices
        self.all -= indices
        for i in indices:
            self.data[i] = None
        self.free.extend(indices)

    def __len__(self):
        return len(self.all)

    def __iter__(self):
        for key,value in self.data:
            yield key

例子:

>>> db = JobDb()
>>> db['new jersey', 'mercer county', 'plumbers'] = 3
>>> db['new jersey', 'mercer county', 'programmers'] = 81
>>> db['new jersey', 'middlesex county', 'programmers'] = 81
>>> db['new jersey', 'middlesex county', 'salesmen'] = 62
>>> db['new york', 'queens county', 'plumbers'] = 9
>>> db['new york', 'queens county', 'salesmen'] = 36

>>> db['new york', None, None]
{('new york', 'queens county', 'plumbers'): 9,
 ('new york', 'queens county', 'salesmen'): 36}

>>> db[None, None, 'plumbers']
{('new jersey', 'mercer county', 'plumbers'): 3,
 ('new york', 'queens county', 'plumbers'): 9}

>>> db['new jersey', 'mercer county', None]
{('new jersey', 'mercer county', 'plumbers'): 3,
 ('new jersey', 'mercer county', 'programmers'): 81}

>>> db['new jersey', 'middlesex county', 'programmers']
81

>>>

编辑:现在使用通配符(None)查询时返回字典,否则返回单个值。

解决方案 18:

我也有类似的事情。我有很多这样的情况:

thedict = {}
for item in ('foo', 'bar', 'baz'):
  mydict = thedict.get(item, {})
  mydict = get_value_for(item)
  thedict[item] = mydict

但深入到很多层面。关键是“.get(item, {})”,因为如果还没有字典,它会创建另一个字典。与此同时,我一直在想办法更好地处理这个问题。现在,有很多

value = mydict.get('foo', {}).get('bar', {}).get('baz', 0)

因此,我做了:

def dictgetter(thedict, default, *args):
  totalargs = len(args)
  for i,arg in enumerate(args):
    if i+1 == totalargs:
      thedict = thedict.get(arg, default)
    else:
      thedict = thedict.get(arg, {})
  return thedict

如果你这样做,效果是一样的:

value = dictgetter(mydict, 0, 'foo', 'bar', 'baz')

好些了吗?我想是的。

解决方案 19:

您可以在 lambda 和 defaultdict 中使用递归,无需定义名称:

a = defaultdict((lambda f: f(f))(lambda g: lambda:defaultdict(g(g))))

以下是一个例子:

>>> a['new jersey']['mercer county']['plumbers']=3
>>> a['new jersey']['middlesex county']['programmers']=81
>>> a['new jersey']['mercer county']['programmers']=81
>>> a['new jersey']['middlesex county']['salesmen']=62
>>> a
defaultdict(<function __main__.<lambda>>,
        {'new jersey': defaultdict(<function __main__.<lambda>>,
                     {'mercer county': defaultdict(<function __main__.<lambda>>,
                                  {'plumbers': 3, 'programmers': 81}),
                      'middlesex county': defaultdict(<function __main__.<lambda>>,
                                  {'programmers': 81, 'salesmen': 62})})})

解决方案 20:

我曾经使用过这个功能。它安全、快速、易于维护。

def deep_get(dictionary, keys, default=None):
    return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)

例子 :

>>> from functools import reduce
>>> def deep_get(dictionary, keys, default=None):
...     return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)
...
>>> person = {'person':{'name':{'first':'John'}}}
>>> print (deep_get(person, "person.name.first"))
John
>>> print (deep_get(person, "person.name.lastname"))
None
>>> print (deep_get(person, "person.name.lastname", default="No lastname"))
No lastname
>>>

解决方案 21:

对于以下内容(从上面复制),有没有办法实现附加函数。我正在尝试使用嵌套字典将值存储为数组。

class Vividict(dict):
    def __missing__(self, key):
        value = self[key] = type(self)() # retain local pointer to value
    return value  

我目前的实现如下:

totalGeneHash=Vividict()
        
for keys in GenHash:
    for second in GenHash[keys]:
        if keys in sampleHash:
            total_val = GenHash[keys][second]
                totalGeneHash[gene][keys].append(total_val)
This is the error I get: AttributeError: 'Vividict' object has no attribute 'append'

解决方案 22:

我可以把这一切都放到一个类中,但似乎有人可能已经这样做了。

NestedDict开源软件包(我是作者)中的课程试图ndicts减轻处理嵌套字典的痛苦。我认为它满足了问题要求的所有要求。

这里是其功能的摘要,更多详细信息请查看文档。

初始化

>>> from ndicts import NestedDict
>>> nd = NestedDict({"a": {"aa": 0}, "b": 1})

获取物品

将其想象成一NestedDict本扁平的字典。

>>> nd["a", "aa"]
0

同时,您可以获取中间节点,而不仅仅是叶值。

>>> nd["a"]
{"aa": 0}

如果不存在键,则会引发异常。

>>> nd["asd"]
Traceback (most recent call last):
...
KeyError: ('asd',)

设置项目

与普通字典一样,如果缺少键,则会将其添加到中NestedDict

>>> nd["a", "ab"] = 2
>>> nd
NestedDict({"a": {"aa": 0, "ab": 2}, "b": 1})

这允许从空的开始,NestedDict通过设置新项目使其变得生动。

迭代

说到迭代,可以把 想象成一个NestedDict扁平的字典。可以使用熟悉的.keys().values()和方法。.item()

>>> [key for key in nd]
[('a', 'aa'), ('a', 'ab'), ('b',)]
>>> [value for value in nd.values()]
[0, 2, 1]
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用