def apply(self, fn, *column_or_columns):
        """Apply ``fn`` to each element or elements of ``column_or_columns``.
        If no ``column_or_columns`` provided, `fn`` is applied to each row.

        Args:
            ``fn`` (function) -- The function to apply.
            ``column_or_columns``: Columns containing the arguments to ``fn``
                as either column labels (``str``) or column indices (``int``).
                The number of columns must match the number of arguments
                that ``fn`` expects.

        Raises:
            ``ValueError`` -- if  ``column_label`` is not an existing
                column in the table.
            ``TypeError`` -- if insufficent number of ``column_label`` passed
                to ``fn``.

        Returns:
            An array consisting of results of applying ``fn`` to elements
            specified by ``column_label`` in each row.

        >>> t = Table().with_columns(
        ...     'letter', make_array('a', 'b', 'c', 'z'),
        ...     'count',  make_array(9, 3, 3, 1),
        ...     'points', make_array(1, 2, 2, 10))
        >>> t
        letter | count | points
        a      | 9     | 1
        b      | 3     | 2
        c      | 3     | 2
        z      | 1     | 10
        >>> t.apply(lambda x: x - 1, 'points')
        array([0, 1, 1, 9])
        >>> t.apply(lambda x, y: x * y, 'count', 'points')
        array([ 9,  6,  6, 10])
        >>> t.apply(lambda x: x - 1, 'count', 'points')
        Traceback (most recent call last):
            ...
        TypeError: <lambda>() takes 1 positional argument but 2 were given
        >>> t.apply(lambda x: x - 1, 'counts')
        Traceback (most recent call last):
            ...
        ValueError: The column "counts" is not in the table. The table contains these columns: letter, count, points

        Whole rows are passed to the function if no columns are specified.

        >>> t.apply(lambda row: row[1] * 2)
        array([18,  6,  6,  2])
        """
        if not column_or_columns:
            return np.array([fn(row) for row in self.rows])
        else:
            if len(column_or_columns) == 1 and \
                    _is_non_string_iterable(column_or_columns[0]):
                warnings.warn(
                   "column lists are deprecated; pass each as an argument", FutureWarning)
                column_or_columns = column_or_columns[0]
            rows = zip(*self.select(*column_or_columns).columns)
            return np.array([fn(*row) for row in rows])
Apply ``fn`` to each element or elements of ``column_or_columns``.
        If no ``column_or_columns`` provided, `fn`` is applied to each row.

        Args:
            ``fn`` (function) -- The function to apply.
            ``column_or_columns``: Columns containing the arguments to ``fn``
                as either column labels (``str``) or column indices (``int``).
                The number of columns must match the number of arguments
                that ``fn`` expects.

        Raises:
            ``ValueError`` -- if  ``column_label`` is not an existing
                column in the table.
            ``TypeError`` -- if insufficent number of ``column_label`` passed
                to ``fn``.

        Returns:
            An array consisting of results of applying ``fn`` to elements
            specified by ``column_label`` in each row.

        >>> t = Table().with_columns(
        ...     'letter', make_array('a', 'b', 'c', 'z'),
        ...     'count',  make_array(9, 3, 3, 1),
        ...     'points', make_array(1, 2, 2, 10))
        >>> t
        letter | count | points
        a      | 9     | 1
        b      | 3     | 2
        c      | 3     | 2
        z      | 1     | 10
        >>> t.apply(lambda x: x - 1, 'points')
        array([0, 1, 1, 9])
        >>> t.apply(lambda x, y: x * y, 'count', 'points')
        array([ 9,  6,  6, 10])
        >>> t.apply(lambda x: x - 1, 'count', 'points')
        Traceback (most recent call last):
            ...
        TypeError: <lambda>() takes 1 positional argument but 2 were given
        >>> t.apply(lambda x: x - 1, 'counts')
        Traceback (most recent call last):
            ...
        ValueError: The column "counts" is not in the table. The table contains these columns: letter, count, points

        Whole rows are passed to the function if no columns are specified.

        >>> t.apply(lambda row: row[1] * 2)
        array([18,  6,  6,  2])