diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index 42170aaa09978..dad7249de64d8 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -761,6 +761,7 @@ Sparse ExtensionArray ^^^^^^^^^^^^^^ - Bug in :meth:`Series.mean` overflowing unnecessarily with nullable integers (:issue:`48378`) +- Bug in :meth:`Series.tolist` for nullable dtypes returning numpy scalars instead of python scalars (:issue:`49890`) - Bug when concatenating an empty DataFrame with an ExtensionDtype to another DataFrame with the same ExtensionDtype, the resulting dtype turned into object (:issue:`48510`) - diff --git a/pandas/core/arrays/masked.py b/pandas/core/arrays/masked.py index 434d6198210f7..1fd6482f650da 100644 --- a/pandas/core/arrays/masked.py +++ b/pandas/core/arrays/masked.py @@ -436,10 +436,8 @@ def to_numpy( def tolist(self): if self.ndim > 1: return [x.tolist() for x in self] - if not self._hasna: - # faster than list(self) - return list(self._data) - return list(self) + dtype = None if self._hasna else self._data.dtype + return self.to_numpy(dtype=dtype).tolist() @overload def astype(self, dtype: npt.DTypeLike, copy: bool = ...) -> np.ndarray: diff --git a/pandas/tests/series/methods/test_tolist.py b/pandas/tests/series/methods/test_tolist.py new file mode 100644 index 0000000000000..4af473528e238 --- /dev/null +++ b/pandas/tests/series/methods/test_tolist.py @@ -0,0 +1,36 @@ +import pytest + +import pandas.util._test_decorators as td + +from pandas import ( + Interval, + Period, + Series, + Timedelta, + Timestamp, +) + + +@pytest.mark.parametrize( + "values, dtype, expected_dtype", + ( + ([1], "int64", int), + ([1], "Int64", int), + ([1.0], "float64", float), + ([1.0], "Float64", float), + (["abc"], "object", str), + (["abc"], "string", str), + ([Interval(1, 3)], "interval", Interval), + ([Period("2000-01-01", "D")], "period[D]", Period), + ([Timedelta(days=1)], "timedelta64[ns]", Timedelta), + ([Timestamp("2000-01-01")], "datetime64[ns]", Timestamp), + pytest.param([1], "int64[pyarrow]", int, marks=td.skip_if_no("pyarrow")), + pytest.param([1.0], "float64[pyarrow]", float, marks=td.skip_if_no("pyarrow")), + pytest.param(["abc"], "string[pyarrow]", str, marks=td.skip_if_no("pyarrow")), + ), +) +def test_tolist_scalar_dtype(values, dtype, expected_dtype): + # GH49890 + ser = Series(values, dtype=dtype) + result_dtype = type(ser.tolist()[0]) + assert result_dtype == expected_dtype