Skip to content

Commit e7e4ccf

Browse files
authored
Merge pull request #1441 from pavlin-policar/pythagorean-tree
[ENH] Pythagorean tree and Pythagorean forest widgets
2 parents b2126d7 + 596a452 commit e7e4ccf

19 files changed

+4151
-4
lines changed

Orange/misc/cache.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,60 @@
1-
def single_cache(f):
1+
"""Common caching methods, using `lru_cache` sometimes has its downsides."""
2+
from functools import wraps, lru_cache
3+
import weakref
4+
5+
6+
def single_cache(func):
7+
"""Cache with size 1."""
28
last_args = ()
39
last_kwargs = set()
410
last_result = None
511

6-
def cached(*args, **kwargs):
12+
@wraps(func)
13+
def _cached(*args, **kwargs):
714
nonlocal last_args, last_kwargs, last_result
815
if len(last_args) != len(args) or \
916
not all(x is y for x, y in zip(args, last_args)) or \
1017
last_kwargs != set(kwargs) or \
1118
any(last_kwargs[k] != kwargs[k] for k in last_kwargs):
12-
last_result = f(*args, **kwargs)
19+
last_result = func(*args, **kwargs)
1320
last_args, last_kwargs = args, kwargs
1421
return last_result
1522

16-
return cached
23+
return _cached
24+
25+
26+
def memoize_method(*lru_args, **lru_kwargs):
27+
"""Memoize methods without keeping reference to `self`.
28+
29+
Parameters
30+
----------
31+
lru_args
32+
lru_kwargs
33+
34+
Returns
35+
-------
36+
37+
See Also
38+
--------
39+
https://stackoverflow.com/questions/33672412/python-functools-lru-cache-with-class-methods-release-object
40+
41+
"""
42+
def _decorator(func):
43+
44+
@wraps(func)
45+
def _wrapped_func(self, *args, **kwargs):
46+
self_weak = weakref.ref(self)
47+
# We're storing the wrapped method inside the instance. If we had
48+
# a strong reference to self the instance would never die.
49+
50+
@wraps(func)
51+
@lru_cache(*lru_args, **lru_kwargs)
52+
def _cached_method(*args, **kwargs):
53+
return func(self_weak(), *args, **kwargs)
54+
55+
setattr(self, func.__name__, _cached_method)
56+
return _cached_method(*args, **kwargs)
57+
58+
return _wrapped_func
59+
60+
return _decorator

Orange/tests/test_misc.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import unittest
2+
3+
from Orange.misc.cache import memoize_method, single_cache
4+
5+
6+
class Calculator:
7+
@memoize_method()
8+
def my_sum(self, *nums):
9+
return sum(nums)
10+
11+
12+
@single_cache
13+
def my_sum(*nums):
14+
return sum(nums)
15+
16+
17+
class TestCache(unittest.TestCase):
18+
19+
def test_single_cache(self):
20+
self.assertEqual(my_sum(1, 2, 3, 4, 5), 15)
21+
self.assertEqual(my_sum(1, 2, 3, 4, 5), 15)
22+
# Make sure different args produce different results
23+
self.assertEqual(my_sum(1, 2, 3, 4), 10)
24+
25+
def test_memoize_method(self):
26+
calc = Calculator()
27+
self.assertEqual(calc.my_sum(1, 2, 3, 4, 5), 15)
28+
self.assertEqual(calc.my_sum(1, 2, 3, 4, 5), 15)
29+
# Make sure different args produce different results
30+
self.assertEqual(calc.my_sum(1, 2, 3, 4), 10)
Lines changed: 22 additions & 0 deletions
Loading
Lines changed: 20 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)