繁体   English   中英

对于列表中的 n:del n

[英]for n in a list: del n

当我遍历一个列表时,我在循环中为列表元素指定的名称显然直接依次指向每个元素,如下所示:

>>> a = [1, 2, 3]
>>> for n in a:
...     print n is a[a.index(n)]
True
True
True

那么为什么这似乎没有任何作用呢?

>>> for n in a: del n
>>> a
[1, 2, 3]

如果我尝试del a[a.index(n)] ,我会得到奇怪的行为,但至少这是我能理解的行为 - 每次我删除一个元素时,我都会缩短列表,更改其他元素的索引,所以我最终删除列表中的所有其他元素:

>>> a = range(10)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for n in a: del a[a.index(n)]
>>> a
[1, 3, 5, 7, 9]

显然,我可以在迭代时从列表中删除。 那么当我尝试在循环中del n了什么? 有什么要删除的吗?

在 any for n in X语句的块内, n指的是名为n的变量本身,而不是“您迭代的最后一个值在列表中的位置”的任何概念。 因此,您的循环正在做的是重复将变量n绑定到从列表中获取的值,然后立即再次解除绑定相同的变量。 del n语句只影响你的局部变量绑定,而不是列表。

因为你这样做:

some_reference = a[0]
del some_reference
#do you expect this to delete a[0]? it doesn't.

您正在操作一个绑定到a[0]值的变量(然后一个绑定到a[1] ,然后......)。 你可以删除它,但它不会做任何a

其他人已经很好地解释了删除参考的想法,我只是想谈谈项目删除的完整性。 即使您使用类似的语法del a[1] ,每种类型也会以稍微不同的方式处理项目删除。 正如预期的那样,从大多数容器中删除项目只是删除它们,有些类型根本不支持项目删除,例如元组。 就像一个有趣的锻炼者:

class A(object):
    def __delitem__(self, index):
        print 'I will NOT delete item {}!'.format(index)

a = A()
del a[3]
# I will NOT delete item 3!

Dolda2000 的回答很好地涵盖了主要问题,但这里还有其他三个问题。


for n in a循环中的for n in a使用index(n)几乎总是一个坏主意。

这是不正确的:

a = [1, 2, 1, 2]
for n in a:
    print(a.index(n))

这将打印0 ,然后是1 ,然后是0 为什么? 好吧,第三个值是1 a.index(1)是列表中前1的索引。 那是0 ,而不是2

它也很慢:要找到第i个值,您必须检查列表中的前i元素。 这将一个简单的线性(快速)算法变成了二次(慢)算法。

幸运的是,Python 有一个很好的工具可以做你想做的事情,enumerate

for i, n in enumerate(a):
    print(i)

或者,如果您根本不需要这些值,只需索引:

for i in len(range(a)):
    print(i)

(这在文档中至少出现了两次提示,方便地隐藏在新手不会看到的地方。但它也在教程的早期进行了说明。)


接下来,您似乎正在尝试测试 Dolda2000 所解释的情况,具体如下:

n is a[a.index(n)]

为什么那不起作用? 你证明了它们是同一个对象,那么为什么删除它没有任何作用呢?

与变量是存储值(包括对其他地址的引用)的地址的 C 系列语言不同,Python 变量是您绑定到在其他地方单独存在的值的名称。 所以变量不能引用其他变量,但它们可以是相同值的名称。 is表达式测试两个表达式是否命名相同的值。 因此,您证明了同一个值有两个名称,您删除了其中一个名称,但另一个名称和值仍然存在。

一个例子值 1000 字,所以运行这个:

a = object() # this guarantees us a completely unique value
b = a
print a, b, id(a), id(b), a is b
del b
print a, id(a)

(当然,如果您还del a ,那么在某些时候 Python删除该值,但您看不到那个,因为根据定义,您不再有任何名称可以查看它。)


显然,我可以在迭代时从列表中删除。

嗯,有点。 Python 没有定义当你在迭代它时改变它时会发生什么 - 但它确实有特殊的语言来描述for docs 中的内置可变序列(这意味着list )和dict s(我不能记住在哪里,但它在某处说它不能保证引发RuntimeError ,这意味着它应该引发RuntimeError )。

因此,如果您知道a是一个list ,而不是list或第三方序列类的某个子类,可以在迭代时从中删除,并且如果您要删除的元素是在迭代器的左侧或左侧。 但是很难想出对这些知识的实际用途。

当你这样做时会发生这种情况

for n in a: del a[a.index(n)]

试试这个:

a = [0, 1, 2, 3, 4]
for n in a: print(n, a); del a[a.index(n)]

这是你得到的:

(0, [0, 1, 2, 3, 4])
(2, [1, 2, 3, 4])
(4, [1, 3, 4])

因此 n 只是索引的跟踪器,您可以这样想。 每次函数迭代时,n 都会移动到可迭代对象中的下一个相对位置。 在这种情况下,n第一次指代a[0],第二次指代a[1],第三次指代a[2]。 之后列表中没有 nextItem,因此迭代停止。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM