Calculate probability of dice total
import

why import product within your method, and not in the module scope? 

instantiation

There is just no reason to instantiate the list in 

choices = list(product(range(1, faces+1), repeat=dice))


when you just iterate over it.

As noted by @JordanSinger, this takes a huge toll on memory, while using it as an iterable suffices



numpy alternative

a = sum(
    np.meshgrid(
        *(np.arange(1, faces + 1, dtype="uint8") for _ in range(dice)),
        copy=False
    )
)
(a == number).sum()


but for larger number of dice and faces this runs into MemoryError too

alternative

The integer value of True is 1. So instead of keeping a counter, and incrementing it each time there is a match, you can do:

def poss_combinations(dice, faces, number):
    choices = product(range(1, faces+1), repeat=dice)
    return sum(sum(roll) == number for roll in choices)


But even this will take ages for 10**10 combinations. Better would be to use a analytical formula like this one



alternative 2

A first alternative, is instead of taking the product, using itertools.combination_with_replacement to get all the combinations of dice rolls. For 10 10-faced dice, this is sum(1 for _ in combinations_with_replacement(range(10), 10)) or 92378. This is a much better number to work with that 10**10

The next step is to check which combinations combine to numbers, and then calculate how much of these combinations are possible link

from collections import Counter
from functools import reduce
from math import factorial
from operator import mul


def product_math(iterable):
    return reduce(mul, iterable, 1)


def combination_permutations(combination):
    c = Counter(combination)
    return factorial(sum(c.values())) / product_math(
        factorial(i) for i in c.values()
    )


calculates the number of possible permutations of a combination

def poss_comb_permutations(dice, faces, numbers):
    return sum(
        combination_permutations(combination)
        for combination in combinations_with_replacement(
            range(1, faces + 1), dice
        )
        if sum(combination) == numbers
    )


Then uses this to calculate the number of matching dice rolls.

All 3 methods arrive at the same result for 

dice = 7
faces = 7
number = 20