如何使用特定的数据结构作为defaultdict的default_factory?

时间:2015-07-30 12:23:44

标签: python dictionary python-collections

我目前正在使用<AzureSDKVersion Condition ="'$(AzureSDKVersion)' == '' ">2.5</AzureSDKVersion> <VisualStudioVersion Condition=" '$(VisualStudioVersion)' == '' ">10.0</VisualStudioVersion> <CloudExtensionsDir Condition=" '$(CloudExtensionsDir)' == '' ">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Windows Azure Tools\$(AzureSDKVersion)\</CloudExtensionsDir> defaultdict来为不可预测的密钥唯一计算几个不可预测的值:

Counter

这给了我预期的结果:

from collections import defaultdict, Counter

d = defaultdict(Counter)
d['x']['b'] += 1
d['x']['c'] += 1
print(d)

我现在需要扩展defaultdict(<class 'collections.Counter'>, {'x': Counter({'c': 1, 'b': 1})}) 中值的结构,并使用两个键设为defaultdict:上一个dict和一个Counter

str

是否可以将特定数据结构(如上所述)用作mystruct = { 'counter': collections.Counter(), 'name': '' } 中的default_factory?预期的结果是,对于defaultdict中的每个不存在的键,将创建一个使用上述结构初始化的新键和值。

2 个答案:

答案 0 :(得分:8)

您只需要将default_factory定义为一个函数,该函数返回您想要默认的字典:

from collections import defaultdict, Counter
d = defaultdict(lambda: {'counter': Counter(), 'name': ''})
d['x']['counter']['b'] += 1
d['x']['counter']['c'] += 1
print(d)

如果你不熟悉lambda,那就是:

def my_factory():
    aDict = {'counter': Counter(), 'name':''}
    return aDict
d = defaultdict(my_factory)

答案 1 :(得分:1)

drootang 的另一个解决方案是使用自定义类:

from collections import defaultdict, Counter

class NamedCounter:
    def __init__(self, name = '', counter = None):
        self.counter = counter if counter else Counter()
        self.name = name

    def __repr__(self):
        return 'NamedCounter(name={}, counter={})'.format(
                repr(self.name), repr(self.counter))

d = defaultdict(NamedCounter)
d['x'].counter['b'] += 1
d['x'].counter['b'] += 1
d['x'].name = 'X counter'
print(d)
  

defaultdict(&lt; class __main __。NamedCounter at 0x19de808&gt;,{'x':NamedCounter(name ='X counter',counter = Counter({'b':2}))})

或者,您可以扩展Counter以将名称合并到计数器本身:

from collections import defaultdict, Counter

class NamedCounter(Counter):
    def __init__(self, name = '', dict = None):
        super(Counter, self).__init__(dict if dict else {})
        self.name = name

    def __repr__(self):
        return 'NamedCounter(name={}, dict={})'.format(
                repr(self.name), super(Counter, self).__repr__())

d = defaultdict(NamedCounter)
d['x']['b'] += 1
d['x']['b'] += 1
d['x'].name = 'X counter'
print(d)
  

defaultdict(&lt; class'__ main __。NamedCounter'&gt;,{'x':NamedCounter(name ='X counter',dict = {'b':2})})