zoukankan      html  css  js  c++  java
  • python 不可变字典 inmutabledict的实现

    python inmutabledict的实现

    关于在python中如何实现不可变字典的方法。早在pep416中,就建议python官方实现inmutabledict,但是官方否认了。理由主要是

    • 根据Raymond Hettinger的说法,使用frozendict很愚蠢。 那些使用它的人倾向于仅将它用作提示,例如声明全局或类级别的“常量”:它们实际上不是永久不变的,因为任何人仍然可以指定名称。
    • There are existing idioms for avoiding mutable default values.

    所以,这个提议就被否决了。但是我们依旧可以自己实现一个inmutabledict。inmutable主要的特点是

    • dict内的值只能在初始化的时候指定
    • 在运行期间,不能添加删除新增dict内部的值

    结合starkoverflow上面的回答
    我们可以通过如下几种魔改的方式实现python的inmutabledict

    几种变通的方案

    1. 最原始的方法,修改setitem魔术方法

    在python中,d["foo"]=bar,将foo和bar作为参数,调用的是python的模式方法__setitem__。函数原型为def __setitem__(self, key, value):。所以,我们可以继承dict类,实现自己的__setitem__。在修改值的时候,抛出TypeError。不就是可以达到无法修改字典的值的目的了嘛。代码如下

    class myDict(dict):
        def __setitem__(self, key, value):
            raise TypeError("inmutabledict can not be modifyed value")
    
    d = myDict({1:2,3:4})
    d[1]=4
    
    

    运行则会提示

        raise TypeError("inmutabledict can not be modifyed value")
    TypeError: inmutabledict can not be modifyed value
    
    Process finished with exit code 1
    

    很好,完美的完成了任务。这种方法应用最为广泛,在werkzeug框架中的ImmutableDict等,就是通过修改魔术方法来实现的不可变字典类型。

    但是在pep0416中,还提到了几种其他方法,PyDictProxy_New等。下面来试一下

    2. pythonapi.PyDictProxy_New

    在官方介绍capi的PyDictProxy_New中,使用代理模式,代理使用字典。并且拦截了字典的修改请求。介绍如下

    PyObject* PyDictProxy_New(PyObject *mapping)¶
    Return value: New reference.
    Return a types.MappingProxyType object for a mapping which enforces read-only behavior. This is normally used to create a view to prevent modification of the dictionary for non-dynamic class types.
    

    意思就是你传入个dict,这个函数返回一个dict(其实是types.MappingProxyType),然后这个返回的dict就不可以修改啦。是不是很简单,代码实现如下

    
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    
    
    from ctypes import pythonapi, py_object
    
    PyDictProxy_New = pythonapi.PyDictProxy_New
    PyDictProxy_New.argtypes = (py_object,)
    PyDictProxy_New.restype = py_object
    
    def make_dictproxy(obj):
        assert isinstance(obj, dict)
        return pythonapi.PyDictProxy_New(obj)
    a={'a': 'b', 'c': 'd'}
    d = make_dictproxy(a)
    

    这是如果修改的话,则会提示TypeError: 'mappingproxy' object does not support item assignment。同样达到了要求。这种方法的弊端主要在于依赖特定的平台,只能适用于cpython。而上面那种则适用于所有平台,cpython,pypy等。

    3 .class types.MappingProxyType(mapping)

    这种方法其实于PyDictProxy_New一样,只不过在py3.3中才实现。
    代码如下

    from types import  MappingProxyType
    
    def make_dictproxy(obj):
        assert isinstance(obj, dict)
        return MappingProxyType(obj)
    
  • 相关阅读:
    C# XML 文档注释
    大数据知识学习
    现在的人,买个钢铁做的车,每天擦,每周打蜡。可对自已的身体最应该保养的“车”,却从不养护
    Asp.net项目因Session阻塞导致页面打开速度变慢
    AvoidRepeatSubmit通过Javascript避免客户端重复提交请求
    Linux下Attansic L2 网卡驱动安装
    如果知道dll文件是面向32位系统还是面向64位系统的?
    整理C# 二进制,十进制,十六进制 互转
    连接Oracle时出现“System.AccessViolationException: 尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”错误的问题
    [转]删除hbase表region块脚本
  • 原文地址:https://www.cnblogs.com/potatsoSec/p/12157051.html
Copyright © 2011-2022 走看看