Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Python3中实现insert for OrderedDict_Python_Ordereddictionary - Fatal编程技术网

如何在Python3中实现insert for OrderedDict

如何在Python3中实现insert for OrderedDict,python,ordereddictionary,Python,Ordereddictionary,我想在某个位置将一个项目插入OrderedICT。 使用of SO的答案,我有一个问题,它在Python3上不起作用 这是使用的实现 from collections import OrderedDict class ListDict(OrderedDict): def __init__(self, *args, **kwargs): super(ListDict, self).__init__(*args, **kwargs) def __insertio

我想在某个位置将一个项目插入OrderedICT。 使用of SO的答案,我有一个问题,它在Python3上不起作用

这是使用的实现

from collections import OrderedDict

class ListDict(OrderedDict):

    def __init__(self, *args, **kwargs):
        super(ListDict, self).__init__(*args, **kwargs)

    def __insertion(self, link_prev, key_value):
        key, value = key_value
        if link_prev[2] != key:
            if key in self:
                del self[key]
            link_next = link_prev[1]
            self._OrderedDict__map[key] = link_prev[1] = link_next[0] = [link_prev, link_next, key]
        dict.__setitem__(self, key, value)

    def insert_after(self, existing_key, key_value):
        self.__insertion(self._OrderedDict__map[existing_key], key_value)

    def insert_before(self, existing_key, key_value):
        self.__insertion(self._OrderedDict__map[existing_key][0], key_value)
像这样使用它

ld = ListDict([(1,1), (2,2), (3,3)])
ld.insert_before(2, (1.5, 1.5))
给予

它与Python2.7配合使用。在Python3中失败的原因是什么? 检查实现的源代码显示使用了
self.\uuu map
而不是
self.\u OrderedDict\uu map
。将代码更改为使用
self.\u map

AttributeError: 'ListDict' object has no attribute '_ListDict__map'

为什么?我如何在Python3中实现这一点?OrderedDict使用内部的
\u map
属性来存储双链接列表。那么,我如何才能正确地访问这个属性呢?

我不确定仅仅在代码中使用一个单独的列表和dict是否会更好地为您服务,但下面是一个关于此类对象的纯Python实现的尝试。这将比Python3.5中的实际
OrderedDict
慢一个数量级,正如我在评论中指出的那样

from collections import OrderedDict

od1 = OrderedDict([
    ('a', 1),
    ('b', 2),
    ('d', 4),
])

items = od1.items()
items.insert(2, ('c', 3))
od2 = OrderedDict(items)

print(od2)  # OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
我最终实现了整个
collections.abc.MutableMapping
契约,因为没有一个方法很长,但您可能不会全部使用它们。特别是,
\uuu eq\uu
popitem
有点随意。我将您在
insert.*
方法上的签名更改为4参数签名,这让我感觉更自然一些。最后一点注意:仅在Python3.5上测试。如果没有一些(微小的)更改,肯定无法在Python 2上工作。

因为Python 3.2可以用来在一个文件中移动项目。以下代码将通过将提供的索引后的所有项目移动到末尾来实现插入功能

请注意,这不是很有效,应该节约使用(如果有的话)

def ordered_dict_插入(ordered_dict,index,key,value):
如果按顺序输入:
raise KeyError(“密钥已存在”)
如果索引<0或索引>长度(按顺序):
提升索引器(“索引超出范围”)
keys=列表(有序目录keys())[索引:]
有序dict[键]=值
对于k in键:
命令命令移动到末尾(k)

可以进行明显的优化和改进,但这是总体思路。

在3.7中尝试新的dict对象,并认为我应该尝试实现两位炼金术士用他的答案所做的,但只是覆盖本机dict类,因为在3.7中dict是有序的

''' Script that extends python3.7 dictionary to include insert_before and insert_after methods. '''
from sys import exit as sExit

