<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def transform(data, channels, transform_fxn, def_channels = None):
 """ Apply some transformation function to flow cytometry data. This function is a template transformation function, intended to be used by other specific transformation functions. It performs basic checks on `channels` and `data`. It then applies `transform_fxn` to the specified channels. Finally, it rescales ``data.range`` and if necessary. Parameters data : FCSData or numpy array NxD flow cytometry data where N is the number of events and D is the number of parameters (aka channels). channels : int, str, list of int, list of str, optional Channels on which to perform the transformation. If `channels` is None, use def_channels. transform_fxn : function Function that performs the actual transformation. def_channels : int, str, list of int, list of str, optional Default set of channels in which to perform the transformation. If `def_channels` is None, use all channels. Returns ------- data_t : FCSData or numpy array NxD transformed flow cytometry data. """

    # Copy data array
    data_t = data.copy().astype(np.float64)

    # Default
    if channels is None:
        if def_channels is None:
            channels = range(data_t.shape[1])
        else:
            channels = def_channels

    # Convert channels to iterable
    if not (hasattr(channels, '__iter__') \
            and not isinstance(channels, six.string_types)):
        channels = [channels]

    # Apply transformation
    data_t[:,channels] = transform_fxn(data_t[:,channels])

    # Apply transformation to ``data.range``
    if hasattr(data_t, '_range'):
        for channel in channels:
            # Transform channel name to index if necessary
            channel_idx = data_t._name_to_index(channel)
            if data_t._range[channel_idx] is not None:
                data_t._range[channel_idx] = \
                    transform_fxn(data_t._range[channel_idx])

    return data_t