99
1010import numpy as np
1111
12- from pandas ._libs import Timedelta , Timestamp , lib , ops as libops
12+ from pandas ._libs import Timedelta , Timestamp , lib
1313from pandas .errors import NullFrequencyError
1414from pandas .util ._decorators import Appender
1515
16- from pandas .core .dtypes .cast import construct_1d_object_array_from_listlike
1716from pandas .core .dtypes .common import (
18- ensure_object ,
19- is_bool_dtype ,
2017 is_datetime64_dtype ,
2118 is_extension_array_dtype ,
2219 is_integer_dtype ,
2724)
2825from pandas .core .dtypes .generic import (
2926 ABCDataFrame ,
30- ABCDatetimeArray ,
31- ABCDatetimeIndex ,
3227 ABCExtensionArray ,
3328 ABCIndexClass ,
3429 ABCSeries ,
35- ABCTimedeltaArray ,
36- ABCTimedeltaIndex ,
3730)
3831from pandas .core .dtypes .missing import isna , notna
3932
4033from pandas ._typing import ArrayLike
4134from pandas .core .construction import array , extract_array
4235from pandas .core .ops .array_ops import (
43- comp_method_OBJECT_ARRAY ,
36+ arithmetic_op ,
37+ comparison_op ,
4438 define_na_arithmetic_op ,
45- na_arithmetic_op ,
39+ logical_op ,
4640)
41+ from pandas .core .ops .array_ops import comp_method_OBJECT_ARRAY # noqa:F401
4742from pandas .core .ops .docstrings import (
4843 _arith_doc_FRAME ,
4944 _flex_comp_doc_FRAME ,
5045 _make_flex_doc ,
5146 _op_descriptions ,
5247)
53- from pandas .core .ops .invalid import invalid_comparison
48+ from pandas .core .ops .invalid import invalid_comparison # noqa:F401
5449from pandas .core .ops .methods import ( # noqa:F401
5550 add_flex_arithmetic_methods ,
5651 add_special_arithmetic_methods ,
@@ -643,30 +638,8 @@ def wrapper(left, right):
643638 left , right = _align_method_SERIES (left , right )
644639 res_name = get_op_result_name (left , right )
645640
646- keep_null_freq = isinstance (
647- right ,
648- (
649- ABCDatetimeIndex ,
650- ABCDatetimeArray ,
651- ABCTimedeltaIndex ,
652- ABCTimedeltaArray ,
653- Timestamp ,
654- ),
655- )
656-
657641 lvalues = extract_array (left , extract_numpy = True )
658- rvalues = extract_array (right , extract_numpy = True )
659-
660- rvalues = maybe_upcast_for_op (rvalues , lvalues .shape )
661-
662- if should_extension_dispatch (left , rvalues ) or isinstance (
663- rvalues , (ABCTimedeltaArray , ABCDatetimeArray , Timestamp )
664- ):
665- result = dispatch_to_extension_op (op , lvalues , rvalues , keep_null_freq )
666-
667- else :
668- with np .errstate (all = "ignore" ):
669- result = na_arithmetic_op (lvalues , rvalues , op , str_rep , eval_kwargs )
642+ result = arithmetic_op (lvalues , right , op , str_rep , eval_kwargs )
670643
671644 # We do not pass dtype to ensure that the Series constructor
672645 # does inference in the case where `result` has object-dtype.
@@ -702,46 +675,10 @@ def wrapper(self, other):
702675 if isinstance (other , ABCSeries ) and not self ._indexed_same (other ):
703676 raise ValueError ("Can only compare identically-labeled Series objects" )
704677
705- other = lib .item_from_zerodim (other )
706- if isinstance (other , list ):
707- # TODO: same for tuples?
708- other = np .asarray (other )
709-
710- if isinstance (other , (np .ndarray , ABCExtensionArray , ABCIndexClass )):
711- # TODO: make this treatment consistent across ops and classes.
712- # We are not catching all listlikes here (e.g. frozenset, tuple)
713- # The ambiguous case is object-dtype. See GH#27803
714- if len (self ) != len (other ):
715- raise ValueError ("Lengths must match to compare" )
716-
717678 lvalues = extract_array (self , extract_numpy = True )
718679 rvalues = extract_array (other , extract_numpy = True )
719680
720- if should_extension_dispatch (lvalues , rvalues ):
721- res_values = dispatch_to_extension_op (op , lvalues , rvalues )
722-
723- elif is_scalar (rvalues ) and isna (rvalues ):
724- # numpy does not like comparisons vs None
725- if op is operator .ne :
726- res_values = np .ones (len (lvalues ), dtype = bool )
727- else :
728- res_values = np .zeros (len (lvalues ), dtype = bool )
729-
730- elif is_object_dtype (lvalues .dtype ):
731- res_values = comp_method_OBJECT_ARRAY (op , lvalues , rvalues )
732-
733- else :
734- op_name = "__{op}__" .format (op = op .__name__ )
735- method = getattr (lvalues , op_name )
736- with np .errstate (all = "ignore" ):
737- res_values = method (rvalues )
738-
739- if res_values is NotImplemented :
740- res_values = invalid_comparison (lvalues , rvalues , op )
741- if is_scalar (res_values ):
742- raise TypeError (
743- "Could not compare {typ} type with Series" .format (typ = type (rvalues ))
744- )
681+ res_values = comparison_op (lvalues , rvalues , op )
745682
746683 result = self ._constructor (res_values , index = self .index )
747684 result = finalizer (result )
@@ -762,58 +699,7 @@ def _bool_method_SERIES(cls, op, special):
762699 """
763700 op_name = _get_op_name (op , special )
764701
765- def na_op (x , y ):
766- try :
767- result = op (x , y )
768- except TypeError :
769- assert not isinstance (y , (list , ABCSeries , ABCIndexClass ))
770- if isinstance (y , np .ndarray ):
771- # bool-bool dtype operations should be OK, should not get here
772- assert not (is_bool_dtype (x .dtype ) and is_bool_dtype (y .dtype ))
773- x = ensure_object (x )
774- y = ensure_object (y )
775- result = libops .vec_binop (x , y , op )
776- else :
777- # let null fall thru
778- assert lib .is_scalar (y )
779- if not isna (y ):
780- y = bool (y )
781- try :
782- result = libops .scalar_binop (x , y , op )
783- except (
784- TypeError ,
785- ValueError ,
786- AttributeError ,
787- OverflowError ,
788- NotImplementedError ,
789- ):
790- raise TypeError (
791- "cannot compare a dtyped [{dtype}] array "
792- "with a scalar of type [{typ}]" .format (
793- dtype = x .dtype , typ = type (y ).__name__
794- )
795- )
796-
797- return result
798-
799- fill_int = lambda x : x
800-
801- def fill_bool (x , left = None ):
802- # if `left` is specifically not-boolean, we do not cast to bool
803- if x .dtype .kind in ["c" , "f" , "O" ]:
804- # dtypes that can hold NA
805- mask = isna (x )
806- if mask .any ():
807- x = x .astype (object )
808- x [mask ] = False
809-
810- if left is None or is_bool_dtype (left .dtype ):
811- x = x .astype (bool )
812- return x
813-
814702 def wrapper (self , other ):
815- is_self_int_dtype = is_integer_dtype (self .dtype )
816-
817703 self , other = _align_method_SERIES (self , other , align_asobject = True )
818704 res_name = get_op_result_name (self , other )
819705
@@ -829,33 +715,10 @@ def wrapper(self, other):
829715 # Defer to DataFrame implementation; fail early
830716 return NotImplemented
831717
832- other = lib .item_from_zerodim (other )
833- if is_list_like (other ) and not hasattr (other , "dtype" ):
834- # e.g. list, tuple
835- other = construct_1d_object_array_from_listlike (other )
836-
837718 lvalues = extract_array (self , extract_numpy = True )
838719 rvalues = extract_array (other , extract_numpy = True )
839720
840- if should_extension_dispatch (self , rvalues ):
841- res_values = dispatch_to_extension_op (op , lvalues , rvalues )
842-
843- else :
844- if isinstance (rvalues , (ABCSeries , ABCIndexClass , np .ndarray )):
845- is_other_int_dtype = is_integer_dtype (rvalues .dtype )
846- rvalues = rvalues if is_other_int_dtype else fill_bool (rvalues , lvalues )
847-
848- else :
849- # i.e. scalar
850- is_other_int_dtype = lib .is_integer (rvalues )
851-
852- # For int vs int `^`, `|`, `&` are bitwise operators and return
853- # integer dtypes. Otherwise these are boolean ops
854- filler = fill_int if is_self_int_dtype and is_other_int_dtype else fill_bool
855-
856- res_values = na_op (lvalues , rvalues )
857- res_values = filler (res_values )
858-
721+ res_values = logical_op (lvalues , rvalues , op )
859722 result = self ._constructor (res_values , index = self .index , name = res_name )
860723 return finalizer (result )
861724
0 commit comments