Skip to content

Commit 1231b9e

Browse files
committed
API: Added ExtensionArray constructors
Adds two new (private, but part of the interface) constructors to EA. Closes pandas-dev#19906
1 parent 1e4c50a commit 1231b9e

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

pandas/core/arrays/base.py

+49
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class ExtensionArray(object):
1818
The interface includes the following abstract methods that must be
1919
implemented by subclasses:
2020
21+
* _from_extension_array
22+
* _from_scalars
2123
* __getitem__
2224
* __len__
2325
* dtype
@@ -56,6 +58,53 @@ class ExtensionArray(object):
5658
# '_typ' is for pandas.core.dtypes.generic.ABCExtensionArray.
5759
# Don't override this.
5860
_typ = 'extension'
61+
62+
# ------------------------------------------------------------------------
63+
# Constructors
64+
# ------------------------------------------------------------------------
65+
@classmethod
66+
def _from_extension_array(cls, array, copy=True):
67+
"""Construct a new ExtensionArray from an existing instance.
68+
69+
Parameters
70+
----------
71+
array : ExtensionArray
72+
An extension array of the same type as cls.
73+
copy : bool, default True
74+
Whether a copy should be made using ``array.copy``. Note that
75+
even if ``copy=False`` there's no guarantee that the underlying
76+
data of the two arrays is the same.
77+
78+
Returns
79+
-------
80+
ExtensionArray
81+
82+
See Also
83+
--------
84+
_from_scalars
85+
"""
86+
raise AbstractMethodError(cls)
87+
88+
@classmethod
89+
def _from_scalars(cls, scalars):
90+
"""Construct a new ExtensionArray from a sequence of scalars.
91+
92+
Parameters
93+
----------
94+
scalars : Sequence
95+
Each element will be an instance of the scalar type for this
96+
array, ``cls.dtype.type``.
97+
98+
Returns
99+
-------
100+
ExtensionArray
101+
102+
See Also
103+
--------
104+
_from_extension_array
105+
"""
106+
raise AbstractMethodError(cls)
107+
59108
# ------------------------------------------------------------------------
60109
# Must be a Sequence
61110
# ------------------------------------------------------------------------

pandas/tests/extension/decimal/array.py

+8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ def __init__(self, values):
3232

3333
self.values = values
3434

35+
@classmethod
36+
def _from_extension_array(cls, array, copy=True):
37+
return cls(array)
38+
39+
@classmethod
40+
def _from_scalars(cls, scalars):
41+
return cls(scalars)
42+
3543
def __getitem__(self, item):
3644
if isinstance(item, numbers.Integral):
3745
return self.values[item]

pandas/tests/extension/json/array.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,21 @@ def __init__(self, values):
3333
raise TypeError
3434
self.data = values
3535

36+
@classmethod
37+
def _from_extension_array(cls, array, copy=True):
38+
return cls(array)
39+
40+
@classmethod
41+
def _from_scalars(cls, scalars):
42+
return cls(scalars)
43+
3644
def __getitem__(self, item):
3745
if isinstance(item, numbers.Integral):
3846
return self.data[item]
3947
elif isinstance(item, np.ndarray) and item.dtype == 'bool':
40-
return type(self)([x for x, m in zip(self, item) if m])
48+
return self._from_scalars([x for x, m in zip(self, item) if m])
4149
else:
42-
return type(self)(self.data[item])
50+
return self._from_extension_array(self.data[item])
4351

4452
def __setitem__(self, key, value):
4553
if isinstance(key, numbers.Integral):
@@ -77,10 +85,10 @@ def isna(self):
7785
def take(self, indexer, allow_fill=True, fill_value=None):
7886
output = [self.data[loc] if loc != -1 else self._na_value
7987
for loc in indexer]
80-
return type(self)(output)
88+
return self._from_scalars(output)
8189

8290
def copy(self, deep=False):
83-
return type(self)(self.data[:])
91+
return self._from_extension_array(self.data[:])
8492

8593
@property
8694
def _na_value(self):

0 commit comments

Comments
 (0)