Skip to content

Commit c729b73

Browse files
jbrockmendeljreback
authored andcommitted
REF: separate method-pinning functions (#27811)
1 parent fae84ec commit c729b73

File tree

2 files changed

+253
-219
lines changed

2 files changed

+253
-219
lines changed

pandas/core/ops/__init__.py

+4-219
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
ABCIndex,
4242
ABCIndexClass,
4343
ABCSeries,
44-
ABCSparseArray,
4544
ABCSparseSeries,
4645
)
4746
from pandas.core.dtypes.missing import isna, notna
@@ -57,6 +56,10 @@
5756
_op_descriptions,
5857
)
5958
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+
)
6063
from pandas.core.ops.roperator import ( # noqa:F401
6164
radd,
6265
rand_,
@@ -587,224 +590,6 @@ def dispatch_to_extension_op(op, left, right):
587590
return res_values
588591

589592

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-
808593
# -----------------------------------------------------------------------------
809594
# Series
810595

0 commit comments

Comments
 (0)