Use a regular expression:
In [16]: re.sub(r'(?: |^)(abc),',r'!+\1+!,', s, flags=re.I)
Out[16]: '!+abc+!,!+Abc+!,!+aBc+!, abc-def, abca'
The patter (?: |^)(abc), will match every abc that proceeds by a space or the start of the string (^) and followed by a comma and replaces it with the first captured group surrounded with your expected characters. Note that :? in the first group makes it a non-captured group so the \1 will refer to abc. Also we are using re.I flag which is the ignore case flag.
If you also want to keep the spaces just use a captured-group for the first group:
In [19]: re.sub(r'( |^)(abc),',r'\1!+\2+!,', s, flags=re.I)
Out[19]: '!+abc+!, !+Abc+!, !+aBc+!, abc-def, abca'
Also note that if you want to pass multiple regex as the replacing pattern you can compile the first regex using re.compile() and pass the other patterns within a loop:
my_regex = re.compile(r'( |^)(abc),')
my_new_result = [my_regex.sub(pattern, s, flags=re.I) for pattern in list_of_patterns]
As a more flexible way to deal with re.sub you can also pass a function as the replacer, and so more operations on your captured strings. For example if you want to lower case the matched strings:
s = "abc, Abc, aBc (abc) abc abc <abc> abc-def, abca"
In [31]: re.sub(r'(^|\W)(abc)($|\W)', lambda x: '{}!+{}+!{}'.format(*x.groups()).lower() if x.group(3) != '-' else x.group(0), s, flags=re.I)
Out[31]: '!+abc+!, !+abc+!, !+abc+! (!+abc+!) !+abc+! abc <!+abc+!> abc-def, abca'