2

我一直在使用惰性属性库(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 ) 进行自动补全。

基本上,这个问题应该在任何基于 Jedi 的自动完成上下文中都可以重现。

我一直想知道是否有一种方法可以重写惰性属性中的代码(可能使用类型提示等),以便绝地可以理解来自惰性属性装饰方法的类型应该与 if 相同装饰师缺席。

这个装饰器的实现其实超级简单,基本上就是:

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 理解它应该假设装饰器不会改变返回值的类型?

任何帮助将不胜感激,干杯。

4

1 回答 1

1

你的问题是绝地不能真正处理super().__init__(fget=fget, fset=fset, fdel=fdel, doc=doc)。它并不真正理解你在那里做什么。如果你self.fget = fget在那一行之后写,绝地会理解你的例子。

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

但是请注意,编写缓存的属性是以前做过的事情。最好的实现之一是@cached_propertyin Django,因此您也可以从那里复制:

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

于 2019-10-17T23:18:20.600 回答