【问题标题】:Python modifying wrong list?Python修改错误列表?
【发布时间】:2011-05-19 05:40:48
【问题描述】:

我正在尝试使用this 方法生成素数列表。我需要遍历每个数字 2...n 并检查它是否是 2...n 的倍数。出于某种原因,似乎修改了错误的列表。

import sys
import argparse
import math

parser = argparse.ArgumentParser(description='find the largest prime factor of a number')
parser.add_argument('n', type=int, help='number')
args = parser.parse_args()

sieve = []
for i in range(2,args.n+1): sieve.append(i) # tried int(i)


copy1 = sieve # tried making extra copies. . .
copy2 = sieve
copy3 = sieve
#print int(math.sqrt(args.n))

for index, i in enumerate(copy1):
    #print index, i
    for ii in copy2:
        #print ii
        if i % ii == 0:
            sieve[index]= None


print sieve

我收到以下错误:

Traceback (most recent call last):  
  File "3.py", line 22, in <module>
    if i % ii == 0: TypeError: unsupported operand type(s) for %:
'int' and 'str'

【问题讨论】:

    标签: python list primes nested-loops


    【解决方案1】:

    你不是在复制。您正在使用引用,所以copy1copy2copy3 都引用同一个列表——sieve。如果要复制,请使用:

    copy1 = sieve[:]
    

    这将创建sieve 的副本并将其分配给copy1

    【讨论】:

    • 这种混淆非常普遍......所有关于该语言的材料(以及所有具有相似语义的语言,顺便说一句)都应该包含一个带有摘要的巨大红色框。
    • delnan:另外,描述了浮点运算的工作原理。 :-)
    • 而在java String == String 不是你想做的。
    【解决方案2】:

    你需要使用

    copy1 = sieve[:] # tried making extra copies. . .
    copy2 = sieve[:]
    copy3 = sieve[:]
    

    实际复制列表。否则,您只需复制对列表的引用。

    >>> a = [1,2]
    >>> b = a
    >>> c = a[:]
    >>> b[0] = 0
    >>> c[0] = 3
    >>> a
    [0, 2]
    >>> b
    [0, 2]
    >>> c
    [3, 2]
    

    【讨论】:

      【解决方案3】:
      copy1 = sieve
      copy2 = sieve
      copy3 = sieve
      

      这些不是副本,它们是参考的。

      primes = [2,3,5,7]
      
      def is_prime(n):
          if n in primes:
              return True
          for item in primes:
              if n % item == 0:
                  return False
          return True
      
      assert is_prime(4) == False
      assert is_prime(29) == True
      assert is_prime(65) == False
      

      是一种很好的筛法

      更多单元测试,因为它很有趣

      true_primes = [int(item) for item in '11,13,17,19,23,29,31,37,41,43,47'.split(',')]
      for item in xrange(10, 50):
          if is_prime(item) == True:
              assert item in true_primes
          else:
              assert item not in true_primes
      

      【讨论】:

        【解决方案4】:

        Python 具有引用语义。通常,a = b 导致名称 a 引用名称 b 当前引用的相同值。它不会创建或存储新值。

        您可以使用上面提到的 [:] 技巧克隆一个列表。更通用的复制方法是使用copy 模块。

        但是,好的 Python 代码通常不需要显式地频繁地复制内容。您应该熟悉使用列表推导来创建现有序列的“修改版本”。例如,我们可以将筛子实现为(也展示一些其他的东西):

        import sys, argparse, math, itertools
        
        parser = argparse.ArgumentParser(description='find the largest prime factor of a number')
        parser.add_argument('n', type=int, help='number')
        args = parser.parse_args()
        
        # Using a loop over a 'range' to fill a list with increasing values is silly, because
        # the range *is* a list of increasing values - that's how the 'for i in ...' bit works.
        sieve = range(2, args.n + 1)
        
        # We don't need to remember the original loop at all.
        # Instead, we rely on each iteration of the sieve putting a new prime at the beginning.
        for index in itertools.count(): # Counting upward,
          if index >= len(sieve): break # until we run out of elements,
          prime = sieve[index] # we grab the next prime from the list,
          sieve = [x for x in sieve if x == prime or x % prime != 0] # and sieve the list with it.
        # Of course, we can optimize that by checking that prime < sqrt(args.n), or whatever.
        
        print sieve
        

        【讨论】:

        • 我注意到您正在使用 Python 3.x,在这种情况下,range 实际上是 Python 2.x 中的 xrange。为了解决这个问题,我们可以做类似sieve = list(range(2, args.n + 1)) 的事情,明确列出生成器。
        【解决方案5】:

        我无法对此进行测试,因为我没有 Python 3.2 的副本(argparse 是 Python 3.2 中的新功能),但我想到了两件事:

        首先,你需要做sieve.append(int(i))

        其次,您不是在制作 sieve 的副本,您只是在创建对同一列表的新引用。要制作副本,您需要

        copy1 = sieve[:]
        

        【讨论】:

          猜你喜欢
          • 2016-10-26
          • 2016-01-08
          • 2013-07-19
          • 2021-01-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-12-24
          相关资源
          最近更新 更多