Jea*_*bre 11 python set python-internals
有人问这里时,把原因1和True在set仅1被保留.
这当然是因为1==True.但在哪些情况下1保留并保留哪些情况True?
让我们来看看:
传递一个list来构建set而不是使用set符号:
>>> set([True,1])
{True}
>>> set([1,True])
{1}
Run Code Online (Sandbox Code Playgroud)
似乎是逻辑的:set迭代内部列表,并且不添加第二个元素,因为它等于第一个元素(注意set([True,1]) 不能产生1,因为set无法知道列表中的内容.它甚至可能不是list一个可迭代的)
现在使用set符号:
>>> {True,1}
{1}
>>> {1,True}
{True}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,似乎是以相反的顺序处理项目列表(在Python 2.7和Python 3.4上测试).
但这有保证吗?或者只是一个实现细节?
语言规范似乎不保证插入集合文字中元素的顺序.但是,Python 3.6已更改,因此它具有预期的从左到右的评估顺序.有关此更改的完整详细信息,请参阅此问题,以及在插入顺序中引入更改的提交.
为了描述的变化在一个位更详细地,构建组字面{True, 1}触发BUILD_SET操作码(与oparg等于2)后第一推动指针True和1到虚拟机的内部堆栈.
在Python 3.4中,BUILD_SET使用以下循环将元素插入集合中(请注意,在我们的示例中oparg为2):
while (--oparg >= 0) {
PyObject *item = POP();
if (err == 0)
err = PySet_Add(set, item);
Py_DECREF(item);
Run Code Online (Sandbox Code Playgroud)
自从1最后添加到堆栈以来,它首先被弹出,并且是插入到集合中的第一个对象.
在较新版本的Python(例如3.6)中,BUILD_SET操作码使用PEEK而不是POP:
for (i = oparg; i > 0; i--) {
PyObject *item = PEEK(i);
if (err == 0)
err = PySet_Add(set, item);
Py_DECREF(item);
Run Code Online (Sandbox Code Playgroud)
PEEK(i)从堆栈中取出第i 个项目,因此{True, 1},首先将对象True添加到集合中.
| 归档时间: |
|
| 查看次数: |
367 次 |
| 最近记录: |