Python:使用模运算符的奇怪行为

时间:2012-03-13 17:27:40

标签: python fibonacci

解决方案可能相当简单,但我无法弄清楚。这是代码,它是一个简单的斐波那契数字生成器。目标是将所有均匀的斐波纳契数字总结为4,000,000以下。

我的方法是首先生成低于4,000,000的所有斐波纳契数,然后: a)用偶数生成一个新列表(“偶数”)(这很好) b)从“all”列表中删除奇数

然而,在后一种情况下,由于我不明白的原因,输出是: [2,5,8,21,34,89,144,377,610,1597,2584,6765,10946,28657,46368,121393,196418,514229,832040,2178309,3524578]

非常感谢任何帮助。谢谢!

all = []
even = []

def fibonacci():
    a, b = 1, 2
    while a < 4000000:
        all.append(a)
        a, b = b, a + b
    print all

##Putting all the even fibonacci numbers in a different list and summing them up works fine
#    for i in all:
#        if i % 2 == 0:
#            even.append(i)
#    print even                   
#    print sum(even)


# But for some strange reason I can't figure out how to remove the odd numbers from the list
    for i in all:
        if i % 2 != 0:
            all.remove(i)

    print all
    print sum(all)

fibonacci()

4 个答案:

答案 0 :(得分:4)

这是一种“陷阱”情况:您在迭代列表时从列表中删除项目,从而更改列表,导致迭代行为异常。试试这个:

...
# But for some strange reason I can't figure out how to remove the odd numbers from the list
    for i in all[:]:
        if i % 2 != 0:
            all.remove(i)
...

这就是所谓的“切片”表示法,并使您迭代列表的一次性副本,以便您的迭代不受all.remove()调用的影响。

答案 1 :(得分:3)

您无法从迭代的列表中删除项目。 Python使用迭代器,它只知道相对于列表开头的当前索引。当您从列表的前面删除项目时,所有元素的位置都会更改,您跳过下一个元素。

您可以通过多种方式避免此问题,例如使用生成器:

def fibonacci():
    a, b = 1, 2
    while a < 4000000:
        yield a
        a, b = b, a + b

def even(seq):
    for item in seq:
        if item % 2 == 0:
            yield item

print sum(even(fibonacci()))

答案 2 :(得分:0)

如果我们仔细观察迭代如何在以下代码中发生

for i in all:
        if i % 2 != 0:
            all.remove(i)

            # Add these two lines for debugging.. 
            # Or to know how this iteration functions

            print "when %d: " %i 
            print all

    print "Remaining Evens",
    print all

如果最大数量为100,则输出结果如下。

original series [1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
when 1: 
[2, 3, 5, 8, 13, 21, 34, 55, 89]
when 3: 
[2, 5, 8, 13, 21, 34, 55, 89]
when 13: 
[2, 5, 8, 21, 34, 55, 89]
when 55: 
[2, 5, 8, 21, 34, 89]
Remaining Evens [2, 5, 8, 21, 34, 89]

当python开始迭代列表时,它在技术上只记住它必须迭代的数字的位置。

如果我们观察输出,

在第一次迭代中,它删除1。

在下一次迭代中,它会记住它必须计算第二个位置。现在列表从“2”开始。所以第二个位置是“3”。因此它将其删除。

在下一次迭代中,它会记住它必须从第3位开始计算。现在在当前列表中,第3个位置是“8”。所以,它从那里算起..不是从“5”。因此,如果不满足,则为13 ..

因此,它会跳过所有这些数字..

如何解决这个问题:

实际上,您需要复制“所有”列表并进行迭代。 (它不应该指同一个对象..)。如果是这样,那就会发生同样的事情。

你可以通过简单地使用切片操作符来做到这一点:

copy_all= all[:] 

#or else, you need to use deepcopy()

import copy
copy_all = copy.deepcopy(all)

# you iterate copy_all but delete in all. 

However, prefer the first method. Its very simple.

答案 3 :(得分:-1)

这是因为你删除索引i处的项目而不是数字“i”。