itertools.combinations. Скармливаете туда range индексов вашей строки. Получаете список из 1/2/сколько надо сделать замен индексов, на эти позиции ставьте ваши Z, Y.
Вот набросок кода.
Я не питонист, возможно есть более лаконичная реализация. Особенно мерзкий хак с перобразованием строки в list, потому что строки в питоне immutable.
import itertools
def GenerateAll(source, rep):
for comb in itertools.combinations(range(len(source)), len(rep)):
s = list(source)
for (i, j) in enumerate(comb):
s[j] = rep[i];
yield "".join(s)
print(list(GenerateAll("abcd", "XY")))
# ['XYcd', 'XbYd', 'XbcY', 'aXYd', 'aXcY', 'abXY']