@@ -1937,24 +1937,25 @@ def _setitem_single_column(self, loc: int, value, plane_indexer):
19371937 pi = plane_indexer
19381938
19391939 ser = self .obj ._ixs (loc , axis = 1 )
1940+ orig_values = ser ._values
19401941
19411942 # perform the equivalent of a setitem on the info axis
19421943 # as we have a null slice or a slice with full bounds
19431944 # which means essentially reassign to the columns of a
19441945 # multi-dim object
19451946 # GH#6149 (null slice), GH#10408 (full bounds)
19461947 if com .is_null_slice (pi ) or com .is_full_slice (pi , len (self .obj )):
1947- ser = value
1948+ pass
19481949 elif (
19491950 is_array_like (value )
19501951 and is_exact_shape_match (ser , value )
19511952 and not is_empty_indexer (pi )
19521953 ):
19531954 if is_list_like (pi ):
1954- ser = value [np .argsort (pi )]
1955+ value = value [np .argsort (pi )]
19551956 else :
19561957 # in case of slice
1957- ser = value [pi ]
1958+ value = value [pi ]
19581959 else :
19591960 # set the item, first attempting to operate inplace, then
19601961 # falling back to casting if necessary; see
@@ -1970,8 +1971,40 @@ def _setitem_single_column(self, loc: int, value, plane_indexer):
19701971 self .obj ._iset_item (loc , ser )
19711972 return
19721973
1973- # reset the sliced object if unique
1974- self .obj ._iset_item (loc , ser )
1974+ # We will not operate in-place, but will attempt to in the future.
1975+ # To determine whether we need to issue a FutureWarning, see if the
1976+ # setting in-place would work, i.e. behavior will change.
1977+ warn = can_hold_element (ser ._values , value )
1978+ # Don't issue the warning yet, as we can still trim a few cases where
1979+ # behavior will not change.
1980+
1981+ self .obj ._iset_item (loc , value )
1982+
1983+ if warn :
1984+ new_values = self .obj ._ixs (loc , axis = 1 )._values
1985+
1986+ if (
1987+ isinstance (new_values , np .ndarray )
1988+ and isinstance (orig_values , np .ndarray )
1989+ and np .shares_memory (new_values , orig_values )
1990+ ):
1991+ # TODO: get something like tm.shares_memory working?
1992+ # The values were set inplace after all, no need to warn,
1993+ # e.g. test_rename_nocopy
1994+ pass
1995+ else :
1996+ warnings .warn (
1997+ "In a future version, `df.iloc[:, i] = newvals` will attempt "
1998+ "to set the values inplace instead of always setting a new "
1999+ "array. To retain the old behavior, use either "
2000+ "`df[df.columns[i]] = newvals` or, if columns are non-unique, "
2001+ "`df.isetitem(i, newvals)`" ,
2002+ FutureWarning ,
2003+ stacklevel = find_stack_level (),
2004+ )
2005+ # TODO: how to get future behavior?
2006+ # TODO: what if we got here indirectly via loc?
2007+ return
19752008
19762009 def _setitem_single_block (self , indexer , value , name : str ):
19772010 """
@@ -1981,7 +2014,6 @@ def _setitem_single_block(self, indexer, value, name: str):
19812014
19822015 info_axis = self .obj ._info_axis_number
19832016 item_labels = self .obj ._get_axis (info_axis )
1984-
19852017 if isinstance (indexer , tuple ):
19862018
19872019 # if we are setting on the info axis ONLY
@@ -1996,7 +2028,9 @@ def _setitem_single_block(self, indexer, value, name: str):
19962028 if len (item_labels .get_indexer_for ([col ])) == 1 :
19972029 # e.g. test_loc_setitem_empty_append_expands_rows
19982030 loc = item_labels .get_loc (col )
1999- self .obj ._iset_item (loc , value )
2031+ # Go through _setitem_single_column to get
2032+ # FutureWarning if relevant.
2033+ self ._setitem_single_column (loc , value , indexer [0 ])
20002034 return
20012035
20022036 indexer = maybe_convert_ix (* indexer ) # e.g. test_setitem_frame_align
0 commit comments