9
9
10
10
import numpy as np
11
11
12
- from pandas ._libs import Timedelta , Timestamp , lib , ops as libops
12
+ from pandas ._libs import Timedelta , Timestamp , lib
13
13
from pandas .errors import NullFrequencyError
14
14
from pandas .util ._decorators import Appender
15
15
16
- from pandas .core .dtypes .cast import construct_1d_object_array_from_listlike
17
16
from pandas .core .dtypes .common import (
18
- ensure_object ,
19
- is_bool_dtype ,
20
17
is_datetime64_dtype ,
21
18
is_extension_array_dtype ,
22
19
is_integer_dtype ,
27
24
)
28
25
from pandas .core .dtypes .generic import (
29
26
ABCDataFrame ,
30
- ABCDatetimeArray ,
31
- ABCDatetimeIndex ,
32
27
ABCExtensionArray ,
33
28
ABCIndexClass ,
34
29
ABCSeries ,
35
- ABCTimedeltaArray ,
36
- ABCTimedeltaIndex ,
37
30
)
38
31
from pandas .core .dtypes .missing import isna , notna
39
32
40
33
from pandas ._typing import ArrayLike
41
34
from pandas .core .construction import array , extract_array
42
35
from pandas .core .ops .array_ops import (
43
- comp_method_OBJECT_ARRAY ,
36
+ arithmetic_op ,
37
+ comparison_op ,
44
38
define_na_arithmetic_op ,
45
- na_arithmetic_op ,
39
+ logical_op ,
46
40
)
41
+ from pandas .core .ops .array_ops import comp_method_OBJECT_ARRAY # noqa:F401
47
42
from pandas .core .ops .docstrings import (
48
43
_arith_doc_FRAME ,
49
44
_flex_comp_doc_FRAME ,
50
45
_make_flex_doc ,
51
46
_op_descriptions ,
52
47
)
53
- from pandas .core .ops .invalid import invalid_comparison
48
+ from pandas .core .ops .invalid import invalid_comparison # noqa:F401
54
49
from pandas .core .ops .methods import ( # noqa:F401
55
50
add_flex_arithmetic_methods ,
56
51
add_special_arithmetic_methods ,
@@ -643,30 +638,8 @@ def wrapper(left, right):
643
638
left , right = _align_method_SERIES (left , right )
644
639
res_name = get_op_result_name (left , right )
645
640
646
- keep_null_freq = isinstance (
647
- right ,
648
- (
649
- ABCDatetimeIndex ,
650
- ABCDatetimeArray ,
651
- ABCTimedeltaIndex ,
652
- ABCTimedeltaArray ,
653
- Timestamp ,
654
- ),
655
- )
656
-
657
641
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 )
670
643
671
644
# We do not pass dtype to ensure that the Series constructor
672
645
# does inference in the case where `result` has object-dtype.
@@ -702,46 +675,10 @@ def wrapper(self, other):
702
675
if isinstance (other , ABCSeries ) and not self ._indexed_same (other ):
703
676
raise ValueError ("Can only compare identically-labeled Series objects" )
704
677
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
-
717
678
lvalues = extract_array (self , extract_numpy = True )
718
679
rvalues = extract_array (other , extract_numpy = True )
719
680
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 )
745
682
746
683
result = self ._constructor (res_values , index = self .index )
747
684
result = finalizer (result )
@@ -762,58 +699,7 @@ def _bool_method_SERIES(cls, op, special):
762
699
"""
763
700
op_name = _get_op_name (op , special )
764
701
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
-
814
702
def wrapper (self , other ):
815
- is_self_int_dtype = is_integer_dtype (self .dtype )
816
-
817
703
self , other = _align_method_SERIES (self , other , align_asobject = True )
818
704
res_name = get_op_result_name (self , other )
819
705
@@ -829,33 +715,10 @@ def wrapper(self, other):
829
715
# Defer to DataFrame implementation; fail early
830
716
return NotImplemented
831
717
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
-
837
718
lvalues = extract_array (self , extract_numpy = True )
838
719
rvalues = extract_array (other , extract_numpy = True )
839
720
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 )
859
722
result = self ._constructor (res_values , index = self .index , name = res_name )
860
723
return finalizer (result )
861
724
0 commit comments