Skip to content

Commit 9a2f276

Browse files
jbrockmendelproost
authored andcommitted
REF: prepare Series logical op to be refactored to array op (pandas-dev#28395)
1 parent dc2d676 commit 9a2f276

File tree

1 file changed

+32
-31
lines changed

1 file changed

+32
-31
lines changed

pandas/core/ops/__init__.py

+32-31
Original file line numberDiff line numberDiff line change
@@ -787,11 +787,17 @@ def na_op(x, y):
787787

788788
return result
789789

790-
fill_int = lambda x: x.fillna(0)
790+
fill_int = lambda x: x
791791

792792
def fill_bool(x, left=None):
793793
# if `left` is specifically not-boolean, we do not cast to bool
794-
x = x.fillna(False)
794+
if x.dtype.kind in ["c", "f", "O"]:
795+
# dtypes that can hold NA
796+
mask = isna(x)
797+
if mask.any():
798+
x = x.astype(object)
799+
x[mask] = False
800+
795801
if left is None or is_bool_dtype(left.dtype):
796802
x = x.astype(bool)
797803
return x
@@ -814,40 +820,35 @@ def wrapper(self, other):
814820
# Defer to DataFrame implementation; fail early
815821
return NotImplemented
816822

817-
elif should_extension_dispatch(self, other):
818-
lvalues = extract_array(self, extract_numpy=True)
819-
rvalues = extract_array(other, extract_numpy=True)
823+
other = lib.item_from_zerodim(other)
824+
if is_list_like(other) and not hasattr(other, "dtype"):
825+
# e.g. list, tuple
826+
other = construct_1d_object_array_from_listlike(other)
827+
828+
lvalues = extract_array(self, extract_numpy=True)
829+
rvalues = extract_array(other, extract_numpy=True)
830+
831+
if should_extension_dispatch(self, rvalues):
820832
res_values = dispatch_to_extension_op(op, lvalues, rvalues)
821-
result = self._constructor(res_values, index=self.index, name=res_name)
822-
return finalizer(result)
823833

824-
elif isinstance(other, (ABCSeries, ABCIndexClass)):
825-
is_other_int_dtype = is_integer_dtype(other.dtype)
826-
other = other if is_other_int_dtype else fill_bool(other, self)
834+
else:
835+
if isinstance(rvalues, (ABCSeries, ABCIndexClass, np.ndarray)):
836+
is_other_int_dtype = is_integer_dtype(rvalues.dtype)
837+
rvalues = rvalues if is_other_int_dtype else fill_bool(rvalues, lvalues)
827838

828-
elif is_list_like(other):
829-
# list, tuple, np.ndarray
830-
if not isinstance(other, np.ndarray):
831-
other = construct_1d_object_array_from_listlike(other)
839+
else:
840+
# i.e. scalar
841+
is_other_int_dtype = lib.is_integer(rvalues)
832842

833-
is_other_int_dtype = is_integer_dtype(other.dtype)
834-
other = type(self)(other)
835-
other = other if is_other_int_dtype else fill_bool(other, self)
843+
# For int vs int `^`, `|`, `&` are bitwise operators and return
844+
# integer dtypes. Otherwise these are boolean ops
845+
filler = fill_int if is_self_int_dtype and is_other_int_dtype else fill_bool
836846

837-
else:
838-
# i.e. scalar
839-
is_other_int_dtype = lib.is_integer(other)
840-
841-
# TODO: use extract_array once we handle EA correctly, see GH#27959
842-
ovalues = lib.values_from_object(other)
843-
844-
# For int vs int `^`, `|`, `&` are bitwise operators and return
845-
# integer dtypes. Otherwise these are boolean ops
846-
filler = fill_int if is_self_int_dtype and is_other_int_dtype else fill_bool
847-
res_values = na_op(self.values, ovalues)
848-
unfilled = self._constructor(res_values, index=self.index, name=res_name)
849-
filled = filler(unfilled)
850-
return finalizer(filled)
847+
res_values = na_op(lvalues, rvalues)
848+
res_values = filler(res_values)
849+
850+
result = self._constructor(res_values, index=self.index, name=res_name)
851+
return finalizer(result)
851852

852853
wrapper.__name__ = op_name
853854
return wrapper

0 commit comments

Comments
 (0)