|
41 | 41 | ABCIndex,
|
42 | 42 | ABCIndexClass,
|
43 | 43 | ABCSeries,
|
44 |
| - ABCSparseArray, |
45 | 44 | ABCSparseSeries,
|
46 | 45 | )
|
47 | 46 | from pandas.core.dtypes.missing import isna, notna
|
|
57 | 56 | _op_descriptions,
|
58 | 57 | )
|
59 | 58 | from pandas.core.ops.invalid import invalid_comparison
|
| 59 | +from pandas.core.ops.methods import ( # noqa:F401 |
| 60 | + add_flex_arithmetic_methods, |
| 61 | + add_special_arithmetic_methods, |
| 62 | +) |
60 | 63 | from pandas.core.ops.roperator import ( # noqa:F401
|
61 | 64 | radd,
|
62 | 65 | rand_,
|
@@ -587,224 +590,6 @@ def dispatch_to_extension_op(op, left, right):
|
587 | 590 | return res_values
|
588 | 591 |
|
589 | 592 |
|
590 |
| -# ----------------------------------------------------------------------------- |
591 |
| -# Functions that add arithmetic methods to objects, given arithmetic factory |
592 |
| -# methods |
593 |
| - |
594 |
| - |
595 |
| -def _get_method_wrappers(cls): |
596 |
| - """ |
597 |
| - Find the appropriate operation-wrappers to use when defining flex/special |
598 |
| - arithmetic, boolean, and comparison operations with the given class. |
599 |
| -
|
600 |
| - Parameters |
601 |
| - ---------- |
602 |
| - cls : class |
603 |
| -
|
604 |
| - Returns |
605 |
| - ------- |
606 |
| - arith_flex : function or None |
607 |
| - comp_flex : function or None |
608 |
| - arith_special : function |
609 |
| - comp_special : function |
610 |
| - bool_special : function |
611 |
| -
|
612 |
| - Notes |
613 |
| - ----- |
614 |
| - None is only returned for SparseArray |
615 |
| - """ |
616 |
| - if issubclass(cls, ABCSparseSeries): |
617 |
| - # Be sure to catch this before ABCSeries and ABCSparseArray, |
618 |
| - # as they will both come see SparseSeries as a subclass |
619 |
| - arith_flex = _flex_method_SERIES |
620 |
| - comp_flex = _flex_method_SERIES |
621 |
| - arith_special = _arith_method_SPARSE_SERIES |
622 |
| - comp_special = _arith_method_SPARSE_SERIES |
623 |
| - bool_special = _bool_method_SERIES |
624 |
| - # TODO: I don't think the functions defined by bool_method are tested |
625 |
| - elif issubclass(cls, ABCSeries): |
626 |
| - # Just Series; SparseSeries is caught above |
627 |
| - arith_flex = _flex_method_SERIES |
628 |
| - comp_flex = _flex_method_SERIES |
629 |
| - arith_special = _arith_method_SERIES |
630 |
| - comp_special = _comp_method_SERIES |
631 |
| - bool_special = _bool_method_SERIES |
632 |
| - elif issubclass(cls, ABCDataFrame): |
633 |
| - # Same for DataFrame and SparseDataFrame |
634 |
| - arith_flex = _arith_method_FRAME |
635 |
| - comp_flex = _flex_comp_method_FRAME |
636 |
| - arith_special = _arith_method_FRAME |
637 |
| - comp_special = _comp_method_FRAME |
638 |
| - bool_special = _arith_method_FRAME |
639 |
| - return arith_flex, comp_flex, arith_special, comp_special, bool_special |
640 |
| - |
641 |
| - |
642 |
| -def _create_methods(cls, arith_method, comp_method, bool_method, special): |
643 |
| - # creates actual methods based upon arithmetic, comp and bool method |
644 |
| - # constructors. |
645 |
| - |
646 |
| - have_divmod = issubclass(cls, ABCSeries) |
647 |
| - # divmod is available for Series and SparseSeries |
648 |
| - |
649 |
| - # yapf: disable |
650 |
| - new_methods = dict( |
651 |
| - add=arith_method(cls, operator.add, special), |
652 |
| - radd=arith_method(cls, radd, special), |
653 |
| - sub=arith_method(cls, operator.sub, special), |
654 |
| - mul=arith_method(cls, operator.mul, special), |
655 |
| - truediv=arith_method(cls, operator.truediv, special), |
656 |
| - floordiv=arith_method(cls, operator.floordiv, special), |
657 |
| - # Causes a floating point exception in the tests when numexpr enabled, |
658 |
| - # so for now no speedup |
659 |
| - mod=arith_method(cls, operator.mod, special), |
660 |
| - pow=arith_method(cls, operator.pow, special), |
661 |
| - # not entirely sure why this is necessary, but previously was included |
662 |
| - # so it's here to maintain compatibility |
663 |
| - rmul=arith_method(cls, rmul, special), |
664 |
| - rsub=arith_method(cls, rsub, special), |
665 |
| - rtruediv=arith_method(cls, rtruediv, special), |
666 |
| - rfloordiv=arith_method(cls, rfloordiv, special), |
667 |
| - rpow=arith_method(cls, rpow, special), |
668 |
| - rmod=arith_method(cls, rmod, special)) |
669 |
| - # yapf: enable |
670 |
| - new_methods["div"] = new_methods["truediv"] |
671 |
| - new_methods["rdiv"] = new_methods["rtruediv"] |
672 |
| - if have_divmod: |
673 |
| - # divmod doesn't have an op that is supported by numexpr |
674 |
| - new_methods["divmod"] = arith_method(cls, divmod, special) |
675 |
| - new_methods["rdivmod"] = arith_method(cls, rdivmod, special) |
676 |
| - |
677 |
| - new_methods.update( |
678 |
| - dict( |
679 |
| - eq=comp_method(cls, operator.eq, special), |
680 |
| - ne=comp_method(cls, operator.ne, special), |
681 |
| - lt=comp_method(cls, operator.lt, special), |
682 |
| - gt=comp_method(cls, operator.gt, special), |
683 |
| - le=comp_method(cls, operator.le, special), |
684 |
| - ge=comp_method(cls, operator.ge, special), |
685 |
| - ) |
686 |
| - ) |
687 |
| - |
688 |
| - if bool_method: |
689 |
| - new_methods.update( |
690 |
| - dict( |
691 |
| - and_=bool_method(cls, operator.and_, special), |
692 |
| - or_=bool_method(cls, operator.or_, special), |
693 |
| - # For some reason ``^`` wasn't used in original. |
694 |
| - xor=bool_method(cls, operator.xor, special), |
695 |
| - rand_=bool_method(cls, rand_, special), |
696 |
| - ror_=bool_method(cls, ror_, special), |
697 |
| - rxor=bool_method(cls, rxor, special), |
698 |
| - ) |
699 |
| - ) |
700 |
| - |
701 |
| - if special: |
702 |
| - dunderize = lambda x: "__{name}__".format(name=x.strip("_")) |
703 |
| - else: |
704 |
| - dunderize = lambda x: x |
705 |
| - new_methods = {dunderize(k): v for k, v in new_methods.items()} |
706 |
| - return new_methods |
707 |
| - |
708 |
| - |
709 |
| -def add_methods(cls, new_methods): |
710 |
| - for name, method in new_methods.items(): |
711 |
| - # For most methods, if we find that the class already has a method |
712 |
| - # of the same name, it is OK to over-write it. The exception is |
713 |
| - # inplace methods (__iadd__, __isub__, ...) for SparseArray, which |
714 |
| - # retain the np.ndarray versions. |
715 |
| - force = not (issubclass(cls, ABCSparseArray) and name.startswith("__i")) |
716 |
| - if force or name not in cls.__dict__: |
717 |
| - setattr(cls, name, method) |
718 |
| - |
719 |
| - |
720 |
| -# ---------------------------------------------------------------------- |
721 |
| -# Arithmetic |
722 |
| -def add_special_arithmetic_methods(cls): |
723 |
| - """ |
724 |
| - Adds the full suite of special arithmetic methods (``__add__``, |
725 |
| - ``__sub__``, etc.) to the class. |
726 |
| -
|
727 |
| - Parameters |
728 |
| - ---------- |
729 |
| - cls : class |
730 |
| - special methods will be defined and pinned to this class |
731 |
| - """ |
732 |
| - _, _, arith_method, comp_method, bool_method = _get_method_wrappers(cls) |
733 |
| - new_methods = _create_methods( |
734 |
| - cls, arith_method, comp_method, bool_method, special=True |
735 |
| - ) |
736 |
| - # inplace operators (I feel like these should get passed an `inplace=True` |
737 |
| - # or just be removed |
738 |
| - |
739 |
| - def _wrap_inplace_method(method): |
740 |
| - """ |
741 |
| - return an inplace wrapper for this method |
742 |
| - """ |
743 |
| - |
744 |
| - def f(self, other): |
745 |
| - result = method(self, other) |
746 |
| - |
747 |
| - # this makes sure that we are aligned like the input |
748 |
| - # we are updating inplace so we want to ignore is_copy |
749 |
| - self._update_inplace( |
750 |
| - result.reindex_like(self, copy=False)._data, verify_is_copy=False |
751 |
| - ) |
752 |
| - |
753 |
| - return self |
754 |
| - |
755 |
| - f.__name__ = "__i{name}__".format(name=method.__name__.strip("__")) |
756 |
| - return f |
757 |
| - |
758 |
| - new_methods.update( |
759 |
| - dict( |
760 |
| - __iadd__=_wrap_inplace_method(new_methods["__add__"]), |
761 |
| - __isub__=_wrap_inplace_method(new_methods["__sub__"]), |
762 |
| - __imul__=_wrap_inplace_method(new_methods["__mul__"]), |
763 |
| - __itruediv__=_wrap_inplace_method(new_methods["__truediv__"]), |
764 |
| - __ifloordiv__=_wrap_inplace_method(new_methods["__floordiv__"]), |
765 |
| - __imod__=_wrap_inplace_method(new_methods["__mod__"]), |
766 |
| - __ipow__=_wrap_inplace_method(new_methods["__pow__"]), |
767 |
| - ) |
768 |
| - ) |
769 |
| - |
770 |
| - new_methods.update( |
771 |
| - dict( |
772 |
| - __iand__=_wrap_inplace_method(new_methods["__and__"]), |
773 |
| - __ior__=_wrap_inplace_method(new_methods["__or__"]), |
774 |
| - __ixor__=_wrap_inplace_method(new_methods["__xor__"]), |
775 |
| - ) |
776 |
| - ) |
777 |
| - |
778 |
| - add_methods(cls, new_methods=new_methods) |
779 |
| - |
780 |
| - |
781 |
| -def add_flex_arithmetic_methods(cls): |
782 |
| - """ |
783 |
| - Adds the full suite of flex arithmetic methods (``pow``, ``mul``, ``add``) |
784 |
| - to the class. |
785 |
| -
|
786 |
| - Parameters |
787 |
| - ---------- |
788 |
| - cls : class |
789 |
| - flex methods will be defined and pinned to this class |
790 |
| - """ |
791 |
| - flex_arith_method, flex_comp_method, _, _, _ = _get_method_wrappers(cls) |
792 |
| - new_methods = _create_methods( |
793 |
| - cls, flex_arith_method, flex_comp_method, bool_method=None, special=False |
794 |
| - ) |
795 |
| - new_methods.update( |
796 |
| - dict( |
797 |
| - multiply=new_methods["mul"], |
798 |
| - subtract=new_methods["sub"], |
799 |
| - divide=new_methods["div"], |
800 |
| - ) |
801 |
| - ) |
802 |
| - # opt out of bool flex methods for now |
803 |
| - assert not any(kname in new_methods for kname in ("ror_", "rxor", "rand_")) |
804 |
| - |
805 |
| - add_methods(cls, new_methods=new_methods) |
806 |
| - |
807 |
| - |
808 | 593 | # -----------------------------------------------------------------------------
|
809 | 594 | # Series
|
810 | 595 |
|
|
0 commit comments