0

I came across this version of the factorial exercise and am completely at sea:

fac = lambda n: n and n * fac(n-1) or 1

It's the and/or part that I can't get my head around -- particularly the n and ... part.

Last: when you run this without the n and ... part, it returns a "maximum recursion depth exceeded" error.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578

4 Answers4

1

Lambda is just another notation for a regular function. It helps to write it like this:

def fac(n):
    if n:
        return n * fac(n-1)
    else:
        return 1

In this notation, it's much easier to see the base case and the recursive case. It's also important to know that the Boolean operators or and and always return one of their operands: https://docs.python.org/3/library/stdtypes.html#truth-value-testing

sammy
  • 857
  • 5
  • 13
1

It's a "clever" way of writing an if/else expression. It would be better expressed using those keywords instead:

fac = lambda n: n * fac(n-1) if n else 1

Or even more explicitly:

fac = lambda n: (n * fac(n-1) if n != 0 else 1)
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
1

The code is badly written in my opinion, probably by a beginner who thinks they're smart (or it might be way to speed up the code, but in that case it should be heavily commented). So if you don't get it, it's not your fault, but the programmer's.

But let's analyse it:

n and x or 1 will return:

  • 1 if n is 0, as 0 and x is always 0 no matter what x is, and due to shortcut evaluation, x (i.e., n*fax(n-1)) is never evaluated; and 0 or 1 is 1.
  • x if n is non-zero, as in this case x cannot be 0.

So the n and x or 1 handles the base case of the recursion, stopping it when n reaches 0. This is also why you get a "maximum recursion depth exceeded" error if you remove the "n and".

The rest is just the definition of factorial, which I guess I don't need to explain here.

Here's a more sane and readable version:

fac = lambda n: (n * fac(n-1)) if n!=0 else 1

And here's how I would prefer to write it, to make it readable and end with the recursive call, as some compilers may be able to optimize the recursion in that situation:

def fac(n):
    if n==0:
        return 1
    else:
        return n*fac(n-1)

None of these handles the undefined case when n is negative very well (it results in recursion overflow), so you just have to avoid that situation if you use the function.

Jesper
  • 1,611
  • 13
  • 10
0

n and refers to n and n * fac(x-1) being truthy when its not 0.

ldz
  • 2,217
  • 16
  • 21