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
iorilu
V2EX  ›  Python

其实我经常好奇一件事, 为什么 Python 得 dict 没有 set 方法, 有人知道什么历史原因吗

  •  
  •   iorilu · 37 天前 · 3097 次点击
    这是一个创建于 37 天前的主题,其中的信息可能已经有所发展或是发生改变。

    经常操作 dict

    d = {}
    d['name'] ='tom'
    d['age'] = 30
    

    这样得代码, 其实我很想有一个 set 方法, 我觉得这样 比上面写法更好

    而且 dict 明明有 get 方法, 有 set 很合理

    而且还有个 setdefault 方法, 而且这个方法很容易混淆, 因为这个方法 主要作用是获取值, 并不是设置值得, 这个名字一看都不清楚什么意思

    总的来说, 我认为应该有 set 方法

    但 python 一直没有, 而且既然没有, 后面加上应该不会有任何不兼容

    当然这么明显得事情 python 开发组不可能不知道, 那么到底是什么原因 不能放一个 set 方法呢

    27 条回复    2024-10-17 09:26:54 +08:00
    julyclyde
        1
    julyclyde  
       37 天前
    set 是 python 语言的关键词
    lucasj
        2
    lucasj  
       37 天前
    我也觉得很合理。
    cmdOptionKana
        3
    cmdOptionKana  
       37 天前
    python 语言本身的设计理念就是想一出是一出,很自由,没啥特殊原因,纯粹当时设计者拍脑袋觉得这样够用,后续也没啥大问题就不改了。
    keakon
        4
    keakon  
       37 天前
    因为有 __setitem__ 方法。提供 dict.get 方法是因为 __getitem__ 在 key 不存在时会抛出异常。
    est
        5
    est  
       37 天前
    .update() 啊

    LZ 可以了解一下一个叫 UserDict 的东西。
    009694
        6
    009694  
       37 天前 via iPhone
    get 是为了默认值 set 是为了啥? 因为你 java 先入为主的概念
    wxf666
        7
    wxf666  
       37 天前
    不懂就问,`d.set('name', 'tom')` 比 `d['name'] = 'tom'` 好在哪儿呢?

    xing7673
        8
    xing7673  
       37 天前
    @wxf666 = 号作为分隔符更清晰
    quicknight
        9
    quicknight  
       37 天前   ❤️ 1
    d.set('name', 'tom'),是把 name 给 tom 还是把 tom 给 name ?
    d['name'] = 'tom'这种方式没有这个二义性
    Trim21
        10
    Trim21  
       37 天前
    @quicknight 真的会有歧义吗,好奇有哪个 API 设计类似方法的时候把 value 放在前面吗?
    quicknight
        11
    quicknight  
       37 天前   ❤️ 4
    @Trim21 苹果的 OC 和 SWIFT 都是值在前面 KEY 在后面
    [dict setObject:@"value" forKey:@"key"]

    你如果经常在不同语言中穿梭,或者你只是想看看一个你不懂的语言的逻辑,没有二义性的体验真的好很多
    DOLLOR
        12
    DOLLOR  
       37 天前
    @julyclyde 不是吧? python 里 set 可以作为变量名、函数名用
    iorilu
        13
    iorilu  
    OP
       37 天前
    @wxf666 get , set 相互匹配

    我如果用 get 取值, 然后用 set 赋值不是很合理吗

    比如
    ```
    count = p.get('count', 0)
    p.set('count', count+1)
    ```
    Soler
        14
    Soler  
       37 天前
    @iorilu 这个世界本来就是不对等的。

    可以使用 p['count'] += 1
    deplives
        15
    deplives  
       37 天前
    我也不知道为啥没有显式的 set ,但是你可以自己实现一个

    ```python
    import ctypes


    class PyType(ctypes.Structure):
    pass


    class PyObject(ctypes.Structure):
    Py_ssize_t = (
    ctypes.c_int64 if ctypes.sizeof(ctypes.c_void_p) == 8 else ctypes.c_int32
    )
    _fields_ = [
    ("ob_refcnt", Py_ssize_t),
    ("ob_type", ctypes.POINTER(PyType)),
    ]


    class PyTypeObject(PyObject):
    _fields_ = [
    ("dict", ctypes.POINTER(PyObject))
    ]


    def inject(class_, method, force=False):
    def _(function):
    name_, dict_ = class_.__name__, class_.__dict__
    proxy_dict = PyTypeObject.from_address(id(dict_))
    namespace = {}
    ctypes.pythonapi.PyDict_SetItem(
    ctypes.py_object(namespace),
    ctypes.py_object(name_),
    proxy_dict.dict
    )
    if not force and namespace.get(name_, {}).get(method, None):
    raise RuntimeError(f"已存在方法 {class_.__name__}.{method}()")
    namespace[name_][method] = function

    return _


    @inject(dict, 'set')
    def dict_set(d, key, value):
    d.update({key: value})
    ```


    a = {}
    a.set("name", "hello")
    print(a)
    Geon97
        16
    Geon97  
       37 天前
    @wxf666 好在没有 d['name'] = 'tom'可读性强
    iorilu
        18
    iorilu  
    OP
       37 天前
    @Soler 说实话把, 我就是不喜欢方框号操作, 因为我习惯性得觉得方括号就是操作数组类似得东西

    主要是我觉得 pyhon 开发组可以加上 set 方法, 至于用不用是开发人员得事, 毕竟还有个 setdefault 呢, 实际上也没啥用, 还不是加上了
    Hookery
        19
    Hookery  
       37 天前
    OP 并没有深刻理解 pythonic
    iorilu
        20
    iorilu  
    OP
       37 天前
    @deplives 好的, 比较底层得方法, 有空学习下
    guyeu
        21
    guyeu  
       37 天前
    set 关键字应该是正解,其次应该是 set 的含义在 dict 这个场景并不能很好地表达这个方法的目的。

    dict 是键值对的集合,往集合里添加内容应该是 put 或 insert 。
    julyclyde
        22
    julyclyde  
       37 天前
    @DOLLOR 嗯我错了。不是保留关键词
    是 built-in type
    你如果用 set 做变量名,相当于覆盖了内置的 set 数据类型吧?
    llsquaer
        23
    llsquaer  
       37 天前
    setdefault 是设置默认值,如果有就不设置了。 你用这个取值?防御性编程啊。
    e3c78a97e0f8
        24
    e3c78a97e0f8  
       37 天前
    [Zen of Python:]( https://peps.python.org/pep-0020/)

    There should be one-- and preferably only one --obvious way to do it.

    虽然 Python 开发者自己也经常搞出同一件事的几种做法,但是他们每次都能找到一堆理由。你这个做法完全是 style preference ,并不符合 Zen Of Python 。
    sgld
        25
    sgld  
       35 天前
    d['name'] = 'tom'

    这个本身不就是调用的__setitem__ 嘛,所以为啥还需要再建立一个 set()方法再调这个方法呢?

    存在这个方法才是真正的多此一举吧。就像 6 楼说的,get 方法是因为需要在不存在时返回默认值。否则直接[]取也是一样的。
    sgld
        26
    sgld  
       35 天前
    @iorilu Python 对序列取值就是用的[],你可能只是不习惯而已。就像取属性用的是 . 这个也对应了`__getattr__(self, name)`

    你这单纯不习惯,不同语言有所不同很正常吧
    woodfizky
        27
    woodfizky  
       35 天前
    其实是有类似你说的方法的,但是是 magic method 。

    d['key'] = 'value' 等同于 d.__setitem__('key', 'value')

    字典主要是还有一个 update 方法,实际上就是遍历 key, value 去做__setitem__


    确实有时候会给人一种设计上不一致的感觉:
    value = d['key'] 也就是 value = d.__getitem__('key')
    上面这种方括号用法有 KeyError 的风险,
    d['key'] = 'value' 同样是方括号用法,同样是对应一个魔法方法,这个却不会有问题。
    然后我换一种风格,用 d.get('key') 和 d.update(other_dict), 都不会出现 KeyError 。

    字典 get 方法和__getitem__方法的逻辑并不一样,前者是默认取不到值取默认值,且默认值为 None ;后者取不到值直接报错,且不提供默认值参数。

    不过仔细看看就知道了,get 方法是属于字典这种 python 中的 Mapping 类的,并不是直接对应__getitem__这种魔法方法的。通用类是并没有自带 get 和 set 这种方法的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3483 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 11:16 · PVG 19:16 · LAX 03:16 · JFK 06:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.