Solution 1

try:
    reduce
except NameError:
    from functools import reduce


def factorial_terms(a_number):
    if a_number < 0:
        raise ValueError("Only defined for positive numbers")
    return list(range(a_number or 1, 0, -1))


def compute_factorial(terms):
    if not terms:
        raise ValueError("Terms should have at least one element")
    return reduce(lambda a, b: a*b, terms, 1)


def factorial(number):
    return compute_factorial(factorial_terms(number))

Function Factorial

The objective of this assignment is to write a factorial function (https://en.wikipedia.org/wiki/Factorial).

In order to do that we'll define 2 helper functions:

  • factorial_terms: will receive a number and return the list of terms to compute the factorial.
  • compute_factorial: Will receive a list of terms and compute de factorial.

Finally, the factorial function will get a number and, using both helper functions, will compute
the answer.

This assignment is designed to practice the reduce function. But if you think it's getting too complicated, you can just try using a for-loop and check the solution later.

Use the tests to see the complete specification of what you're required to write.

Test Cases

test factorial terms with an invalid value - Run Test

import pytest

def test_factorial_terms_with_an_invalid_value():
    """Should raise an exception if an invalid number is provided"""
    with pytest.raises(ValueError):
        factorial_terms(-1)

test compute factorial with no arguments - Run Test

import pytest

def test_compute_factorial_with_no_arguments():
    """Should raise an exception"""
    with pytest.raises(ValueError):
        compute_factorial([])

test factorial for regular integers - Run Test

def test_factorial_for_regular_integers():
    """Should return the factorial number for the terms"""
    assert factorial(5) == 120

test factorial with negative number - Run Test

import pytest

def test_factorial_with_negative_number():
    """Should raise an exception"""
    with pytest.raises(ValueError):
        factorial(-1)

test compute factorial for regular integers - Run Test

def test_compute_factorial_for_regular_integers():
    """Should return the factorial number for the terms"""
    assert compute_factorial([5, 4, 3, 2, 1]) == 120

test factorial of zero - Run Test

def test_factorial_of_zero():
    """Should return 1"""
    assert factorial(0) == 1

test compute factorial invoked with one - Run Test

def test_compute_factorial_invoked_with_one():
    """Should return 1"""
    assert compute_factorial([1]) == 1

test factorial terms are generated ok - Run Test

def test_factorial_terms_are_generated_ok():
    """Should return the correct terms for a number"""
    assert factorial_terms(5) == [5, 4, 3, 2, 1]

test factorial terms of zero - Run Test

def test_factorial_terms_of_zero():
    """Should return [1]"""
    assert factorial_terms(0) == [1]
def factorial_terms(a_number): pass def compute_factorial(terms): pass def factorial(number): pass