import functools
import sys

def file_reader(func):
    @functools.wraps(func)
    def helper(file, *args, **kwargs):
        return File(file, func, *args, **kwargs)
    return helper


class File(object):

    def __init__(self, file, func, *args, **kwargs):
        self.close_file = kwargs.pop('close', True)
        # accept either filename or file-like object
        self.file = file if hasattr(file, 'read') else open(file)

        try:
            # func is responsible for self.file if it doesn't return it
            self.file = func(self.file, *args, **kwargs)
        except:  # clean up on any error
            self.__exit__(*sys.exc_info())
            raise

    # context manager support
    def __enter__(self):
        return self

    def __exit__(self, *args, **kwargs):
        if not self.close_file:
            return  # do nothing
        # clean up
        exit = getattr(self.file, '__exit__', None)
        if exit is not None:
            return exit(*args, **kwargs)
        else:
            exit = getattr(self.file, 'close', None)
            if exit is not None:
                exit()

    # iterator support
    def __iter__(self):
        return self

    def __next__(self):
        return next(self.file)

    next = __next__  # Python 2 support

    # delegate everything else to file object
    def __getattr__(self, attr):
        return getattr(self.file, attr)


@file_reader
def f(file):
    print(repr(file.read(10)))
    return file

file = f('prog.py')  # use as ordinary function
print(repr(file.read(20)))
file.seek(0)
for line in file:
    print(repr(line))
    break
file.close()  # need to close explicitly

with f('prog.py') as file:  # use as a context manager
    print(repr(file.read(20)))