用numpy支持覆盖dict [英] Override a dict with numpy support

查看:110
本文介绍了用numpy支持覆盖dict的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 Python中的基本想法:如何完美覆盖一个dict ,我根据应该支持分配点分隔键的字典编写一个类,即 Extendeddict('level1.level2','value')== {'level1':{ 'level2':'value'}}



代码是

 导入集合
import numpy

class Extendeddict(collections.MutableMapping):
添加功能以支持链接键的Dictionary重载类,例如ABC
:rtype:Extendeddict

#noinspection PyMissingConstructor
def __init __(self,* args,** kwargs):
self._store = dict ()
self.update(dict(* args,** kwargs))

def __getitem __(self,key):
keys = self._keytransform(key)
print'原始密钥:{0} \\\
Transformed keys:{1}'。format(key,keys)
if len(keys)== 1:
return self._store [key]
else:
key1 ='。'。join(ke ys [1:])
如果self._store中的键[0]:
subdict = Extendeddict(self [keys [0]]或{})
try:
return $ key $($)
$ key $($)

def __setitem __(self,key,value )
keys = self._keytransform(key)
如果len(keys)== 1:
self._store [key] = value
else:
key1 ='。'。join(keys [1:])
subdict = Extendeddict(self.get(keys [0])或{})
subdict.update({key1:value})
self._store [keys [0]] = subdict._store

def __delitem __(self,key):
keys = self._keytransform(key)
if len键)== 1:
del self._store [key]
else:
key1 ='。'。join(keys [1:])
del self._store [键[0]] [key1]
如果不是self._store [keys [0]]:
del self._store [keys [0]]

def __iter __(self):
return iter

def __len __(self):
return len(self._store)

def __repr __(self):
return self。 _store .__ repr __()

#noinspection PyMethodMayBeStatic
def _keytransform(self,key):
try:
return key.split('。')
除了:
return [key]

但是使用Python 2.7.10和numpy 1.11。 0,正在运行

  basic = {'Test.field':'test'} 
print' 0}'。format(basic)
print'列表中的正常字典:{0}'。format([basic])
print'numpy array中的正常字典:{0} numpy.array([basic],dtype = object))
print'numpy array.tolist()中的正常字典:{0}'。format(numpy.array([basic],dtype = object).tolist ())

extended_dict = Extendeddict(basic)
print'扩展字典:{0}'。format(extended_dict)
print'列表中的扩展字典:{0}'。format ]
print'numpy array中的扩展字典:{0}'。format(numpy.array([extended_dict],dtype = object))
print'numpy array.tolist()中的扩展字典: {0}'。format(numpy.array([extended_dict],dtype = object).tolist())

我得到:

 正常字典:{'Test.field':'test'} 
正常字典在列表中:[{'Test.field':'test'}]
numpy数组中的正常字典:[{'Test.field':'test'}]
numpy数组中的正常字典。 tolist():[{'Test.field':'test'}]
原始键:测试
转换键:['Test']
扩展字典:{'Test' 'field':'test'}}
列表中的扩展字典:[{'Test':{'field':'test'}}]
原始键:0
转换的ke ys:[0]
追溯(最近的最后一次呼叫):
文件/tmp/scratch_2.py,第77行,< module>
print'numpy array中的扩展字典:{0}'。format(numpy.array([extended_dict],dtype = object))
文件/tmp/scratch_2.py,第20行, __getitem__
return self._store [key]
KeyError:0

而我将期望 print'numpy array中的扩展字典:{0}'。format(numpy.array([extended_dict],dtype = object))导致扩展字典在numpy数组中:[{'Test':{'field':'test'}}]



这可能是错的?这是否是正确的方法?

解决方案

问题出在 np.array 构造函数步。它尝试创建更高维数组。

 在[99]中:basic = {'test.field' :'test'} 

在[100]中:eb = Extendeddict(basic)

在[104]中:eba = np.array([eb],object)
< keys:0,[0]>
---------------------------------------------- -----------------------------
KeyError Traceback(最近的最后一次调用)
< ipython-input -104-5591a58c168a>在< module>()
----> 1 eba = np.array([eb],object)

