Skip to content

Commit 2f3c1e2

Browse files
authored
Optimize cached_method when wrapping no-arg methods (#6381)
Previously, the first time a no-arg cached method was called the decorator would make three calls: `hasattr`, `object.__setattr__`, `getattr`, and when called subsequently it would make two calls: `hasattr`, `getattr`. Here we refactor the implementation to use a sentinel value so that on the first call we only make two calls: `getattr`, `object.__setattr__`, and when called subsequently we only make a single `getattr` call.
1 parent ec727ca commit 2f3c1e2

File tree

1 file changed

+9
-3
lines changed

1 file changed

+9
-3
lines changed

cirq-core/cirq/_compat.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ def with_debug(value: bool) -> Iterator[None]:
6767
from backports.cached_property import cached_property # type: ignore[no-redef]
6868

6969

70+
# Sentinel used by wrapped_no_args below when method has not yet been cached.
71+
_NOT_FOUND = object()
72+
73+
7074
TFunc = TypeVar('TFunc', bound=Callable)
7175

7276

@@ -103,9 +107,11 @@ def decorator(func):
103107

104108
@functools.wraps(func)
105109
def wrapped_no_args(self):
106-
if not hasattr(self, cache_name):
107-
object.__setattr__(self, cache_name, func(self))
108-
return getattr(self, cache_name)
110+
result = getattr(self, cache_name, _NOT_FOUND)
111+
if result is _NOT_FOUND:
112+
result = func(self)
113+
object.__setattr__(self, cache_name, result)
114+
return result
109115

110116
return wrapped_no_args
111117

0 commit comments

Comments
 (0)