HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonModerate

Telling fibonaccis to the user

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
userthefibonaccistelling

Problem

Though this program tells the truth (unless you change the source code), it does tell Fibonacci numbers, depending on the user's input. Keeping in mind of all (or most) of the feedback given from previous questions, I wrote this program to see how well I have progressed.

def get_fibonacci_sequence(max):
    '''
    Returns the Fibonacci sequence from the
    first to the nth Fibonacci number.
    '''

    fib1 = 1
    fib2 = 1
    result = [fib1, fib2]
    for i in range(2, max):
        result.append(fib1 + fib2)
        fib1 = fib2
        fib2 = result[i]
    return result

def get_nth_fibonacci(n):
    '''Returns the nth Fibonacci number.'''

    return get_fibonacci_sequence(n)[n - 1]

def main():
    print("Would you like to have the sequence or the number?")
    print("Enter 's' for sequence, and anything else for the number.")
    seqOrNum = input("> ")
    if seqOrNum == 's':
        print("Up to which number would you like the sequence up to?")
        max = int(input("> "))
        print("The sequence up to the {}th Fibonacci number:".format(max))
        print(get_fibonacci_sequence(max))
    else:
        print("Which Fibonacci number would you like to get?")
        max = int(input("> "))
        print("The {}th Fibonacci number is:".format(max),
              get_nth_fibonacci(max))

if __name__ == "__main__":
    main()


Example Output:

Would you like to have the sequence or the number?
Enter 's' for sequence, and anything else for the number.
> s
Up to which number would you like the sequence up to?
> 10
The sequence up to the 10th Fibonacci number:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]


Concerns:

  • Are my docstrings well-used?



  • Does it follow conventions?

Solution

Generators, not lists

Rather than returning a list of Fibonacci numbers, it would be much more useful to simply return an infinite generator of them. That is, yield them. This way, you don't even need the max:

def get_fibonacci_numbers():
    '''
    Generator for all the fibonacci numbers
    '''
    fib1 = 1
    fib2 = 1
    yield fib1
    yield fib2
    while True:
        yield fib1 + fib2
        fib1 = fib2
        fib2 = fib1 + fib2


Note that double assigns are actually better done in one go for clarity:

def get_fibonacci_numbers():
    '''
    Generator for all the fibonacci numbers
    '''
    fib1, fib2 = 0, 1
    while True:
        yield fib2
        fib1, fib2 = fib2, fib1 + fib2


If you want the first n numbers, you can use itertools.islice.

Why a generator?

You can easily turn a generator into a list of specific size, so you're not losing any functionality this way. But there's simply so much you can do with a lightweight generator that you can't do with a list. Consider some simple problems - what's the first Fibonacci number over 1000?

>>> next(dropwhile(lambda x: x < 1000, get_fibonacci_numbers()))


Euler problem #2: find the sum of the even-valued fibonacci numbers under 4 million?

>>> sum(i for i in takewhile(lambda x: x < 4e6, get_fibonacci_numbers()) if i%2 == 0)


Can't do either with a list. At least, not unless you know where to stop up front.

If you want just the nth one, that's:

def get_nth_fibonacci(n):
    return next(itertools.islice(
        get_fibonacci_numbers(),
        n, None))

Code Snippets

def get_fibonacci_numbers():
    '''
    Generator for all the fibonacci numbers
    '''
    fib1 = 1
    fib2 = 1
    yield fib1
    yield fib2
    while True:
        yield fib1 + fib2
        fib1 = fib2
        fib2 = fib1 + fib2
def get_fibonacci_numbers():
    '''
    Generator for all the fibonacci numbers
    '''
    fib1, fib2 = 0, 1
    while True:
        yield fib2
        fib1, fib2 = fib2, fib1 + fib2
>>> next(dropwhile(lambda x: x < 1000, get_fibonacci_numbers()))
>>> sum(i for i in takewhile(lambda x: x < 4e6, get_fibonacci_numbers()) if i%2 == 0)
def get_nth_fibonacci(n):
    return next(itertools.islice(
        get_fibonacci_numbers(),
        n, None))

Context

StackExchange Code Review Q#114384, answer score: 16

Revisions (0)

No revisions yet.