On Sat, Mar 23, 2013 at 8:33 AM, Antoine Pitrou email@example.com wrote:
On Sat, 23 Mar 2013 16:30:39 +0100 Masklinn firstname.lastname@example.org wrote:
Right, but in this case while I called it a cache the semantics really is a lazy singleton: only create the regex object when it's needed, but keep it around once it's been created.
Perhaps we need a functools.lazy_compute() function:
pat = functools.lazy_compute(re.compile, r"my very long regex")
As in something like:
def compute_once(f, *args, **kwds): value = not_called = object() @wraps(f): def compute_on_demand(): nonlocal value if value is not_called: value = f(*args, **kwds) return value return compute_on_demand
_pattern = compute_once(re.compile, r"my very long regex")
def use_pattern(data): return _pattern().search(data)
Runtime overhead is then just the identity check for the initial sentinel value.
The difference with both functools.partial and functools.lru_cache is that it wouldn't support customisation at call time - you have to fully define the operation up front, the only thing you're deferring is the actual call. That call will only happen once, with all subsequent calls returning the same value as the initial call. This is what allows the call time overhead to be stripped back to almost nothing.
Seems like a reasonable justification for a dedicated tool to me.