From e7070f09bcbc4aa960216d099beff4431744a7e2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 8 Jun 2015 11:19:24 +0300 Subject: [PATCH] Issue #14373: C implementation of functools.lru_cache() now can be used with methods. --- Lib/test/test_functools.py | 31 +++++++++++++++++++++++++++++++ Misc/NEWS | 3 +++ Modules/_functoolsmodule.c | 12 +++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index 632b2d37409..569bdcf701c 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -1203,6 +1203,37 @@ class TestLRU: def f(): pass + def test_lru_method(self): + class X(int): + f_cnt = 0 + @self.module.lru_cache(2) + def f(self, x): + self.f_cnt += 1 + return x*10+self + a = X(5) + b = X(5) + c = X(7) + self.assertEqual(X.f.cache_info(), (0, 0, 2, 0)) + + for x in 1, 2, 2, 3, 1, 1, 1, 2, 3, 3: + self.assertEqual(a.f(x), x*10 + 5) + self.assertEqual((a.f_cnt, b.f_cnt, c.f_cnt), (6, 0, 0)) + self.assertEqual(X.f.cache_info(), (4, 6, 2, 2)) + + for x in 1, 2, 1, 1, 1, 1, 3, 2, 2, 2: + self.assertEqual(b.f(x), x*10 + 5) + self.assertEqual((a.f_cnt, b.f_cnt, c.f_cnt), (6, 4, 0)) + self.assertEqual(X.f.cache_info(), (10, 10, 2, 2)) + + for x in 2, 1, 1, 1, 1, 2, 1, 3, 2, 1: + self.assertEqual(c.f(x), x*10 + 7) + self.assertEqual((a.f_cnt, b.f_cnt, c.f_cnt), (6, 4, 5)) + self.assertEqual(X.f.cache_info(), (15, 15, 2, 2)) + + self.assertEqual(a.f.cache_info(), X.f.cache_info()) + self.assertEqual(b.f.cache_info(), X.f.cache_info()) + self.assertEqual(c.f.cache_info(), X.f.cache_info()) + class TestLRUC(TestLRU, unittest.TestCase): module = c_functools diff --git a/Misc/NEWS b/Misc/NEWS index 03b8631a4a2..16098167bb2 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,6 +15,9 @@ Core and Builtins Library ------- +- Issue #14373: C implementation of functools.lru_cache() now can be used with + methods. + - Issue #8232: webbrowser support incomplete on Windows. Patch by Brandon Milam diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 99b50b0e9d3..95b5b13fbec 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -1003,6 +1003,16 @@ lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds) return self->wrapper(self, args, kwds); } +static PyObject * +lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type) +{ + if (obj == Py_None || obj == NULL) { + Py_INCREF(self); + return self; + } + return PyMethod_New(self, obj); +} + static PyObject * lru_cache_cache_info(lru_cache_object *self, PyObject *unused) { @@ -1115,7 +1125,7 @@ static PyTypeObject lru_cache_type = { lru_cache_getsetlist, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ - 0, /* tp_descr_get */ + lru_cache_descr_get, /* tp_descr_get */ 0, /* tp_descr_set */ offsetof(lru_cache_object, dict), /* tp_dictoffset */ 0, /* tp_init */