Drop 1 or more columns. Any column which does not exist in the DataFrame is skipped, i.e. not removed,
        without raising an exception.

        Unlike Pandas' drop, this is currently restricted to dropping columns.

        Parameters
        ----------
        columns : str or list of str
            Column name or list of column names to drop.

        Returns
        -------
        DataFrame
            A new DataFrame without these columns.

def drop(self, columns):
        """Drop 1 or more columns. Any column which does not exist in the DataFrame is skipped, i.e. not removed,
        without raising an exception.

        Unlike Pandas' drop, this is currently restricted to dropping columns.

        Parameters
        ----------
        columns : str or list of str
            Column name or list of column names to drop.

        Returns
        -------
        DataFrame
            A new DataFrame without these columns.

        """
        if isinstance(columns, str):
            new_data = OrderedDict()
            if columns not in self._gather_column_names():
                raise KeyError('Key {} not found'.format(columns))

            for column_name in self:
                if column_name != columns:
                    new_data[column_name] = self._data[column_name]

            return DataFrame(new_data, self.index)
        elif isinstance(columns, list):
            check_inner_types(columns, str)

            df = self
            for column in columns:
                df = df.drop(column)

            return df
        else:
            raise TypeError('Expected columns as a str or a list of str')