Можно например сформировать все варианты таких подстановок и сравнивать с ними.
from itertools import product
zav = {'a': ['а', '@', 'A'], 'b': ['b', 'б'], 'ч': ['4'], 'и': ['u'], 'к': ['k']}
bad_word = "пончик"
# список всех возможных вариантов подстановки
bad_words = [''.join(word) for word in product(*[[x]+zav.get(x, []) for x in bad_word])]
print(bad_words)
# ['пончик', 'пончиk', 'пончuк', 'пончuk', 'пон4ик', 'пон4иk', 'пон4uк', 'пон4uk']
Другой вариант вижу в использовании regexp, примерно похожим образом из bad_word "пончик" и нашего словаря формируем универсальный шаблон "(п)(о)(н)(ч|4)(и|u)(к|k)" под который попадут все варианты.