As far as I know there is no builtin way in itertools to do this. You can evidently filter the result, but this would be rather inefficient: one expects only a small amount of combinations to add up to sum.
Given all fed values are positive (zero is acceptable) however, you can use this lazy function:
def product_sum(sum,*args):
return product_sum_intern(sum,0,0,[],*args)
def product_sum_intern(sum,cur_sum,idx,cur,*args):
if idx >= len(args):
if sum == cur_sum:
yield tuple(cur)
elif cur_sum <= sum:
for x in args[idx]:
cur.append(x)
for e in product_sum_intern(sum,cur_sum+x,idx+1,cur,*args):
yield e
cur.pop()
For instance:
>>> list(product_sum(15,[1,12],[1,4,7],[0,3,6,7],[0,1]))
[(1, 7, 6, 1), (1, 7, 7, 0)]
this algorithm gives up on branches as soon as it finds out it is already overshooting the sum. A more advanced algorithm exists that also gives up branches if there is no way to get in reach of the sum.
list(filter(lambda x: sum(x) == 1, itertools.product(a,a,a,a,a)))