human
Complete this python program:
def _putmask_smart(v, m, n):
assistant
#Here is the Python program you requested.

    """Return a new ndarray, try to preserve dtype if possible.
    Parameters
    v : `values`, updated in-place (array like)
    m : `mask`, applies to both sides (array like)
    n : `new values` either scalar or an array like aligned with `values`
    Returns
    values : ndarray with updated values
    this *may* be a copy of the original
    See Also
    ndarray.putmask
    """
    if (not is_list_like(n)):
        n = np.repeat(n, len(m))
    elif (isinstance(n, np.ndarray) and (n.ndim == 0)):
        n = np.repeat(np.array(n, ndmin=1), len(m))
    try:
        nn = n[m]
        if (not _isna_compat(v, nn[0])):
            raise ValueError
        with catch_warnings(record=True):
            nn_at = nn.astype(v.dtype)
        if ((not is_numeric_v_string_like(nn, nn_at)) and (is_float_dtype(nn.dtype) or (is_integer_dtype(nn.dtype) and is_float_dtype(nn_at.dtype)) or is_integer_dtype(nn_at.dtype))):
            comp = (nn == nn_at)
            if (is_list_like(comp) and comp.all()):
                nv = v.copy()
                nv[m] = nn_at
                return nv
    except (ValueError, IndexError, TypeError):
        pass
    n = np.asarray(n)
    def _putmask_preserve(nv, n):
        try:
            nv[m] = n[m]
        except (IndexError, ValueError):
            nv[m] = n
        return nv
    if (v.dtype.kind == n.dtype.kind):
        return _putmask_preserve(v, n)
    (dtype, _) = maybe_promote(n.dtype)
    if (is_extension_type(v.dtype) and is_object_dtype(dtype)):
        v = v.get_values(dtype)
    else:
        v = v.astype(dtype)
    return _putmask_preserve(v, n)