Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python syntax: how to return 0 instead of False when evaluating 0

For an assignment we were asked to define a fibonacci function, which I accomplished with this:

def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

However, I have seen recursive functions, such as the factorial function, defined in a one line return statement like so:

def factorial(n):
    return n > 1 and n * factorial(n-1) or 1

So, I attempted to apply the same to my fibonacci function. After several attempts, I got it to work for all tested cases except when s = 0, in which case it returns False when it should return 0. Here is where I am:

def fibonacci(n):
    return ((n == 0 or n == 1) and n) or (n > 1 and (fibonacci(n-1) + fibonacci(n-2)))

I understand that python evaluates 0 to False, so how would I have python return zero instead of False when n is 0 while maintaining the current length/structure of the code? Is that even possible?

Also, is this style of creating a function (recursive or otherwise) more or less desirable/pythonic than the textbook version? (I would imagine not just because of readability)

To be clear, I have satisfied the requirements for the assignment, and for personal knowledge only, I would like a clearer understanding of what is happening in the return statement.

like image 380
Verbal_Kint Avatar asked Dec 21 '22 22:12

Verbal_Kint


2 Answers

The x and y or z idiom doesn't work if y is falsy. You can swap the condition to make it work nonetheless:

def fibonacci(n):
    return n >= 2 and fibonacci(n-1) + fibonacci(n-2) or n

However, as of Python 2.5 (released 6 years ago), we have proper conditional expressions and don't need the and/or hack any longer:

def fibonacci(n):
    return n if n < 2 else fibonacci(n-1) + fibonacci(n-2)

Now this has an exponential runtime complexity. If you want to be efficient, use the O(n) algorithm:

def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a

Or even write a generator to yield all the numbers and only take as much as you need.

like image 171
Niklas B. Avatar answered Dec 23 '22 12:12

Niklas B.


Perhaps this makes it clearer:

def fibonacci(n):
    print ((n == 0 or n == 1) and n)
    print (n > 1 and (fibonacci(n-1) + fibonacci(n-2)))
    return ((n == 0 or n == 1) and n) or (n > 1 and (fibonacci(n-1) + fibonacci(n-2)))


print 0 or False
print False or 0
like image 33
jgritty Avatar answered Dec 23 '22 13:12

jgritty