< ipython-input-88-a7d937b1c8fd> in __getitem __(self,key)
11 keys = self._keytransform(key); print key; print keys
12 if len(keys)== 1:
---> 13 return self._store [key]
14 else:
15 key1 ='。'。join(keys [1:])

KeyError:0

但是,如果我做一个数组,并分配对象它工作正常



在[105]中:eba = np.zeros((1,),object)

在[106]中:eba [0] = eb

在[107]中:eba
Out [107]:array([{'test':{'field':'test'}}],dtype = object)

np.array 是一个棘手的功能,与 D型=对象。比较 np.array([[1,2],[2,3]],dtype = object) np.array([[1 ,2],[2]],D型细胞=对象)。一个是(2,2)另一个(2,)。它尝试制作一个2d数组,只有在失败的情况下才能使用1d列表元素。在这里有一些事情发生在这里。



我看到了两个解决方案 - 一个是关于构建数组的方法,我在其他场合使用过。另一个是找出为什么 np.array 不会挖掘到 dict ,而是与你的。 np.array 被编译,所以可能需要阅读艰难的GITHUB代码。





$ b $我尝试一个解决方案,使用 f = np.frompyfunc(lambda x:x,1,1),但这不起作用(请参阅我的编辑历史记录细节)。但是我发现混合一个 Extendeddict dict 可以正常工作:



[pre> 在[139]中:np.array([eb,basic])
Out [139]:array([{'test':{'field' 'test'}},{'test.field':'test'}],dtype = object)

因此,将其与其他类似或空列表

 <$ c $在[140]中:np.array([eb,[]])
Out [140]:array([{'test':{'field':'test'}},[]] dtype = object)

在[142]中:np.array([eb,None])[: - 1]
Out [142]:array([{'test' 'field':'test'}}],dtype = object)

这是另一个常见的技巧构建列表的对象数组。



如果您给出两个或多个不同长度的 Extendeddict / p>

np.array([eb,Extendeddict({})])。换句话说,如果 len(...)不同(就像混合列表一样)。


Using the base idea from Python: How to "perfectly" override a dict, I coded a class based on dictionaries that should support assigning dot delimited keys, i.e. Extendeddict('level1.level2', 'value') == {'level1':{'level2':'value'}}

The code is

import collections
import numpy

class Extendeddict(collections.MutableMapping):
    """Dictionary overload class that adds functions to support chained keys, e.g. A.B.C          
    :rtype : Extendeddict
    """
    # noinspection PyMissingConstructor
    def __init__(self, *args, **kwargs):
        self._store = dict()
        self.update(dict(*args, **kwargs))

    def __getitem__(self, key):
        keys = self._keytransform(key)
        print 'Original key: {0}\nTransformed keys: {1}'.format(key, keys)
        if len(keys) == 1:
            return self._store[key]
        else:
            key1 = '.'.join(keys[1:])
            if keys[0] in self._store:
                subdict = Extendeddict(self[keys[0]] or {})
                try:
                    return subdict[key1]
                except:
                    raise KeyError(key)
            else:
                raise KeyError(key)

    def __setitem__(self, key, value):
        keys = self._keytransform(key)
        if len(keys) == 1:
            self._store[key] = value
        else:
            key1 = '.'.join(keys[1:])
            subdict = Extendeddict(self.get(keys[0]) or {})
            subdict.update({key1: value})
            self._store[keys[0]] = subdict._store

    def __delitem__(self, key):
        keys = self._keytransform(key)
        if len(keys) == 1:
            del self._store[key]
        else:
            key1 = '.'.join(keys[1:])
            del self._store[keys[0]][key1]
            if not self._store[keys[0]]:
                del self._store[keys[0]]

    def __iter__(self):
        return iter(self._store)

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

    def __repr__(self):
        return self._store.__repr__()

    # noinspection PyMethodMayBeStatic
    def _keytransform(self, key):
        try:
            return key.split('.')
        except:
            return [key]

But with Python 2.7.10 and numpy 1.11.0, running

