<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _read_df(f,nrows,names,converters,defaults=None):
 """ a private method to read part of an open file into a pandas.DataFrame. Parameters f : file object nrows : int number of rows to read names : list names to set the columns of the dataframe with converters : dict dictionary of lambda functions to convert strings to numerical format defaults : dict dictionary of default values to assign columns. Default is None Returns ------- pandas.DataFrame : pandas.DataFrame """

        seek_point = f.tell()
        line = f.readline()
        raw = line.strip().split()
        if raw[0].lower() == "external":
            filename = raw[1]
            assert os.path.exists(filename),"Pst._read_df() error: external file '{0}' not found".format(filename)
            df = pd.read_csv(filename,index_col=False,comment='#')
            df.columns = df.columns.str.lower()
            for name in names:
                assert name in df.columns,"Pst._read_df() error: name" +\
                "'{0}' not in external file '{1}' columns".format(name,filename)
                if name in converters:
                    df.loc[:,name] = df.loc[:,name].apply(converters[name])
            if defaults is not None:
                for name in names:
                    df.loc[:, name] = df.loc[:, name].fillna(defaults[name])
        else:
            if nrows is None:
                raise Exception("Pst._read_df() error: non-external sections require nrows")
            f.seek(seek_point)
            df = pd.read_csv(f, header=None,names=names,
                             nrows=nrows,delim_whitespace=True,
                             converters=converters, index_col=False,
                             comment='#')

            # in case there was some extra junk at the end of the lines
            if df.shape[1] > len(names):
                df = df.iloc[:,len(names)]
                df.columns = names
            isnull = pd.isnull(df)
            if defaults is not None:
                for name in names:
                    df.loc[:,name] = df.loc[:,name].fillna(defaults[name])

            elif np.any(pd.isnull(df).values.flatten()):
                raise Exception("NANs found")
            f.seek(seek_point)
            extras = []
            for i in range(nrows):
                line = f.readline()
                extra = np.NaN
                if '#' in line:
                    raw = line.strip().split('#')
                    extra = ' # '.join(raw[1:])
                extras.append(extra)

            df.loc[:,"extra"] = extras

        return df