В настоящее время я работаю над проектом, в котором у меня есть класс с различными дорогими методами, которые я хотел бы кэшировать.Я хочу реализовать кеш самостоятельно, как для упражнений, так и для того, чтобы он был особенным в том смысле, что он специально нацелен на функции, где f(f(x)) == x
равно True
(через подкласс dict, где d[key] == value and d[value] == key
равно True
).Временами это немного углубляется в python, и в данный момент я немного растерялся.
Кэш должен быть присоединен к классу, для которого определен метод, и, таким образом, мне нужно было извлечь класс изфункция в декораторе, которая добавляет кэш для функции.Проблема в том, что кажется, что python действительно делает что-то еще, как f = dec(f)
, когда декорирует f
с помощью @dec
.
Мой тестовый код и начало декоратора кеша:
def bidirectional_cache(function):
"""Function decorator for caching
For functions where f(f(x)) == x is True
Requires hashable args and doesn't support kwargs
"""
parent_instance = getattr(function, "__self__", None)
#print(type(function))
#print(dir(function))
if parent_instance is None:
parent_class = globals()[function.__qualname__.rstrip(f".{function.__name__}")]
elif type(parent_instance) is type:
parent_class = parent_instance
else:
parent_class = parent_instance.__class__
print(parent_class)
...
class A():
N = 0
def __init__(self, n):
self.n = n
def __hash__(self):
return hash(self.n)
def __add__(self, other):
return self.__class__(int(self) + int(other))
def __int__(self):
return self.n
@bidirectional_cache
def test(self):
return f"n = {self.n}"
@bidirectional_cache
@staticmethod
def test_static(a, b):
return a + b
@bidirectional_cache
@classmethod
def test_class(cls, b):
return N + b
При определении A
без декоратора кеша и последующем выполнении следующих вызовов (сеанс REPL) он выдает ожидаемые результаты:
>>> bidirectional_cache(A.test)
<class '__main__.A'>
>>> bidirectional_cache(A.test_static)
<class '__main__.A'>
>>> bidirectional_cache(A.test_class)
<class '__main__.A'>
>>> a = A(5)
>>> bidirectional_cache(a.test)
<class '__main__.A'>
>>> bidirectional_cache(a.test_static)
<class '__main__.A'>
>>> bidirectional_cache(a.test_class)
<class '__main__.A'>
Но если вместо этого я запускаю определение класса с декораторомУ меня всегда есть staticmethod
объекты внутри декоратора, и он ломается, потому что у них нет __qualname__
.Вызов dir
для A.x
, где x
- все методы тестирования, дает совершенно другой вывод, как при вызове dir
в декораторе.
Вопрос, который у меня возникает, почемучто @dec
получает объект функции, отличный от того, что получает dec(f)
?Есть ли способ получить класс, для которого определена функция в рамках декоратора, или мне всегда придется делать A.x = dec(x)
?