Я бы предпочел что-то подобное для простых случаев:
import random
animals = ["cat", "dog", "monkey", "tiger"]
def ra():
return random.choice(animals)
print(f'{ra()} fights with {ra()}. {ra()} can play with {ra()}. Sth {ra()} sth {ra()} ...')
Но это ближе к вашей отправной точке, вы можете предпочесть это:
import re
import random
animals = ["cat", "dog", "monkey", "tiger"]
template = "$animal fights with $animal. $animal can play with $animal. Sth $animal sth $animal ..."
print(re.sub(r'\$animal', lambda _: random.choice(animals), template))
Обратите внимание, что оба решения не волнует, сколько животных вы заменяете.