V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
black11black
V2EX  ›  Python

Python 有办法限制字典不能添加新键吗 ?

  •  
  •   black11black · 2020-02-08 13:46:15 +08:00 · 3929 次点击
    这是一个创建于 1510 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,在自己开发 library

    目前希望做到的一个效果是,比如

    class configure:
    	def __init__(self):
    		param1_set = {'person_number':12}
            param2_set = {'age': 1}
    

    如果我生成一个 configure 对象用来对库的行为进行控制,我不希望用户可以随意修改其中的数值,我希望将可修改的范围完全限制在我初始化规定的范围里。

    众所周知用__slots__可以限制属性不能超出范围 但是像我这样属性内部放的是字典对象,字典的键值对还是可以随意修改的,可能导致各种未知问题 有什么解决办法吗?

    20 条回复    2020-02-10 10:16:29 +08:00
    Livid
        1
    Livid  
    MOD
       2020-02-08 13:51:18 +08:00
    这里有一些实现可以参考:

    https://www.python.org/dev/peps/pep-0416/
    monsterxx03
        2
    monsterxx03  
       2020-02-08 14:02:41 +08:00 via iPhone
    写个 class 继承 dict,重载__setitem__,直接抛异常
    ipwx
        3
    ipwx  
       2020-02-08 14:04:30 +08:00 via Android
    dataclass frozen=true?
    freakxx
        4
    freakxx  
       2020-02-08 14:07:29 +08:00
    可以考虑写个

    继承 dict, 复写 __setitem__
    freakxx
        5
    freakxx  
       2020-02-08 14:08:33 +08:00
    https://github.com/slezica/python-frozendict

    也有这样的库,可以参考下实现
    imn1
        6
    imn1  
       2020-02-08 14:09:39 +08:00
    标题是键,正文是值,那么究竟修改 value 还是 key ?
    value 的话,可以 forzendict,或者直接用 pickle 二进制保存
    key 的话,可以预置一个固定 key 的 dict,然后从输入更新 value,舍弃非预置的 key
    Leigg
        7
    Leigg  
       2020-02-08 14:24:26 +08:00 via Android
    多了解一下双下划线开头的方法
    est
        8
    est  
       2020-02-08 14:33:07 +08:00
    namedtuple 香~
    ClericPy
        9
    ClericPy  
       2020-02-08 14:40:05 +08:00
    0. https://www.dogedoge.com/results?q=Python+immutable+dict
    1. 用户只要想改, 动态语言基本上用点成本都能改改
    2. 主流的保护方式是双下划线保护基类, 子类改起来就很麻烦
    3. 可以用一些 immutable 对象做属性调用, 比如基于数组的 namedtuple, 当然 frozendict 和 immutables 这俩库也可以, 就是有点多余了
    4. 感觉有点杞人忧天过早优化了, 实在不行, 自己继承个 dict 在 __setitems__ 里面加上一个 warning 就够了
    laike9m
        10
    laike9m  
       2020-02-08 15:41:28 +08:00
    @Livid 感觉 types.MappingProxyType 应该是正解了,虽然还是只能期待用户不会直接改包含在其中的 dict
    laike9m
        11
    laike9m  
       2020-02-08 15:44:32 +08:00
    @Livid 感觉 types.MappingProxyType 应该是正解了,虽然还是只能期待用户不会直接改包含在其中的 dict
    @monsterxx03 这个比你想的要 tricky: https://stackoverflow.com/q/2060972/2142577
    frostming
        12
    frostming  
       2020-02-08 19:18:14 +08:00
    @monsterxx03 直接继承 dict 不是个好方法,(tomlkit 就是这样,我都报过好几个 bug 了) https://treyhunner.com/2019/04/why-you-shouldnt-inherit-from-list-and-dict-in-python/

    @laike9m 用 collections.abc.Mapping 可能比 types.MappingProxyType 要更好一点
    aguesuka
        13
    aguesuka  
       2020-02-08 21:30:20 +08:00
    不要暴露字典接口,而是自己提供一个方法比较好吧
    black11black
        14
    black11black  
    OP
       2020-02-09 03:15:23 +08:00
    @freakxx

    试了一下 setitem 是无论新建键值对,还是修改已有条目都会调用的啊,不太满足需求
    想看一下实现部分 py 的源码,这种不用库导入的 bif 找了半天没找到在什么地方。
    laike9m
        15
    laike9m  
       2020-02-09 03:47:31 +08:00
    @frostming types.MappingProxyType 实际上就是 abc.Mapping,没什么区别的,还更方便
    https://github.com/python/cpython/blob/3.8/Lib/_collections_abc.py#L691
    freakxx
        16
    freakxx  
       2020-02-09 15:30:04 +08:00
    class FrozenDict(dict):
    def __setitem__(self, key, value):
    raise TypeError("'FrozenDict' object does not support item assignment")


    frozen_dict = FrozenDict


    你要的是这样?
    freakxx
        17
    freakxx  
       2020-02-09 15:33:43 +08:00
    不过看了你发的这几个贴。。。实际上搞个 tuplename 就算了,
    frostming
        18
    frostming  
       2020-02-09 20:10:55 +08:00
    @laike9m 抽象类和具体类的区别
    RRRoger
        19
    RRRoger  
       2020-02-10 09:55:29 +08:00
    frozen dict
    cassidyhere
        20
    cassidyhere  
       2020-02-10 10:16:29 +08:00
    可以参考 werkzeug.datastructures 里实现的 ImmutableDict
    flask 就用到了
    class Flask(_PackageBoundObject):
    ...
    default_config = ImmutableDict({"ENV": None, ...})
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5460 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 08:30 · PVG 16:30 · LAX 01:30 · JFK 04:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.