Once¶
Run a function a single time; later calls return the first result and ignore their arguments.
from python_wrap import once
@once
def setup() -> object:
return object()
assert setup() is setup()
assert setup.called is True
setup.reset() # forget the result; the next call runs again
assert setup.called is False
When to use it¶
- Initialisation, setup or a config load that must happen one time.
- Not when the result depends on arguments: use
memoize. - Not for a per-object attribute: use
cached_property.
Failures¶
If the first call raises, the function is not marked done and the next call tries again.
Async and methods¶
once is thread-safe. For async def functions, concurrent first awaits share one run, even across threads that each run their own event loop: it runs once per process.
import asyncio
from python_wrap import once
runs = []
@once
async def connect() -> str:
runs.append(1)
await asyncio.sleep(0.01)
return "connection"
async def main() -> None:
a, b = await asyncio.gather(connect(), connect()) # share one task
assert a == b == "connection"
assert runs == [1]
asyncio.run(main())
Testing¶
While python_wrap.testing.disable_caching() is active, once runs the function on every call and stores nothing. Use .reset() to re-arm it between tests.