Это не требует itertools; просто используйте вложенный l oop. Внешний l oop выбирает, какой коэффициент варьировать, а внутренний l oop меняет его в зависимости от его возможных значений. Формат ввода представляет собой список списков, где каждая «строка» содержит возможные значения для одного фактора, причем первое значение является его «значением по умолчанию».
def vary_individual_factors(factors):
r = [f[0] for f in factors]
yield tuple(r)
for i, [first, *rest] in enumerate(factors):
for x in rest:
r[i] = x
yield tuple(r)
r[i] = first
Пример:
>>> factors = [
... ['a1', 'a2', 'a3', 'a4'],
... ['b1', 'b2', 'b3', 'b4'],
... ['c1', 'c2', 'c3', 'c4'],
... ['d1', 'd2', 'd3', 'd4']
... ]
...
>>> for t in vary_individual_factors(factors):
... print(t)
...
('a1', 'b1', 'c1', 'd1')
('a2', 'b1', 'c1', 'd1')
('a3', 'b1', 'c1', 'd1')
('a4', 'b1', 'c1', 'd1')
('a1', 'b2', 'c1', 'd1')
('a1', 'b3', 'c1', 'd1')
('a1', 'b4', 'c1', 'd1')
('a1', 'b1', 'c2', 'd1')
('a1', 'b1', 'c3', 'd1')
('a1', 'b1', 'c4', 'd1')
('a1', 'b1', 'c1', 'd2')
('a1', 'b1', 'c1', 'd3')
('a1', 'b1', 'c1', 'd4')