它同意for
循环中的可迭代项仅评估一次。因此,输出f called
打印一次。
我努力想弄清楚的是,为什么我没有得到out-of-bound error
?由于在评估时,长度等于100
。
mylist = [x for x in range(100)]
def printmylist(thelist):
print("f called")
return thelist
for i, item in enumerate(printmylist(mylist)):
print(len(mylist))
del mylist[len(mylist) - i - 1]
f called 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51
答案 0 :(得分:2)
在for
循环中,使用列表的当前长度来评估要删除的位置。并且,您从列表的末尾删除。所以你的循环只迭代50次。
如果您更改print
语句以显示i
,您会发现它只会从0到49进行计数。
答案 1 :(得分:2)
虽然print("f called")
只被调用一次,但是在您的案例中存储iterable object
评估值的变量(称为enumerate(printmylist(mylist))
)从时间变为set
的变化时间,因为你逐个删除枚举。首先你有100个项目,但它逐个减少:
Note: len(mylist) - i - 1 = 99, delete index 99 -> 100 removed
1 2 3 ... 98 99 100 #len(mylist) = 100
^ <-- here is i = 0
Note: len(mylist) - i - 1 = 98, delete index 98 -> 99 removed
1 2 3 ... 98 99 #len(mylist) = 99
^ <-- here is i = 1
Note: len(mylist) - i - 1 = 97, delete index 97 -> 98 removed
1 2 3 ... 98 #len(mylist) = 98
^ <-- here is i = 2
... and so on
另外,由于i
将针对该变量(iterable object
)检查循环的每一端,因此,您只能从50
个项目中打印100
个项目。
来自 Python for statement documentation:
表达式列表的评估一次;它应该产生一个可迭代的 宾语。为
expression_list
的结果创建了一个迭代器。 然后,对于由提供的每个项目,一次执行该套件 迭代器,按升序索引。每个项目依次是 使用分配的标准规则分配给目标列表, 然后套件被执行。 当项目耗尽时(即 当序列为空时立即,else
子句中的套件, 如果存在,则执行,loop
终止。
为了简化,假设你有
v = enumerate(printmylist(mylist)) #v is the iterable object
虽然只评估过一次,但每次删除项目时,set
所指向的v
都会发生变化,但i
会在v
上进行迭代。因此,i
将逐渐增加,直到最后i = 50
。
.
.
.
v = ... 50, i = 49
^ <-- here is i and is in v
v = ... 50 , i = 50 and is out from v
^ <-- no more item found
在边界之外不再需要评估项目。这样就得到了结果:
100 99 ... 51
并没有超出范围。
More on how for works internally,包括它如何创建内部索引器并每次都根据终止值指向的值进行检查。