Skip to content

Cache some properties #5540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
13 changes: 7 additions & 6 deletions xarray/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from .types import T_Xarray
from .utils import (
NDArrayMixin,
cached_property,
either_dict_or_kwargs,
get_valid_numpy_dtype,
safe_cast_to_index,
Expand Down Expand Up @@ -472,7 +473,7 @@ def __getitem__(self, key):
class LazilyIndexedArray(ExplicitlyIndexedNDArrayMixin):
"""Wrap an array to make basic and outer indexing lazy."""

__slots__ = ("array", "key")
__slots__ = ("array", "key", "__dict__")

def __init__(self, array, key=None):
"""
Expand Down Expand Up @@ -509,7 +510,7 @@ def _updated_key(self, new_key):
return BasicIndexer(full_key)
return OuterIndexer(full_key)

@property
@cached_property
def shape(self) -> tuple[int, ...]:
shape = []
for size, k in zip(self.array.shape, self.key.tuple):
Expand Down Expand Up @@ -552,7 +553,7 @@ def __repr__(self):
class LazilyVectorizedIndexedArray(ExplicitlyIndexedNDArrayMixin):
"""Wrap an array to make vectorized indexing lazy."""

__slots__ = ("array", "key")
__slots__ = ("array", "key", "__dict__")

def __init__(self, array, key):
"""
Expand All @@ -568,7 +569,7 @@ def __init__(self, array, key):
self.key = _arrayize_vectorized_indexer(key, array.shape)
self.array = as_indexable(array)

@property
@cached_property
def shape(self) -> tuple[int, ...]:
return np.broadcast(*self.key.tuple).shape

Expand Down Expand Up @@ -1367,7 +1368,7 @@ def transpose(self, order):
class PandasIndexingAdapter(ExplicitlyIndexedNDArrayMixin):
"""Wrap a pandas.Index to preserve dtypes and handle explicit indexing."""

__slots__ = ("array", "_dtype")
__slots__ = ("array", "_dtype", "__dict__")

def __init__(self, array: pd.Index, dtype: DTypeLike = None):
self.array = safe_cast_to_index(array)
Expand All @@ -1391,7 +1392,7 @@ def __array__(self, dtype: DTypeLike = None) -> np.ndarray:
array = array.astype("object")
return np.asarray(array.values, dtype=dtype)

@property
@cached_property
def shape(self) -> tuple[int, ...]:
return (len(self.array),)

Expand Down
8 changes: 8 additions & 0 deletions xarray/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -977,3 +977,11 @@ def contains_only_dask_or_numpy(obj) -> bool:
for var in obj.variables.values()
]
)


class cached_property(functools.cached_property):
"""Read only version of functools.cached_property."""

def __set__(self, instance, val):
"""Raise an error when attempting to set a cached property."""
raise AttributeError("Can't set attribute")
5 changes: 3 additions & 2 deletions xarray/core/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
NdimSizeLenMixin,
OrderedSet,
_default,
cached_property,
decode_numpy_dict_values,
drop_dims_from_indexers,
either_dict_or_kwargs,
Expand Down Expand Up @@ -292,7 +293,7 @@ class Variable(AbstractArray, NdimSizeLenMixin, VariableArithmetic):
they can use more complete metadata in context of coordinate labels.
"""

__slots__ = ("_dims", "_data", "_attrs", "_encoding")
__slots__ = ("_dims", "_data", "_attrs", "_encoding", "__dict__")

def __init__(self, dims, data, attrs=None, encoding=None, fastpath=False):
"""
Expand Down Expand Up @@ -327,7 +328,7 @@ def __init__(self, dims, data, attrs=None, encoding=None, fastpath=False):
def dtype(self):
return self._data.dtype

@property
@cached_property
def shape(self):
return self._data.shape

Expand Down