TheAlgorithms / Python

All Algorithms implemented in Python
https://thealgorithms.github.io/Python/
MIT License
194.81k stars 45.84k forks source link

Nested functions can't be tested by doctest #10837

Open nkstonks opened 1 year ago

nkstonks commented 1 year ago

Feature description

9943

So I was adding doctests to a nested function in fibonacci.py, however doctest doesn't seem to be testing that function.

The function in this case is fib_recursive_term(), that's nested inside fib_recursive, as seen below: image Note: the 5 doctests for fib_recursive_term() is what I added.

If I run the doctests, I get this output below. As per the output below, 5 tests for fib_recursive() runs, but the 5 tests for fib_recursive_term() doesn't. image

So I want to propose taking the fib_recursive_term() function out of the fib_recursive() function and have it defined above it, so doctests actually goes through it. Would there be any issues there?

nkstonks commented 1 year ago

misclicked and accidentally closed the issue, sorry...

AasheeshLikePanner commented 1 year ago

Why not just write the code just Like this? It is difficult in photo to know what is the issue and unable to copy code.

nkstonks commented 1 year ago

Oh yeah my bad, I forgot that was a thing

What I wanted to show with those screenshots was just that I really just that there is indeed doctests for fib_recursive_term (first screenshot) but when I run the doctests it doesn’t say that the function as tested (second screenshot)

Below is the relavant part of the code, if you want the whole file then here’s the link to it: https://github.com/nkstonks/Python/blob/master/maths/fibonacci.py

def fib_recursive(n: int) -> list[int]:
    """
    Calculates the first n (0-indexed) Fibonacci numbers using recursion
    >>> fib_iterative(0)
    [0]
    >>> fib_iterative(1)
    [0, 1]
    >>> fib_iterative(5)
    [0, 1, 1, 2, 3, 5]
    >>> fib_iterative(10)
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    >>> fib_iterative(-1)
    Traceback (most recent call last):
        ...
    Exception: n is negative
    """

    def fib_recursive_term(i: int) -> int:
        """
        Calculates the i-th (0-indexed) Fibonacci number using recursion
        >>> fib_recursive_term(0)
        0
        >>> fib_recursive_term(1)
        1
        >>> fib_recursive_term(5)
        5
        >>> fib_recursive_term(10)
        55
        >>> fib_recursive_term(-1)
        Traceback (most recent call last):
            ...
        Exception: n is negative
        """
        if i < 0:
            raise Exception("n is negative")
        if i < 2:
            return i
        return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)

    if n < 0:
        raise Exception("n is negative")
    return [fib_recursive_term(i) for i in range(n + 1)]
AasheeshLikePanner commented 1 year ago

I don't know why but When I run the code. The error doesn't come in my computer. I am using the online python compiler (Interpreter)

nkstonks commented 1 year ago

Yeah the program runs just fine, it's just that if you look at the output of it, towards the end of it it says this:

2 items had no tests:
    __main__
    __main__.time_func
5 items passed all tests:
   6 tests in __main__.fib_binet
   5 tests in __main__.fib_iterative
   5 tests in __main__.fib_memoization
   5 tests in __main__.fib_recursive
   5 tests in __main__.fib_recursive_cached
26 tests in 7 items.
26 passed and 0 failed.
Test passed.

The thing with this is that it's not testing the tests in the fib_recursive_term function, as it doesn't mention that function in the output.

But if I take the fib_recursive_term function outside of the fib_recursive function, something like this:

def fib_recursive_term(i: int) -> int:
        """
        Calculates the i-th (0-indexed) Fibonacci number using recursion
        >>> fib_recursive_term(0)
        0
        >>> fib_recursive_term(1)
        1
        >>> fib_recursive_term(5)
        5
        >>> fib_recursive_term(10)
        55
        >>> fib_recursive_term(-1)
        Traceback (most recent call last):
            ...
        Exception: n is negative
        """
        if i < 0:
            raise Exception("n is negative")
        if i < 2:
            return i
        return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)

def fib_recursive(n: int) -> list[int]:
    """
    Calculates the first n (0-indexed) Fibonacci numbers using recursion
    >>> fib_iterative(0)
    [0]
    >>> fib_iterative(1)
    [0, 1]
    >>> fib_iterative(5)
    [0, 1, 1, 2, 3, 5]
    >>> fib_iterative(10)
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    >>> fib_iterative(-1)
    Traceback (most recent call last):
        ...
    Exception: n is negative
    """

    if n < 0:
        raise Exception("n is negative")
    return [fib_recursive_term(i) for i in range(n + 1)]

notice how the fib_recursive_term function is above the fib_recursive function now.

If I run this, the program runs fine and the fib_recursive_term function gets tested as well. (relavant output below)

2 items had no tests:
    __main__
    __main__.time_func
6 items passed all tests:
   6 tests in __main__.fib_binet
   5 tests in __main__.fib_iterative
   5 tests in __main__.fib_memoization
   5 tests in __main__.fib_recursive
   5 tests in __main__.fib_recursive_cached
   5 tests in __main__.fib_recursive_term
31 tests in 8 items.
31 passed and 0 failed.
Test passed.

So that's why I'm proposing to take the fib_recursive_term function out of the fib_recursive function and have it as a global function instead of a nested (local) function.

Khany123 commented 11 months ago

Use this ; Lolll🤣🤣🤣 USE THIS IN PYTHON ; 🤣🤣🤣🤣🤣🤣🤣🤣

MilindSaini commented 11 months ago

def fib_recursive(n: int) -> list[int]: """ Calculates the first n (0-indexed) Fibonacci numbers using recursion

fib_iterative(0) [0] fib_iterative(1) [0, 1] fib_iterative(5) [0, 1, 1, 2, 3, 5] fib_iterative(10) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55] fib_iterative(-1) Traceback (most recent call last): ... Exception: n is negative """

def fib_recursive_term(i: int) -> int:
    """
    Calculates the i-th (0-indexed) Fibonacci number using recursion
    >>> fib_recursive_term(0)
    0
    >>> fib_recursive_term(1)
    1
    >>> fib_recursive_term(5)
    5
    >>> fib_recursive_term(10)
    55
    >>> fib_recursive_term(-1)
    Traceback (most recent call last):
        ...
    Exception: n is negative
    """
    if i < 0:
        raise Exception("n is negative")
    if i < 2:
        return i
    return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)

if n < 0:
    raise Exception("n is negative")
memo = [0] * (n + 1)
for i in range(2, n + 1):
    memo[i] = fib_recursive_term(i)
return memo

This corrected code properly implements memoization and stores the computed Fibonacci numbers in the memo list. It also eliminates the redundant computations in the original code, which makes it more efficient.

Hope this is the right way I am understanding your problem