我已经使用惰性属性库(https://pypi.org/project/lazy-property/)一段时间了。它运行完美,但是在我的编辑器中,这些惰性属性不会提供任何自动填充功能。

我的设置是Atom,使用ide-python软件包(https://github.com/lgeiger/ide-python),该软件包由python-语言服务器(https://github.com/palantir/python-language-server)驱动,该服务器使用Jedi(https://github.com/davidhalter/jedi)进行自动完成。

基本上,此问题应该在任何基于Jedi的自动完成情况下都可以重现。

我一直在想是否可以重写惰性属性中的代码(也许使用类型提示和诸如此类的东西),以使Jedi能够理解来自惰性属性装饰方法的类型应该与装饰工不在。

这个装饰器的实现实际上是非常简单的,基本上就是:

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


是否有人对我如何重构该类有任何想法,以使Jedi理解它应该假定装饰器不会更改返回值的类型?

任何帮助将不胜感激,欢呼。

最佳答案

您遇到的问题是Jedi无法真正处理super().__init__(fget=fget, fset=fset, fdel=fdel, doc=doc)。它真的不了解您在那做什么。如果您在该行之后写self.fget = fget,Jedi将理解您的示例。

为了更深入地挖掘,绝地试图了解分支机构。在您的情况下,它认为result = self.fget(instance)的结果就是要推断的结果,因为self.fget is not None推断为True。它推断为True,因为self.fgetproperty在排版的存根中定义为def fget(self) -> Any: ...,这基本上意味着它肯定存在。因此,存根在本质上与您的实际情况略有不同(那里可能有些错误)。

但是,也请注意,写入缓存属性是之前完成的工作。最佳实现之一是@cached_property中的Django,因此您也可以从那里复制:

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

关于python - 实现绝地可以理解的懒惰属性,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58413609/

10-12 19:27