One option would be to pass the docstring into the decorator. That way you would still have a docstring by the function definition for reading source code but if you were to change or remove the decorator you wouldn't end up with an incorrect docstring.
For example:
@file_aware(docstring="Do stuff. `f` can be file object or file name", mode="r")
def function(f, *args, **kwargs):
for line in f:
....
Your file_aware
decorator might then look something like this:
def file_aware(docstring, mode):
def deco(func):
@functools.wraps(func)
def wrapped(f, *args, **kwargs):
if isinstance(f, str):
file_obj = open(f, mode)
else:
file_obj = f
return func(file_obj, *args, **kwargs)
wrapped.__doc__ = docstring
return wrapped
return deco