вам не нужно повторять, replace заменит первое вхождение строки:
умное решение состоит в том, чтобы разделить строку, которую вы ищете, а затем заархивировать список со списком замен длина такая же, а затем объединение
list1 = my_str.split('?')
params = ['temp_table', 'destination_table']
zipped = zip(list1, params)
replaced = ''.join([elt for sublist in zipped for elt in sublist])
In [19]: replaced
Out[19]: 'Take the source data from temp_table and pass to destination_table'
Вы можете использовать строки из нескольких символов, что убьет ваш метод:
my_str = "Take the source data from magicword and pass to magicword;
list1 = my_str.split('magicword')
params = ['temp_table', 'destination_table']
zipped = zip(list1, params)
replaced = ''.join([elt for sublist in zipped for elt in sublist])
In [25]: replaced
Out[25]: 'Take the source data from temp_table and pass to destination_table'
Обратите внимание, что если ваши параметры короче, чем количество вхождения вашей строки поиска, это обрежет ее
IN []my_str = "Take the source data from ? and pass to ?; then do again with ? and to ?"
Out[22]: 'Take the source data from temp_table and pass to destination_table'
Также обратите внимание, что последний бит после поиска строки удаляется :(, что-то вроде
replaced = ''.join([elt for sublist in zipped for elt in sublist] + [list1[-1]])
Подойдет