class MutableDict(dict):
    ''' Class that extends python3.7 dictionary to include insert_before and insert_after methods. '''

    def insert_before(self, key, newKey, val):
        ''' Insert newKey:value into dict before key'''
        try:
            __keys = list(self.keys())
            __vals = list(self.values())

            insertAt = __keys.index(key)

            __keys.insert(insertAt, newKey)
            __vals.insert(insertAt, val)

            self.clear()
            self.update({x: __vals[i] for i, x in enumerate(__keys)})

        except ValueError as e:
            sExit(e)

    def insert_after(self, key, newKey, val):
        ''' Insert newKey:value into dict after key'''
        try:
            __keys = list(self.keys())
            __vals = list(self.values())

            insertAt = __keys.index(key) + 1

            if __keys[-1] != key:
                __keys.insert(insertAt, newKey)
                __vals.insert(insertAt, val)
                self.clear()
                self.update({x: __vals[i] for i, x in enumerate(__keys)})
            else:
                self.update({newKey: val})

        except ValueError as e:
            sExit(e)
一点测试:

 In: v = MutableDict([('a', 1), ('b', 2), ('c', 3)])
Out: {'a': 1, 'b': 2, 'c': 3}

 In: v.insert_before('a', 'g', 5)
Out: {'g': 5, 'a': 1, 'b': 2, 'c': 3}

 In: v.insert_after('b', 't', 5)
Out: {'g': 5, 'a': 1, 'b': 2, 't': 5, 'c': 3}
编辑:我决定做一个小的基准测试,看看这会带来什么样的性能冲击。我将使用
from timeit import timeit

获取基线。创建具有任意值的dict

 In: timeit('{x: ord(x) for x in string.ascii_lowercase[:27]}', setup='import string', number=1000000)
Out: 1.8214202160015702
查看使用与以前相同的任意值初始化MutableDict需要多长时间

 In: timeit('MD({x: ord(x) for x in string.ascii_lowercase[:27]})', setup='import string; from MutableDict import MutableDict as MD', number=1000000)
Out: 2.382507269998314
1.82/2.38=0.76。所以,如果我考虑一下这个正确的情况,MutableDict的创建速度要慢24%

让我们看看插入需要多长时间。对于这个测试,我将使用insert_after方法,因为它稍微大一些。还将在靠近末端的位置查找一个键以进行插入。”在这种情况下是不行的

 In: timeit('v.insert_after("t", "zzrr", ord("z"))', setup='import string; from MutableDict import MutableDict as MD; v = MD({x: ord(x) for x in string.ascii_lowercase[:27]})' ,number=1000000)
Out: 3.9161406760104
2.38/3.91=0.60,插入_后比初始化时慢40%。在一个100万个循环的小测试中还不错。为了比较时间关系,我们将测试:

 In: timeit('"-".join(map(str, range(100)))', number=1000000)
Out: 10.342204540997045

不是一个苹果对苹果的比较,但我希望这些测试将帮助您(读者不一定是OP)决定在3.7项目中使用或不使用该类。

如果问题是为什么
self.\u map
不起作用,请参阅。至于为什么代码可以在python2中工作,而不能在python3中工作,我不知道。非常有用,谢谢。我知道这个双下划线规则。但它并没有回答这个问题。我相信,
OrderedDict
是,所以可能在Python中不再可以访问以前的任何私有结构
self.\uu map
。这就是为什么当开发人员使用他们所拥有的任何一点东西来表示Python中的某些东西是不能弄乱的时,您应该倾听,而不是试图在您的子类中依赖它。实现细节会发生变化,您会被搞砸。这不会在
OrderedICT
上实现插入。这将创建一个全新的OrderedDict。感谢您提供完整的代码片段!在我的问题中,我尝试使用init文件的ordered dict的python-only实现,并在那里重新实现了insert_*方法。有趣的是,一个性能基准测试显示,它的速度(对于一个小的dict)是您的或“列表并从修改后的列表创建一个新的有序dict”实现的3倍。我只是希望看到将OrderedICT子类化变得更容易。。。
 In: timeit('MD({x: ord(x) for x in string.ascii_lowercase[:27]})', setup='import string; from MutableDict import MutableDict as MD', number=1000000)
Out: 2.382507269998314
 In: timeit('v.insert_after("t", "zzrr", ord("z"))', setup='import string; from MutableDict import MutableDict as MD; v = MD({x: ord(x) for x in string.ascii_lowercase[:27]})' ,number=1000000)
Out: 3.9161406760104
 In: timeit('"-".join(map(str, range(100)))', number=1000000)
Out: 10.342204540997045