[英]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.