diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 1fff30525853d..483091c939d0c 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -213,6 +213,20 @@ are returned. (:issue:`21521`) df.groupby("a").ffill() +``__str__`` methods now call ``__repr__`` rather than vica-versa +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Pandas has until now mostly defined string representations in a Pandas objects's +``__str__``/``__unicode__``/``__bytes__`` methods, and called ``__str__`` from the ``__repr__`` +method, if a specific ``__repr__`` method is not found. This is not needed for Python3. +In Pandas 0.25, the string representations of Pandas objects are now generally +defined in ``__repr__``, and calls to ``__str__`` in general now pass the call on to +the ``__repr__``, if a specific ``__str__`` method doesn't exist, as is standard for Python. +This change is backward compatible for direct usage of Pandas, but if you subclass +Pandas objects *and* give your subclasses specific ``__str__``/``__repr__`` methods, +you may have to adjust your ``__str__``/``__repr__`` methods (:issue:`26495`). + + .. _whatsnew_0250.api_breaking.deps: Increased minimum versions for dependencies diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index d25ccd1b158be..0fa705369908a 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -2022,7 +2022,7 @@ def _get_repr(self, length=True, na_rep='NaN', footer=True): result = formatter.to_string() return str(result) - def __str__(self): + def __repr__(self): """ String representation. """ @@ -2037,10 +2037,6 @@ def __str__(self): return result - def __repr__(self): - # We want to bypass the ExtensionArray.__repr__ - return str(self) - def _maybe_coerce_indexer(self, indexer): """ return an indexer coerced to the codes dtype diff --git a/pandas/core/arrays/sparse.py b/pandas/core/arrays/sparse.py index 7a66e0ff33cc7..b0236cb393c1c 100644 --- a/pandas/core/arrays/sparse.py +++ b/pandas/core/arrays/sparse.py @@ -1831,7 +1831,7 @@ def _add_comparison_ops(cls): # ---------- # Formatting # ----------- - def __str__(self): + def __repr__(self): return '{self}\nFill: {fill}\n{index}'.format( self=printing.pprint_thing(self), fill=printing.pprint_thing(self.fill_value), diff --git a/pandas/core/base.py b/pandas/core/base.py index f7837c60c0b82..3f59871fb5b38 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -55,7 +55,7 @@ def __repr__(self): return str(self) -class PandasObject(StringMixin, DirNamesMixin): +class PandasObject(DirNamesMixin): """baseclass for various pandas objects""" @@ -64,7 +64,7 @@ def _constructor(self): """class constructor (for this class it's just `__class__`""" return self.__class__ - def __str__(self): + def __repr__(self): """ Return a string representation for a particular object. """ diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 6bfa63012689d..e619cda453e0b 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -610,7 +610,7 @@ def _info_repr(self): return info_repr_option and not (self._repr_fits_horizontal_() and self._repr_fits_vertical_()) - def __str__(self): + def __repr__(self): """ Return a string representation for a particular DataFrame. """ diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 623e2b4863029..76c73fc40977c 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2022,7 +2022,7 @@ def __setstate__(self, state): # ---------------------------------------------------------------------- # Rendering Methods - def __str__(self): + def __repr__(self): # string representation based upon iterating over self # (since, by definition, `PandasContainers` are iterable) prepr = '[%s]' % ','.join(map(pprint_thing, self)) diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index 4e9e3b4963b6d..aa04b7505afe4 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -373,8 +373,8 @@ def __init__(self, obj, keys=None, axis=0, level=None, def __len__(self): return len(self.groups) - def __str__(self): - # TODO: Better str/repr for GroupBy object + def __repr__(self): + # TODO: Better repr for GroupBy object return object.__repr__(self) def _assure_grouper(self): diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index eff7ff2c9f347..a4544e79e2dfa 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -932,7 +932,7 @@ def __deepcopy__(self, memo=None): # -------------------------------------------------------------------- # Rendering Methods - def __str__(self): + def __repr__(self): """ Return a string representation for this object. """ diff --git a/pandas/core/indexes/frozen.py b/pandas/core/indexes/frozen.py index 60e4253e3101b..aeb0fa119ab33 100644 --- a/pandas/core/indexes/frozen.py +++ b/pandas/core/indexes/frozen.py @@ -149,7 +149,7 @@ def values(self): arr = self.view(np.ndarray).copy() return arr - def __str__(self): + def __repr__(self): """ Return a string representation for this object. """ diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 0ac87c653cfff..f86ef40a97299 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -233,8 +233,7 @@ def make_block_same_class(self, values, placement=None, ndim=None, return make_block(values, placement=placement, ndim=ndim, klass=self.__class__, dtype=dtype) - def __str__(self): - + def __repr__(self): # don't want to print out all of the items here name = pprint_thing(self.__class__.__name__) if self._is_single_block: diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index 96a672b60da70..0b63588c9f5d9 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -291,7 +291,7 @@ def _post_setstate(self): def __len__(self): return len(self.items) - def __str__(self): + def __repr__(self): output = pprint_thing(self.__class__.__name__) for i, ax in enumerate(self.axes): if i == 0: diff --git a/pandas/core/panel.py b/pandas/core/panel.py index b6b957c543df6..c65a73bd0d3f0 100644 --- a/pandas/core/panel.py +++ b/pandas/core/panel.py @@ -340,7 +340,7 @@ def _compare_constructor(self, other, func): # ---------------------------------------------------------------------- # Magic methods - def __str__(self): + def __repr__(self): """ Return a string representation for a particular Panel. """ diff --git a/pandas/core/series.py b/pandas/core/series.py index 5b59fd6e7b38d..55b5bdcbf53f4 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1384,7 +1384,7 @@ def reset_index(self, level=None, drop=False, name=None, inplace=False): # ---------------------------------------------------------------------- # Rendering Methods - def __str__(self): + def __repr__(self): """ Return a string representation for a particular Series. """ diff --git a/pandas/core/sparse/series.py b/pandas/core/sparse/series.py index ae1c94e136475..eac59e2c0f5eb 100644 --- a/pandas/core/sparse/series.py +++ b/pandas/core/sparse/series.py @@ -217,9 +217,8 @@ def as_sparse_array(self, kind=None, fill_value=None, copy=False): return SparseArray(self.values, sparse_index=self.sp_index, fill_value=fill_value, kind=kind, copy=copy) - def __str__(self): - # currently, unicode is same as repr...fixes infinite loop - series_rep = Series.__str__(self) + def __repr__(self): + series_rep = Series.__repr__(self) rep = '{series}\n{index!r}'.format(series=series_rep, index=self.sp_index) return rep diff --git a/pandas/core/window.py b/pandas/core/window.py index deb64f1fb089d..d51e12035c829 100644 --- a/pandas/core/window.py +++ b/pandas/core/window.py @@ -157,7 +157,7 @@ def _get_window(self, other=None): def _window_type(self): return self.__class__.__name__ - def __str__(self): + def __repr__(self): """ Provide a nice str repr of our rolling object. """