是否有不可变的类字典对象? [英] Is there a dictionary-like object that is immutable?

查看:86
本文介绍了是否有不可变的类字典对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要一个可以灵活获取任何键的Python对象,并且可以像字典一样通过键进行访问,但是它是不可变的。一种选择是灵活地生成 namedtuple ,但是这样做不好吗?在下面的示例中,短绒棉料不会期望 nt 具有属性 a

I would like a Python object that can flexibly take any key and I can access by key, like a dictionary, but is immutable. One option could be to flexibly generate a namedtuple but is it bad practice to do this? In the example below a linter would not expect nt to have attribute a for example.

示例:

from collections import namedtuple

def foo(bar):
    MyNamedTuple = namedtuple("MyNamedTuple", [k for k in bar.keys()])
    d = {k: v for k, v in bar.items()}
    return MyNamedTuple(**d)

>>> nt = foo({"a": 1, "b": 2})


推荐答案

我在评论中提到了它,我不确定为什么需要这样做。

但是可以简单地覆盖 __ setitem __ 词典类。可能这可能(很可能)会导致问题。一个最小的例子是:

I mentioned it in the comments, that I'm not sure why this is needed.
But one could simply override __setitem__ of a dictionary class. Alltho this might (most likely) cause problems down the line. A minimal example of this would be:

class autodict(dict):
    def __init__(self, *args, **kwargs):
        super(autodict, self).__init__(*args, **kwargs)

    def __getitem__(self, key):
        val = dict.__getitem__(self, key)
        return val

    def __setitem__(self, key, val):
        pass

x = autodict({'a' : 1, 'b' : 2})
x['c'] = 3
print(x)

哪个将产生 {'a':1,'b':2} 并因此忽略 x ['c '] = 3 集。

Which will produce {'a': 1, 'b': 2} and thus ignoring the x['c'] = 3 set.

使用字典继承的速度差是命名元组的40-1000倍。 (粗略的速度测试,请参见下文)

The speed difference is some where between 40-1000 times faster using dictionary inheritance compared to named tuples. (See below for crude speed tests)

in 运算符适用于字典,像这样使用时,在命名元组上不太好:

The in operator works on dictionaries, not so well on named tuples when used like this:

'a' in nt == False
'a' in x == True

您可以使用键访问词典样式代替(因为缺少 JavaScript样式

You can use key access dictionary style instead of (for lack of a better term) JavaScript style

x['a'] == nt.a

尽管这是一个品味问题。



您也不要必须对键保持警惕,因为字典基本上支持任何键标识符:

Although that's a matter of taste.

You also don't have to be picky about keys, since dictionaries support essentially any key identifier:

x[1] = 'a number'
nt = foo({1 : 'a number'})

命名元组将导致类型名称和字段名称必须是有效的标识符:'1'

现在,这是一个粗糙的示例,根据系统,位置的不同,会有很大的不同的

Now, this is a crude example, and it would vary a lot depending on the system, the place of the moon in the sky etc.. But as a crude example:

import time
from collections import namedtuple

class autodict(dict):
    def __init__(self, *args, **kwargs):
        super(autodict, self).__init__(*args, **kwargs)
        #self.update(*args, **kwargs)

    def __getitem__(self, key):
        val = dict.__getitem__(self, key)
        return val

    def __setitem__(self, key, val):
        pass

    def __type__(self, *args, **kwargs):
        return dict

def foo(bar):
    MyNamedTuple = namedtuple("MyNamedTuple", [k for k in bar.keys()])
    d = {k: v for k, v in bar.items()}
    return MyNamedTuple(**d)

start = time.time()
for i in range(1000000):
    nt = foo({'x'+str(i) : i})
end = time.time()
print('Named tuples:', end - start,'seconds.')

start = time.time()
for i in range(1000000):
    x = autodict({'x'+str(i) : i})
end = time.time()
print('Autodict:', end - start,'seconds.')

结果为:

Named tuples: 59.21987843513489 seconds.
Autodict: 1.4844810962677002 seconds.

字典设置在我的书中,非常快。尽管这很可能与命名元组设置中的多个 for 循环有关,并且很可能可以通过一些方法轻松地对其进行补救。但是对于基本的了解,这是一个很大的差异。该示例显然不会测试较大的一次性创建或访问时间。只是,如果您使用这些选项在一段时间内创建数据集,您将失去多少时间呢?:)

The dictionary setup is in my book, insanely quicker. Although that most likely has to do with multiple for loops in the named tuple setup, and that can probably be easily remedied some how. But for basic understanding this is a big difference. The example obviously doesn't test larger one-time-creations or access times. Just, "what if you use these options to create data-sets over a period of time, how much time would you loose" :)

奖金:如果您拥有

base_dict = {'x'+str(i) : i for i in range(1000000)}

start = time.time()
nt = foo(base_dict)
end = time.time()
print('Named tuples:', end - start,'seconds.')

start = time.time()
x = autodict(base_dict)
end = time.time()
print('Autodict:', end - start,'seconds.')

好吧,差异大于我的预期。. x1038.5 更快。

(我正在使用CPU

Well, the difference was bigger than I expected.. x1038.5 times faster.
(I was using the CPU for other stuff, but I think this is fair game)

Named tuples: 154.0662612915039 seconds.
Autodict: 0.1483476161956787 seconds.

这篇关于是否有不可变的类字典对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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