Skip to content

Commit 8c08aca

Browse files
committed
PERF: allow a cache_readonly to be 'set' if allow_settings is passed on the decoration
useful when specifiying an index that is **known** to be unique (e.g. in the case of a default range index)
1 parent b8382a3 commit 8c08aca

File tree

3 files changed

+27
-11
lines changed

3 files changed

+27
-11
lines changed

pandas/core/common.py

+1
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,7 @@ def _default_index(n):
11561156
values = np.arange(n, dtype=np.int64)
11571157
result = values.view(Int64Index)
11581158
result.name = None
1159+
result.is_unique = True
11591160
return result
11601161

11611162

pandas/core/index.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ def is_monotonic(self):
278278
def is_lexsorted_for_tuple(self, tup):
279279
return True
280280

281-
@cache_readonly
281+
@cache_readonly(allow_setting=True)
282282
def is_unique(self):
283283
return self._engine.is_unique
284284

pandas/src/properties.pyx

+25-10
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,20 @@ from cpython cimport PyDict_Contains, PyDict_GetItem, PyDict_GetItem
44
cdef class cache_readonly(object):
55

66
cdef readonly:
7-
object fget, name
7+
object func, name, allow_setting
88

9-
def __init__(self, func):
10-
self.fget = func
11-
self.name = func.__name__
9+
def __init__(self, func=None, allow_setting=False):
10+
if func is not None:
11+
self.func = func
12+
self.name = func.__name__
13+
self.allow_setting = allow_setting
1214

13-
def __get__(self, obj, type):
14-
if obj is None:
15-
return self.fget
15+
def __call__(self, func, doc=None):
16+
self.func = func
17+
self.name = func.__name__
18+
return self
1619

20+
def __get__(self, obj, typ):
1721
# Get the cache or set a default one if needed
1822

1923
cache = getattr(obj, '_cache', None)
@@ -23,12 +27,23 @@ cdef class cache_readonly(object):
2327
if PyDict_Contains(cache, self.name):
2428
# not necessary to Py_INCREF
2529
val = <object> PyDict_GetItem(cache, self.name)
26-
return val
2730
else:
28-
val = self.fget(obj)
31+
val = self.func(obj)
2932
PyDict_SetItem(cache, self.name, val)
30-
return val
33+
return val
34+
35+
def __set__(self, obj, value):
36+
37+
if not self.allow_setting:
38+
raise Exception("cannot set values for [%s]" % self.name)
39+
40+
# Get the cache or set a default one if needed
41+
cache = getattr(obj, '_cache', None)
42+
if cache is None:
43+
cache = obj._cache = {}
3144

45+
PyDict_SetItem(cache, self.name, value)
46+
3247
cdef class AxisProperty(object):
3348
cdef:
3449
Py_ssize_t axis

0 commit comments

Comments
 (0)