basic = {'Test.field': 'test'}
print 'Normal dictionary: {0}'.format(basic)
print 'Normal dictionary in a list: {0}'.format([basic])
print 'Normal dictionary in numpy array: {0}'.format(numpy.array([basic], dtype=object))
print 'Normal dictionary in numpy array.tolist(): {0}'.format(numpy.array([basic], dtype=object).tolist())

extended_dict = Extendeddict(basic)
print 'Extended dictionary: {0}'.format(extended_dict)
print 'Extended dictionary in a list: {0}'.format([extended_dict])
print 'Extended dictionary in numpy array: {0}'.format(numpy.array([extended_dict], dtype=object))
print 'Extended dictionary in numpy array.tolist(): {0}'.format(numpy.array([extended_dict], dtype=object).tolist())

I get:

Normal dictionary: {'Test.field': 'test'}
Normal dictionary in a list: [{'Test.field': 'test'}]
Normal dictionary in numpy array: [{'Test.field': 'test'}]
Normal dictionary in numpy array.tolist(): [{'Test.field': 'test'}]
Original key: Test
Transformed keys: ['Test']
Extended dictionary: {'Test': {'field': 'test'}}
Extended dictionary in a list: [{'Test': {'field': 'test'}}]
Original key: 0
Transformed keys: [0]
Traceback (most recent call last):
  File "/tmp/scratch_2.py", line 77, in <module>
    print 'Extended dictionary in numpy array: {0}'.format(numpy.array([extended_dict], dtype=object))
  File "/tmp/scratch_2.py", line 20, in __getitem__
    return self._store[key]
KeyError: 0

Whereas I would expect print 'Extended dictionary in numpy array: {0}'.format(numpy.array([extended_dict], dtype=object)) to result in Extended dictionary in numpy array: [{'Test': {'field': 'test'}}]

Any suggestions on what might be wrong for this? Is this even the right way to do it?

解决方案

The problem is in the np.array constructor step. It digs into its inputs trying to create a higher dimensional array.

In [99]: basic={'test.field':'test'}

In [100]: eb=Extendeddict(basic)

In [104]: eba=np.array([eb],object)
<keys: 0,[0]>
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-104-5591a58c168a> in <module>()
----> 1 eba=np.array([eb],object)

<ipython-input-88-a7d937b1c8fd> in __getitem__(self, key)
     11         keys = self._keytransform(key);print key;print keys
     12         if len(keys) == 1:
---> 13             return self._store[key]
     14         else:
     15             key1 = '.'.join(keys[1:])

KeyError: 0 

But if I make an array, and assign the object it works fine

In [105]: eba=np.zeros((1,),object)

In [106]: eba[0]=eb

In [107]: eba
Out[107]: array([{'test': {'field': 'test'}}], dtype=object)

np.array is a tricky function to use with dtype=object. Compare np.array([[1,2],[2,3]],dtype=object) and np.array([[1,2],[2]],dtype=object). One is (2,2) the other (2,). It tries to make a 2d array, and resorts to 1d with list elements only if that fails. Something along that line is happening here.

I see 2 solutions - one is this round about way of constructing the array, which I've used in other occasions. The other is to figure out why np.array doesn't dig into dict but does with yours. np.array is compiled, so that may require reading tough GITHUB code.


I tried a solution with f=np.frompyfunc(lambda x:x,1,1), but that doesn't work (see my edit history for details). But I found that mixing an Extendeddict with a dict does work:

In [139]: np.array([eb,basic])
Out[139]: array([{'test': {'field': 'test'}}, {'test.field': 'test'}], dtype=object)

So does mixing it with something else like None or an empty list

In [140]: np.array([eb,[]])
Out[140]: array([{'test': {'field': 'test'}}, []], dtype=object)

In [142]: np.array([eb,None])[:-1]
Out[142]: array([{'test': {'field': 'test'}}], dtype=object)

This is another common trick for constructing an object array of lists.

It also works if you give it two or more Extendeddict with different lengths

np.array([eb, Extendeddict({})]). In other words if len(...) differ (just as with mixed lists).

这篇关于用numpy支持覆盖dict的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