新手编写Python质因数提取代码运行异常:输入60结果错误、120触发ValueError
质因数计算代码运行异常排查
问题背景
作为编程入门学习者,涉及的问题或代码疏漏还请见谅。
本次编程作业要求编写代码实现:用户输入一个数字后,程序返回该数字的质因数。目前已编写的代码运行不符合预期,始终定位不到问题,更希望明确当前代码无法正常运行的原因以及修复方式,而非单纯获取更优的实现方案。
现有代码
def all_factors(): '''first create a list of all factors''' number = int(input("please enter a number: ")) # ask for number prime_list = [] # this is gonna be the prime factor list check_list= list(range(2,number)) # all the numbers up to the input number. factor_list = [] #all the factors of the inputnumber, including non-primes for factor in check_list: if number%factor == 0: factor_list.append(factor) ''' function to check if factor is a prime number''' prime_list = factor_list.copy() for num in prime_list: if num%2 == 0 and num!= 2: '''remove even numbers except 2''' prime_list.remove(num) elif num%2!=0 and num!= 2: '''remove odd numbers that are not prime ''' try_list = list(range(2,num)) for check in try_list: if num%check == 0: prime_list.remove(num) pass result = set(prime_list) print(result) print('the factor list is ',factor_list) print('the prime list is ',prime_list)
测试异常表现
分别使用60、120两个数字对代码进行测试,均出现异常:
- 输入60时,返回结果列表中仍包含非质数的偶数
- 输入120时程序触发报错
- 无法理解为什么类似10这类非质数没有从prime_list中被移除
输入60的运行输出
please enter a number: 60 {2, 3, 5, 10, 15, 30} the factor list is [2, 3, 4, 5, 6, 10, 12, 15, 20, 30] the prime list is [2, 3, 5, 10, 15, 30]
输入120的报错输出
please enter a number: 120 --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-19-fc97ce9d24c1> in <module> ----> 1 all_factors() <ipython-input-16-bb4c2a026f3b> in all_factors() 25 for check in try_list: 26 if num%check == 0: ---> 27 prime_list.remove(num) 28 pass 29 ValueError: list.remove(x): x not in list
异常原因拆解
- 核心问题1:遍历列表的同时对原列表执行删除操作。Python的列表迭代器内部按固定索引值推进,每取完一个元素就将索引值加1,不会因为列表元素的删除、移动而调整索引位置。当某个元素被删除后,后续元素会自动向前填充空位,原本在当前索引之后的元素会向前移动,导致迭代器直接跳过这些被前移的元素,从未对它们执行质数判断。
以输入60的执行流程为例:- 初始prime_list为[2,3,4,5,6,10,12,15,20,30],迭代器从索引0开始依次取元素2、3、4
- 取到4时执行删除操作,此时列表变为[2,3,5,6,10,12,15,20,30],原本在索引3的5前移到索引2的位置
- 迭代器索引自动加1走到3,取到元素6,执行删除操作,列表变为[2,3,5,10,12,15,20,30],原本在索引4的10前移到索引3的位置
- 迭代器索引自动加1走到4,取到元素12,执行删除操作,列表变为[2,3,5,10,15,20,30],原本在索引5的15前移到索引4的位置
- 迭代器索引自动加1走到5,取到元素20,执行删除操作,列表变为[2,3,5,10,15,30],原本在索引6的30前移到索引5的位置
- 迭代器索引自动加1走到6,已超出当前列表的最大索引5,循环直接结束
整个流程中,前移到索引3的10、索引4的15、索引5的30从来没有被迭代器取到过,自然不会被执行质数判断和删除操作,因此最终留在列表中。
- 核心问题2:非质数判断逻辑内重复执行删除操作,没有设置跳出机制。对于奇数非质数的判断,一旦检测到num能被try_list中的任意数整除,代码就会执行
prime_list.remove(num),但这个操作写在check的遍历循环内部,没有用break跳出循环。当num被第一次删除后,后续的check判断还会继续运行,下一次再执行remove(num)时,该元素已经不在列表中,就会触发ValueError: list.remove(x): x not in list报错。 - 附加不规范问题:代码中在判断语句行内用三引号写注释,属于写法不规范。Python中行内注释应使用
#,三引号标记的内容会被当成字符串表达式执行,虽然不影响当前运行,但容易引发后续解析问题。
修复思路
- 遍历操作和修改操作分离:先对因子列表做拷贝,遍历这个拷贝列表中的每一个元素,判断是否为质数,将符合质数要求的元素存入新的结果列表,全程不修改正在遍历的列表长度,从根源上避免跳过元素的问题。
- 优化非质数判断逻辑:只要发现某个因子存在除1和自身外的因数,就立刻用
break跳出内层判断循环,不重复执行删除操作。 - 规范注释写法:将三引号的行内注释替换为
#开头的标准注释,避免语法歧义。
内容的提问来源于stack exchange,提问作者Festi
相关产品推荐
相关产品推荐

