Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/332.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
Python “a”会是什么;“冷冻口述”;是 冷冻套装就是冷冻套装 冻结列表可以是元组 冷冻的口述会是什么?不可变的、可散列的指令_Python_Dictionary_Data Structures_Immutability - Fatal编程技术网

Python “a”会是什么;“冷冻口述”;是 冷冻套装就是冷冻套装 冻结列表可以是元组 冷冻的口述会是什么?不可变的、可散列的指令

Python “a”会是什么;“冷冻口述”;是 冷冻套装就是冷冻套装 冻结列表可以是元组 冷冻的口述会是什么?不可变的、可散列的指令,python,dictionary,data-structures,immutability,Python,Dictionary,Data Structures,Immutability,我猜它可能是类似于collections.namedtuple,但这更像是一个冻结键dict(半冻结dict)。不是吗 “frozendict”应该是一个冻结字典,它应该有键,值,获取,等等,并且在中支持,用于等等 更新: *这就是:假设字典的键和值本身是不可变的(例如字符串),那么: Python没有内置的frozendict类型。事实证明,这并不太有用(尽管它仍然可能比frozenset更有用) 希望使用这种类型的最常见原因是当记忆函数调用具有未知参数的函数时。存储dict的可散列等价物(其

我猜它可能是类似于
collections.namedtuple
,但这更像是一个冻结键dict(半冻结dict)。不是吗

“frozendict”应该是一个冻结字典,它应该有
获取
,等等,并且在中支持
用于
等等

更新:

*这就是:

假设字典的键和值本身是不可变的(例如字符串),那么:


Python没有内置的frozendict类型。事实证明,这并不太有用(尽管它仍然可能比
frozenset
更有用)

希望使用这种类型的最常见原因是当记忆函数调用具有未知参数的函数时。存储dict的可散列等价物(其中值是可散列的)最常见的解决方案类似于
tuple(排序(kwargs.iteritems())

这取决于排序是否有点疯狂。Python不能肯定地保证排序将在这里产生合理的结果。(但它不能承诺更多,所以不要过分担心。)


你可以很容易地做一些类似于dict的包装

import collections

class FrozenDict(collections.Mapping):
    """Don't forget the docstrings!!"""

    def __init__(self, *args, **kwargs):
        self._d = dict(*args, **kwargs)
        self._hash = None

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

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

    def __getitem__(self, key):
        return self._d[key]

    def __hash__(self):
        # It would have been simpler and maybe more obvious to 
        # use hash(tuple(sorted(self._d.iteritems()))) from this discussion
        # so far, but this solution is O(n). I don't know what kind of 
        # n we are going to run into, but sometimes it's hard to resist the 
        # urge to optimize when it will gain improved algorithmic performance.
        if self._hash is None:
            hash_ = 0
            for pair in self.items():
                hash_ ^= hash(pair)
            self._hash = hash_
        return self._hash
它应该非常有效:

>>> x = FrozenDict(a=1, b=2)
>>> y = FrozenDict(a=1, b=2)
>>> x is y
False
>>> x == y
True
>>> x == {'a': 1, 'b': 2}
True
>>> d = {x: 'foo'}
>>> d[y]
'foo'

每次我写这样的函数时,我都会想到frozendict:

def do_something(blah, optional_dict_parm=None):
    if optional_dict_parm is None:
        optional_dict_parm = {}
from collections import namedtuple

MY_CONSTANT = namedtuple('MyConstant', 'something something_else')(123, 456)
class MyFrozenDict:
    def __getitem__(self, key):
        if key == 'mykey1':
            return 0
        if key == 'mykey2':
            return "another value"
        raise KeyError(key)

这是我一直在使用的代码。我将frozenset子类化。这样做的好处如下

  • 这是一个真正不变的对象。不依赖未来用户和开发人员的良好行为
  • 在普通字典和冻结字典之间来回转换很容易。FrozenDict(原文)-->冻结词典。口述(冻结口述)-->常规口述
  • 2015年1月21日更新:我在2014年发布的原始代码使用for循环查找匹配的密钥。这真是太慢了。现在我已经准备好了一个利用frozenset散列特性的实现。键值对存储在特殊的容器中,
    \uuuuuuu散列
    \uuuuuuuu eq
    函数仅基于键。这段代码也经过了正式的单元测试,不像我在2014年8月发布的那样

    麻省理工学院风格的许可证

    if 3 / 2 == 1:
        version = 2
    elif 3 / 2 == 1.5:
        version = 3
    
    def col(i):
        ''' For binding named attributes to spots inside subclasses of tuple.'''
        g = tuple.__getitem__
        @property
        def _col(self):
            return g(self,i)
        return _col
    
    class Item(tuple):
        ''' Designed for storing key-value pairs inside
            a FrozenDict, which itself is a subclass of frozenset.
            The __hash__ is overloaded to return the hash of only the key.
            __eq__ is overloaded so that normally it only checks whether the Item's
            key is equal to the other object, HOWEVER, if the other object itself
            is an instance of Item, it checks BOTH the key and value for equality.
    
            WARNING: Do not use this class for any purpose other than to contain
            key value pairs inside FrozenDict!!!!
    
            The __eq__ operator is overloaded in such a way that it violates a
            fundamental property of mathematics. That property, which says that
            a == b and b == c implies a == c, does not hold for this object.
            Here's a demonstration:
                [in]  >>> x = Item(('a',4))
                [in]  >>> y = Item(('a',5))
                [in]  >>> hash('a')
                [out] >>> 194817700
                [in]  >>> hash(x)
                [out] >>> 194817700
                [in]  >>> hash(y)
                [out] >>> 194817700
                [in]  >>> 'a' == x
                [out] >>> True
                [in]  >>> 'a' == y
                [out] >>> True
                [in]  >>> x == y
                [out] >>> False
        '''
    
        __slots__ = ()
        key, value = col(0), col(1)
        def __hash__(self):
            return hash(self.key)
        def __eq__(self, other):
            if isinstance(other, Item):
                return tuple.__eq__(self, other)
            return self.key == other
        def __ne__(self, other):
            return not self.__eq__(other)
        def __str__(self):
            return '%r: %r' % self
        def __repr__(self):
            return 'Item((%r, %r))' % self
    
    class FrozenDict(frozenset):
        ''' Behaves in most ways like a regular dictionary, except that it's immutable.
            It differs from other implementations because it doesn't subclass "dict".
            Instead it subclasses "frozenset" which guarantees immutability.
            FrozenDict instances are created with the same arguments used to initialize
            regular dictionaries, and has all the same methods.
                [in]  >>> f = FrozenDict(x=3,y=4,z=5)
                [in]  >>> f['x']
                [out] >>> 3
                [in]  >>> f['a'] = 0
                [out] >>> TypeError: 'FrozenDict' object does not support item assignment
    
            FrozenDict can accept un-hashable values, but FrozenDict is only hashable if its values are hashable.
                [in]  >>> f = FrozenDict(x=3,y=4,z=5)
                [in]  >>> hash(f)
                [out] >>> 646626455
                [in]  >>> g = FrozenDict(x=3,y=4,z=[])
                [in]  >>> hash(g)
                [out] >>> TypeError: unhashable type: 'list'
    
            FrozenDict interacts with dictionary objects as though it were a dict itself.
                [in]  >>> original = dict(x=3,y=4,z=5)
                [in]  >>> frozen = FrozenDict(x=3,y=4,z=5)
                [in]  >>> original == frozen
                [out] >>> True
    
            FrozenDict supports bi-directional conversions with regular dictionaries.
                [in]  >>> original = {'x': 3, 'y': 4, 'z': 5}
                [in]  >>> FrozenDict(original)
                [out] >>> FrozenDict({'x': 3, 'y': 4, 'z': 5})
                [in]  >>> dict(FrozenDict(original))
                [out] >>> {'x': 3, 'y': 4, 'z': 5}   '''
    
        __slots__ = ()
        def __new__(cls, orig={}, **kw):
            if kw:
                d = dict(orig, **kw)
                items = map(Item, d.items())
            else:
                try:
                    items = map(Item, orig.items())
                except AttributeError:
                    items = map(Item, orig)
            return frozenset.__new__(cls, items)
    
        def __repr__(self):
            cls = self.__class__.__name__
            items = frozenset.__iter__(self)
            _repr = ', '.join(map(str,items))
            return '%s({%s})' % (cls, _repr)
    
        def __getitem__(self, key):
            if key not in self:
                raise KeyError(key)
            diff = self.difference
            item = diff(diff({key}))
            key, value = set(item).pop()
            return value
    
        def get(self, key, default=None):
            if key not in self:
                return default
            return self[key]
    
        def __iter__(self):
            items = frozenset.__iter__(self)
            return map(lambda i: i.key, items)
    
        def keys(self):
            items = frozenset.__iter__(self)
            return map(lambda i: i.key, items)
    
        def values(self):
            items = frozenset.__iter__(self)
            return map(lambda i: i.value, items)
    
        def items(self):
            items = frozenset.__iter__(self)
            return map(tuple, items)
    
        def copy(self):
            cls = self.__class__
            items = frozenset.copy(self)
            dupl = frozenset.__new__(cls, items)
            return dupl
    
        @classmethod
        def fromkeys(cls, keys, value):
            d = dict.fromkeys(keys,value)
            return cls(d)
    
        def __hash__(self):
            kv = tuple.__hash__
            items = frozenset.__iter__(self)
            return hash(frozenset(map(kv, items)))
    
        def __eq__(self, other):
            if not isinstance(other, FrozenDict):
                try:
                    other = FrozenDict(other)
                except Exception:
                    return False
            return frozenset.__eq__(self, other)
    
        def __ne__(self, other):
            return not self.__eq__(other)
    
    
    if version == 2:
        #Here are the Python2 modifications
        class Python2(FrozenDict):
            def __iter__(self):
                items = frozenset.__iter__(self)
                for i in items:
                    yield i.key
    
            def iterkeys(self):
                items = frozenset.__iter__(self)
                for i in items:
                    yield i.key
    
            def itervalues(self):
                items = frozenset.__iter__(self)
                for i in items:
                    yield i.value
    
            def iteritems(self):
                items = frozenset.__iter__(self)
                for i in items:
                    yield (i.key, i.value)
    
            def has_key(self, key):
                return key in self
    
            def viewkeys(self):
                return dict(self).viewkeys()
    
            def viewvalues(self):
                return dict(self).viewvalues()
    
            def viewitems(self):
                return dict(self).viewitems()
    
        #If this is Python2, rebuild the class
        #from scratch rather than use a subclass
        py3 = FrozenDict.__dict__
        py3 = {k: py3[k] for k in py3}
        py2 = {}
        py2.update(py3)
        dct = Python2.__dict__
        py2.update({k: dct[k] for k in dct})
    
        FrozenDict = type('FrozenDict', (frozenset,), py2)
    

    是的,这是我的第二个答案,但这是一个完全不同的方法。第一个实现是用纯python实现的。这是在赛昂。如果您知道如何使用和编译Cython模块,这与普通字典一样快。大约0.04到0.06微秒来检索单个值

    这是“冻结的dict.pyx”文件

    这是文件“setup.py”

    如果已安装Cython,请将上述两个文件保存到同一目录中。在命令行中移动到该目录

    python setup.py build_ext --inplace
    python setup.py install
    

    应该这样做。

    奇怪的是,尽管我们有很少有用的
    冻结集,但仍然没有冻结映射。这个想法在年被拒绝了。在以后的Python版本中可能会重新讨论这个想法,请参阅

    因此,Python 2解决方案解决了这一问题:

    def foo(config={'a': 1}):
        ...
    
    仍然似乎有点跛脚:

    def foo(config=None):
        if config is None:
            config = default_config = {'a': 1}
        ...
    
    在Python 3中,您可以选择:

    现在,默认配置可以动态更新,但在您希望它不可变的地方,可以通过传递代理来保持不变

    因此,
    default\u config
    中的更改将按预期更新
    DEFAULTS
    ,但不能写入映射代理对象本身


    诚然,它与“不可变的、可散列的dict”并不完全相同,但它可能是frozendict某些用例的一个不错的替代品。

    namedtuple
    的主要缺点是在使用它之前需要指定它,因此对于单个用例来说不太方便

    然而,有一种实用的变通方法可用于处理许多此类情况。假设你想要一个不可变的等价物:

    MY_CONSTANT = {
        'something': 123,
        'something_else': 456
    }
    
    可以这样模拟:

    def do_something(blah, optional_dict_parm=None):
        if optional_dict_parm is None:
            optional_dict_parm = {}
    
    from collections import namedtuple
    
    MY_CONSTANT = namedtuple('MyConstant', 'something something_else')(123, 456)
    
    class MyFrozenDict:
        def __getitem__(self, key):
            if key == 'mykey1':
                return 0
            if key == 'mykey2':
                return "another value"
            raise KeyError(key)
    
    甚至可以编写一个辅助函数来实现自动化:

    def freeze_dict(data):
        from collections import namedtuple
        keys = sorted(data.keys())
        frozen_type = namedtuple(''.join(keys), keys)
        return frozen_type(**data)
    
    a = {'foo':'bar', 'x':'y'}
    fa = freeze_dict(data)
    assert a['foo'] == fa.foo
    
    当然,这只适用于平面dict,但实现递归版本应该不会太困难。

    您可以使用from-package作为:

    >>> from utilspie.collectionsutils import frozendict
    
    >>> my_dict = frozendict({1: 3, 4: 5})
    >>> my_dict  # object of `frozendict` type
    frozendict({1: 3, 4: 5})
    
    # Hashable
    >>> {my_dict: 4}
    {frozendict({1: 3, 4: 5}): 4}
    
    # Immutable
    >>> my_dict[1] = 5
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Users/mquadri/workspace/utilspie/utilspie/collectionsutils/collections_utils.py", line 44, in __setitem__
        self.__setitem__.__name__, type(self).__name__))
    AttributeError: You can not call '__setitem__()' for 'frozendict' object
    
    >>来自utilspie.collectionutils导入frozendict
    >>>my_dict=frozendict({1:3,4:5})
    >>>“frozendict”类型的my_dict对象
    frozendict({1:3,4:5})
    #散列
    >>>{我的遗嘱:4}
    {frozendict({1:3,4:5}):4}
    #不变的
    >>>我的字典[1]=5
    回溯(最近一次呼叫最后一次):
    文件“”,第1行,在
    文件“/Users/mquadri/workspace/utilspie/utilspie/collectionsutils/collections_utils.py”,第44行,在u_setitem中__
    self.\uuuuuu设置项。\uuuuuu名称\uuuuuuu,类型(self)。\uuuuuuuuuu名称\uuuuuuuuuu)
    AttributeError:无法为“frozendict”对象调用“\uuuuSetItem\uuuuuIf()”
    

    根据:

    frozendict(dict_obj):接受dict类型的obj并返回一个可散列且不可变的dict

    子类化
    dict
    我在野外看到了这种模式(github),并想提到它:

    class FrozenDict(dict):
        def __init__(self, *args, **kwargs):
            self._hash = None
            super(FrozenDict, self).__init__(*args, **kwargs)
    
        def __hash__(self):
            if self._hash is None:
                self._hash = hash(tuple(sorted(self.items())))  # iteritems() on py2
            return self._hash
    
        def _immutable(self, *args, **kws):
            raise TypeError('cannot change object - object is immutable')
    
        # makes (deep)copy alot more efficient
        def __copy__(self):
            return self
    
        def __deepcopy__(self, memo=None):
            if memo is not None:
                memo[id(self)] = self
            return self
    
        __setitem__ = _immutable
        __delitem__ = _immutable
        pop = _immutable
        popitem = _immutable
        clear = _immutable
        update = _immutable
        setdefault = _immutable
    
    用法示例:

    d1 = FrozenDict({'a': 1, 'b': 2})
    d2 = FrozenDict({'a': 1, 'b': 2})
    d1.keys() 
    assert isinstance(d1, dict)
    assert len(set([d1, d2])) == 1  # hashable
    
    专业人士

    • 支持
      get()
      keys()
      items()
      iteritems()
      ,在py2上)以及所有来自
      dict
      的现成商品,而无需显式实现它们
    • 在内部使用dict
      dict
      ,这意味着性能(
      dict
      在CPython中用c编写)
    • 优雅简单,没有黑魔法
    • isinstance(my_freezed_dict,dict)
      返回True-尽管python鼓励许多包使用
      isinstance()
      ,但这可以节省许多调整和自定义
    缺点

    • 任何子类都可以覆盖它或在内部访问它(在python中,您不能真正100%地保护某些东西,您应该信任您的用户并提供
      class frozen_dict(dict):
          def __setitem__(self, key, value):
              raise Exception('Frozen dictionaries cannot be mutated')
      
      frozen_dict = frozen_dict({'foo': 'FOO' })
      print(frozen['foo']) # FOO
      frozen['foo'] = 'NEWFOO' # Exception: Frozen dictionaries cannot be mutated
      
      # OR
      
      from types import MappingProxyType
      
      frozen_dict = MappingProxyType({'foo': 'FOO'})
      print(frozen_dict['foo']) # FOO
      frozen_dict['foo'] = 'NEWFOO' # TypeError: 'mappingproxy' object does not support item assignment
      
      pip install frozendict
      
      from frozendict import frozendict
      
      def smth(param = frozendict({})):
          pass
      
      >>> from types import MappingProxyType
      >>> foo = MappingProxyType({'a': 1})
      >>> foo
      mappingproxy({'a': 1})
      >>> foo['a'] = 2
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      TypeError: 'mappingproxy' object does not support item assignment
      >>> foo
      mappingproxy({'a': 1})
      
      class MyFrozenDict:
          def __getitem__(self, key):
              if key == 'mykey1':
                  return 0
              if key == 'mykey2':
                  return "another value"
              raise KeyError(key)
      
      a = MyFrozenDict()
      print(a['mykey1'])