我的类无法正确生成斐波那契数列

问题描述 投票:0回答:3

我正在尝试创建一个生成斐波那契数列的类。我的两个模块如下: 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
python tdd fibonacci
3个回答
2
投票

要处理 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]

0
投票

看起来代码正在做什么和测试期望什么之间存在误解。 max_count 在原始代码中的实现方式很有意义——它表示要生成的斐波那契数的数量。因此,如果 max_count=1,它应该产生 [0],而不是 [0, 1]。这与迭代器通常的工作方式一致:它们生成特定数量的项目,而不是达到特定索引的项目。

如果测试期望 max_count=1 为 [0, 1],则测试可能是错误的,或者分配要求可能不清楚。如果要求明确指出 [0, 1] 是预期输出,则需要更改逻辑,以便 max_count 表示最后一个斐波那契数的索引而不是计数。但老实说,根据标准迭代器行为,原始代码似乎是正确的,因此可能值得仔细检查赋值指令。


0
投票

我添加了一个与OP和@Mark Tolonen的答案相距不远的解决方案。

在我的测试代码中我添加了测试

test_max_count_2()
,我认为在使用TDD开发代码时这是必要的(我没有使用
pytest
,而是使用了标准模块
unittest
)。

此外,在课堂上

Fibonacci
我使用了2个属性(
previous_number_1
previous_number_2
)来阐明代码的工作原理。

文件 test_fibonacci.py

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
© www.soinside.com 2019 - 2024. All rights reserved.