Skip to main content

Lazy Evaluation

build shields License: MIT

Lazy evaluate function/class method/class property. The target will be evaluated once and only once on first call , and concurrent calls will get the result immediately once the target is ready and gets the same exception when the target raises some exception.

Features

  • Implemented both sync and async version.

  • Lock free!!!! (thanks to asyncio.Future and concurrent.futures.Future, all the operations are atomic)

  • Assign will update cache immediately.

  • Async property must use sync setter and deleter for now, due to the limitation that python does not support await before assignment or del. await setattr(foo, value) is one possible workaround, but it introduces more obfuscation.

Installation

pip install lazy-async

Example

import asyncio
from lazy_async import lazy, lazy_property, lazy_async, lazy_property_async
from threading import Thread
import time


class ExampleClass:
    def __init__(self):
        self.sync_called = 0
        self.async_called = 0
        self.prop = 'nothing'

    @lazy
    def func1(self):
        time.sleep(5)
        self.sync_called += 1
        return 'something'

    @lazy_async
    async def func2(self):
        await asyncio.sleep(5)
        self.async_called += 1
        return 'something'

    @lazy
    def func3(self):
        time.sleep(5)
        raise ValueError('SomeException')

    @lazy_async
    async def func4(self):
        await asyncio.sleep(5)
        raise ValueError('SomeException')

    @lazy_property
    def func5(self):
        time.sleep(5)
        self.sync_called += 1
        return self.prop

    @func5.setter
    def func5(self, value):
        self.prop = value

    @lazy_property_async
    async def func6(self):
        await asyncio.sleep(5)
        self.async_called += 1
        return self.prop

    @func6.setter
    def func6(self, value):
        self.prop = value

def test_something_sync():
    test_class = ExampleClass()
    test1 = dict()

    def start1():
        test1[1] = test_class.func1()

    def start2():
        time.sleep(3)
        test1[2] = test_class.func1()

    def start3():
        time.sleep(10)
        test1[3] = test_class.func1()

    Thread(target=start1).start()
    Thread(target=start2).start()
    Thread(target=start3).start()
    time.sleep(1)
    assert test1 == {}
    time.sleep(3)
    assert test1 == {}
    time.sleep(2)
    assert test1 == {1: 'something', 2: 'something'}
    time.sleep(5)
    assert test1 == {1: 'something', 2: 'something', 3: 'something'}


def test_something_async():
    test2 = dict()
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    test_class = ExampleClass()

    async def start1():
        test2[1] = await test_class.func2()

    async def start2():
        await asyncio.sleep(3)
        test2[2] = await test_class.func2()

    async def start3():
        await asyncio.sleep(10)
        test2[3] = await test_class.func2()

    async def assert1():
        await asyncio.sleep(1)
        assert test2 == {}
        await asyncio.sleep(3)
        assert test2 == {}
        await asyncio.sleep(2)
        assert test2 == {1: 'something', 2: 'something'}
        await asyncio.sleep(5)
        assert test2 == {1: 'something', 2: 'something', 3: 'something'}

    loop.run_until_complete(asyncio.gather(start1(), start2(), start3(), assert1()))

See unittest for more examples.

Metadata

Release files for lazy-async 0.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lazy-async 0.7
File Size Uploaded
lazy-async-0.7.tar.gz 3.6 kB Details

Release files / lazy-async-0.7.tar.gz

Download URL lazy-async-0.7.tar.gz
Size 3.6 kB
Tags Source
SHA-256 checksum
How to use checksums
6a52d0079d97922ac9289062bfb61ca67fbe22dddce0b2e7757c94ff2052b545
BLAKE2b-256 checksum
How to use checksums
69a8c1c973a9c9cdbf9c45db8aa0e440b175381255309d239ce1013d7913a667
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/46.0.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.7

Release history Release notifications | RSS feed

This release

0.7 This release

1 release file

0.6

1 release file

0.5

1 release file

0.3

1 release file

0.2

1 release file

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page