我正在尝试创建一个生成斐波那契数列的类。我的两个模块如下: fibonacci.py 模块和 test_fibonacci.py 模块。 前两个测试通过了,但无论我做什么,第三个测试似乎都失败了。 我怎样才能通过? 请帮我纠正这个问题。
斐波那契.py代码:
class Fibonacci:
"""An iterable for creating a Fibonacci series"""
def __init__(self, max_count):
"""
Constructor requires a single positional argument
which must be an integer.
"""
self.max_count = max_count # Maximum number of iterations
self.current_count = 0 # Keeps track of number of Fibonacci numbers generated
self.current_number = 0 # Tracks current Fibonacci number
self.next_number = 1 # Tracks next Fibonacci number
# Raises ValueError for non-integer input
if not isinstance(max_count, int):
raise ValueError(f'{max_count} is not an integer.')
def __iter__(self):
"""Returns the instance of Fibonacci class as an iterator"""
return self
def __next__(self):
"""Defines the instance of Fibonacci class as an iterator"""
# Handles the case where max_count is 0 by returning 0 once
if self.max_count == 0 and self.current_count == 0:
self.current_count += 1
return 0
# Stops iteration when the number of iterations equals max_count
if self.current_count >= self.max_count:
raise StopIteration
temp = self.next_number
self.next_number = self.current_number + self.next_number
self.current_number = temp
self.current_count += 1 # Counter incremented for next iteration
return self.current_number # Returns the current Fibonacci number
这是测试代码:
import pytest
from fibonacci import Fibonacci
def test_non_integer():
"""Test that non-integer input raises ValueError"""
with pytest.raises(ValueError):
Fibonacci(3.14)
def test_max_count_0():
"""
Tests that [0] is returned with constructor value of 0
if cast as a list.
"""
assert list(Fibonacci(0)) == [0]
def test_max_count_1():
"""
Tests that [0,1] is returned with constructor value of 1
if cast as a list.
"""
assert list(Fibonacci(1)) == [0,1]
这是 Pytest 的输出:
test_fibonacci.py::test_non_integer PASSED [ 33%]
test_fibonacci.py::test_max_count_0 PASSED [ 66%]
test_fibonacci.py::test_max_count_1 FAILED [100%]
test_fibonacci.py:37 (test_max_count_1)
[1] != [0, 1]
Expected :[0, 1]
Actual :[1]
<Click to see difference>
def test_max_count_1():
"""
Tests that [0,1] is returned with constructor value of 1
if cast as a list.
"""
> assert list(Fibonacci(1)) == [0,1]
E assert [1] == [0, 1]
E
E At index 0 diff: 1 != 0
E Right contains one more item: 1
E
E Full diff:
E [
E - 0,
E 1,
E ]
test_fibonacci.py:43: AssertionError
要处理 0,捕获当前值以返回,然后计算新值。 返回捕获的值。 这将通过您的测试,如图所示。
class Fibonacci:
"""An iterable for creating a Fibonacci series"""
def __init__(self, max_count):
"""
Constructor requires a single positional argument
which must be an integer.
"""
self.max_count = max_count # Maximum number of iterations
self.current_count = 0 # Keeps track of number of Fibonacci numbers generated
self.current_number = 0 # Tracks current Fibonacci number
self.next_number = 1 # Tracks next Fibonacci number
# Raises ValueError for non-integer input
if not isinstance(max_count, int):
raise ValueError(f'{max_count} is not an integer.')
def __iter__(self):
"""Returns the instance of Fibonacci class as an iterator"""
return self
def __next__(self):
"""Defines the instance of Fibonacci class as an iterator"""
# Stops iteration when the number of iterations is greater than max_count
if self.current_count > self.max_count: # NOTE: change to > from
raise StopIteration
# NOTE: a,b,c = b,c,d is short for a=b; b=c; c=d
return_value, self.current_number, self.next_number = \
self.current_number, self.next_number, self.current_number + self.next_number
self.current_count += 1 # Counter incremented for next iteration
return return_value # Returns the current Fibonacci number
print(list(Fibonacci(0)))
print(list(Fibonacci(1)))
print(list(Fibonacci(5)))
输出:
[0]
[0, 1]
[0, 1, 1, 2, 3, 5]
看起来代码正在做什么和测试期望什么之间存在误解。 max_count 在原始代码中的实现方式很有意义——它表示要生成的斐波那契数的数量。因此,如果 max_count=1,它应该产生 [0],而不是 [0, 1]。这与迭代器通常的工作方式一致:它们生成特定数量的项目,而不是达到特定索引的项目。
如果测试期望 max_count=1 为 [0, 1],则测试可能是错误的,或者分配要求可能不清楚。如果要求明确指出 [0, 1] 是预期输出,则需要更改逻辑,以便 max_count 表示最后一个斐波那契数的索引而不是计数。但老实说,根据标准迭代器行为,原始代码似乎是正确的,因此可能值得仔细检查赋值指令。
我添加了一个与OP和@Mark Tolonen的答案相距不远的解决方案。
在我的测试代码中我添加了测试
test_max_count_2()
,我认为在使用TDD开发代码时这是必要的(我没有使用pytest
,而是使用了标准模块unittest
)。
此外,在课堂上
Fibonacci
我使用了2个属性(previous_number_1
和previous_number_2
)来阐明代码的工作原理。
import unittest
from fibonacci import Fibonacci
class MyTestCase(unittest.TestCase):
def test_max_count_0(self):
# Tests that [0] is returned with constructor value of 0
# if cast as a list.
assert list(Fibonacci(0)) == [0]
def test_max_count_1(self):
# Tests that [0,1] is returned with constructor value of 1
# if cast as a list.
assert list(Fibonacci(1)) == [0, 1]
# I have to add this test to complete the method __next__ of the class Fibonacci
def test_max_count_2(self):
assert list(Fibonacci(2)) == [0, 1, 1]
def test_non_integer(self):
"""Test that non-integer input raises ValueError"""
with self.assertRaises(ValueError):
Fibonacci(3.14)
if __name__ == '__main__':
unittest.main()
fibonacci.py
class Fibonacci:
def __init__(self, max_count):
"""
Constructor requires a single positional argument
which must be an integer.
"""
self.max_count = max_count # Maximum number of iterations
self.current_count = 0 # Keeps track of number of Fibonacci numbers generated
self.current_number = 0 # Tracks current Fibonacci number
self.previous_number_1 = 0 # Tracks previous Fibonacci number
self.previous_number_2 = 0 # Tracks previous Fibonacci number
# Raises ValueError for non-integer input
if not isinstance(max_count, int):
raise ValueError(f'{max_count} is not an integer.')
def __iter__(self):
"""Returns the instance of Fibonacci class as an iterator"""
return self
def __next__(self):
"""Defines the instance of Fibonacci class as an iterator"""
# Stops iteration when the number of iterations is greater than max_count
if self.current_count > self.max_count:
raise StopIteration
if self.current_count <= 1:
self.current_number = self.current_count
else:
self.current_number = self.previous_number_1 + self.previous_number_2
self.previous_number_2 = self.previous_number_1
self.previous_number_1 = self.current_number
self.current_count += 1
return self.current_number