首页 注册 登录
V2EX = way to explore V2EX 是一个关于分享和探索的地方
现在注册 已注册用户请 登录
V2EX Python

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

iorilu · 2024 年 10 月 14 日 · 4165 次点击
这是一个创建于 453 天前的主题,其中的信息可能已经有所发展或是发生改变。

经常操作 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 2024 年 10 月 14 日
set 是 python 语言的关键词
lucasj
2
lucasj 2024 年 10 月 14 日
我也觉得很合理。
cmdOptionKana
3
cmdOptionKana 2024 年 10 月 14 日
python 语言本身的设计理念就是想一出是一出,很自由,没啥特殊原因,纯粹当时设计者拍脑袋觉得这样够用,后续也没啥大问题就不改了。
keakon
4
keakon 2024 年 10 月 14 日
因为有 __setitem__ 方法。提供 dict.get 方法是因为 __getitem__ 在 key 不存在时会抛出异常。
est
5
est 2024 年 10 月 14 日
.update() 啊

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

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

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

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

比如
```
count = p.get('count', 0)
p.set('count', count+1)
```
9Y8lCIS38J8AlhRs
14
9Y8lCIS38J8AlhRs 2024 年 10 月 15 日
@iorilu 这个世界本来就是不对等的。

可以使用 p['count'] += 1
deplives
15
deplives 2024 年 10 月 15 日
我也不知道为啥没有显式的 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 2024 年 10 月 15 日
@wxf666 好在没有 d['name'] = 'tom'可读性强
iorilu
18
iorilu
OP
2024 年 10 月 15 日
@Soler 说实话把, 我就是不喜欢方框号操作, 因为我习惯性得觉得方括号就是操作数组类似得东西

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

dict 是键值对的集合,往集合里添加内容应该是 put 或 insert 。
julyclyde
22
julyclyde 2024 年 10 月 15 日
@DOLLOR 嗯我错了。不是保留关键词
是 built-in type
你如果用 set 做变量名,相当于覆盖了内置的 set 数据类型吧?
llsquaer
23
llsquaer 2024 年 10 月 15 日
setdefault 是设置默认值,如果有就不设置了。 你用这个取值?防御性编程啊。
e3c78a97e0f8
24
e3c78a97e0f8 2024 年 10 月 15 日
[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 2024 年 10 月 17 日
d['name'] = 'tom'

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

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

你这单纯不习惯,不同语言有所不同很正常吧
woodfizky
27
woodfizky 2024 年 10 月 17 日
其实是有类似你说的方法的,但是是 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 · Solana · 2660 人在线 最高记录 6679 · Select Language 创意工作者们的社区 World is powered by solitude VERSION: 3.9.8.5 · 26ms · UTC 06:17 · PVG 14:17 · LAX 22:17 · JFK 01:17
♥ Do have faith in what you're doing.

AltStyle によって変換されたページ (->オリジナル) /