Реализация ленивого свойства, которое джедай может понять - PullRequest
2 голосов
/ 16 октября 2019

Я уже некоторое время использую библиотеку ленивых свойств (https://pypi.org/project/lazy-property/). Она отлично работает, но в моем редакторе эти ленивые свойства не дают автозаполнения.

Мои настройкиэто Atom, использующий пакет ide-python (https://github.com/lgeiger/ide-python),, который управляется python-language-server (https://github.com/palantir/python-language-server),, который использует Jedi (https://github.com/davidhalter/jedi) для автозаполнения.

По сути, эта проблема должна воспроизводиться в любом контексте автозаполнения на основе джедаев.

Мне было интересно, можно ли как-нибудь переписать код в lazy-property (возможно, используя type-hints и whatnot)так что джедай мог понять, что тип, исходящий из метода с отложенными свойствами, должен быть таким же, как если бы декоратор отсутствовал.

Реализация этого декоратора на самом деле очень проста, в основном это просто:

class lazy_property(property):
    def __init__(self, method, fget=None, fset=None, fdel=None, doc=None):

        self.method = method
        self.cache_name = f"_{self.method.__name__}"

        doc = doc or method.__doc__
        super().__init__(fget=fget, fset=fset, fdel=fdel, doc=doc)

        update_wrapper(self, method)

    def __get__(self, instance, owner):

        if instance is None:
            return self

        if hasattr(instance, self.cache_name):
            result = getattr(instance, self.cache_name)
        else:
            if self.fget is not None:
                result = self.fget(instance)
            else:
                result = self.method(instance)

            setattr(instance, self.cache_name, result)

        return result

Есть ли у кого-нибудь идеи о том, как я могу провести рефакторинг этого класса, чтобы джедай понял, что он должен предполагать, что декоратор не меняет типЧто из возвращаемых значений?

Любая помощь будет высоко ценится, ура.

1 Ответ

1 голос
/ 18 октября 2019

Проблема в вашем случае в том, что джедай не может справиться с super().__init__(fget=fget, fset=fset, fdel=fdel, doc=doc). Это не совсем понятно, что ты там делаешь. Если вы напишите self.fget = fget после этой строки, джедай поймет ваш пример.

Чтобы покопаться немного глубже, джедай попытается понять, переходят ли ветки. В вашем случае он думает, что результат result = self.fget(instance) - это то, что он должен вывести, потому что self.fget is not None означает Истину. Это означает True, потому что self.fget для property определено в заглушках с типами как def fget(self) -> Any: ..., что в основном означает, что оно определенно существует. Таким образом, заглушки в вашем случае немного отличаются от реальности (возможно, они немного ошибочны).

Однако, пожалуйста, обратите внимание, что написание кешированных свойств было сделано ранее. Одна из лучших реализаций для этого - @cached_property в Django, так что вы также можете просто скопировать оттуда:

https://docs.djangoproject.com/en/2.2/_modules/django/utils/functional/#cached_property

...