Summation and product functions using functional paradigm
The start parameter of accumulate is a bit misleading.
My first thought was that start is the first element of the sequence,
but it's an accumulated value.
A more common name is acc or accum.

Reassigning function parameter is considered a bad practice, 
in any language as far as I remember.
It's basically reusing an input variable for one additional purpose.
start is an input to your function,
but when you reassign it, it becomes something else:
instead of being just the input,
now it carries the result of a calculation.
When you look at your function body,
the variable start is sometimes the input, 
sometimes the result of a local calculation.
This duality in purpose can be confusing and can lead to errors.
It's cleaner to assign the mutated value to a completely new local variable.

In this version, acc always has the same value,
there can be no confusion and misuse, it's perfectly clear:

def accumulate(combiner, acc, n, term):
    """Return the result of combining the first n terms in a sequence."""
    if n == 0:
        return acc
    else:
        next_acc = combiner(term(n), acc)
        return accumulate(combiner, next_acc, n-1, term)


The benefit may not be obvious in this simple function,
but I hope you see the truth in the principle of not reusing parameter variables.
In a longer, more complicated function the benefits would become more clear.

In languages that have out-parameters,
re-assignment of parameters forces me to double-check the signature.
Although Python doesn't have out-parameters,
I still review code like this with suspicion,
in case the author may have mistakenly believed that the re-assigned value will produce a side effect outside the function.
This may sound a bit paranoid, but I've seen this kind of thing happen more than once.
By not re-assigning parameters,
all suspicions are cleared, and the code is easier to review.

For the record, I was tempted to suggest to drop the else clause there,
to simplify to:

def accumulate(combiner, acc, n, term):
    """Return the result of combining the first n terms in a sequence."""
    if n == 0:
        return acc
    next_acc = combiner(term(n), acc)
    return accumulate(combiner, next_acc, n-1, term)


But then, most functional languages return the last evaluation,
and explicit return statements are not recommended,
which makes if-else necessary.
For example the Scala solution would look something like this:

def accumulate(combiner, acc, n, term): Int = {
    if (n == 0) {
        acc
    } else {
        val nextAcc = combiner(term(n), acc)
        accumulate(combiner, nextAcc, n-1, term)
    }
}


So using the explicit else clause is closer to the spirit of functional programming, so I'd leave that as you did.