def _putmask_smart(v, m, n):
<EOL>if not is_list_like(n):<EOL><INDENT>n = np.repeat(n, len(m))<EOL><DEDENT>elif isinstance(n, np.ndarray) and n.ndim == <NUM_LIT:0>:  <EOL><INDENT>n = np.repeat(np.array(n, ndmin=<NUM_LIT:1>), len(m))<EOL><DEDENT>try:<EOL><INDENT>nn = n[m]<EOL>if not _isna_compat(v, nn[<NUM_LIT:0>]):<EOL><INDENT>raise ValueError<EOL><DEDENT>with warnings.catch_warnings(record=True):<EOL><INDENT>warnings.simplefilter("<STR_LIT:ignore>", np.ComplexWarning)<EOL>nn_at = nn.astype(v.dtype)<EOL><DEDENT>if (not is_numeric_v_string_like(nn, nn_at) and<EOL>(is_float_dtype(nn.dtype) or<EOL>is_integer_dtype(nn.dtype) and<EOL>is_float_dtype(nn_at.dtype) or<EOL>is_integer_dtype(nn_at.dtype))):<EOL><INDENT>comp = (nn == nn_at)<EOL>if is_list_like(comp) and comp.all():<EOL><INDENT>nv = v.copy()<EOL>nv[m] = nn_at<EOL>return nv<EOL><DEDENT><DEDENT><DEDENT>except (ValueError, IndexError, TypeError, OverflowError):<EOL><INDENT>pass<EOL><DEDENT>n = np.asarray(n)<EOL>def _putmask_preserve(nv, n):<EOL><INDENT>try:<EOL><INDENT>nv[m] = n[m]<EOL><DEDENT>except (IndexError, ValueError):<EOL><INDENT>nv[m] = n<EOL><DEDENT>return nv<EOL><DEDENT>if v.dtype.kind == n.dtype.kind:<EOL><INDENT>return _putmask_preserve(v, n)<EOL><DEDENT>dtype, _ = maybe_promote(n.dtype)<EOL>if is_extension_type(v.dtype) and is_object_dtype(dtype):<EOL><INDENT>v = v.get_values(dtype)<EOL><DEDENT>else:<EOL><INDENT>v = v.astype(dtype)<EOL><DEDENT>return _putmask_preserve(v, n)<EOL>
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