我使用懒惰属性库(https://pypi.org/project/lazy-property/)已经有一段时间了。它工作得很完美,但在我的编辑器中,这些懒惰的属性不会提供任何自动补全。
我的设置是Atom,使用由python-language-server (https://github.com/palantir/python-language-server)驱动的ide-python包(https://github.com/lgeiger/ide-python),它使用Jedi (https://github.com/davidhalter/jedi)进行自动完成。
基本上,这个问题应该可以在任何基于绝地的自动完成上下文中重现。
我一直在想,是否有一种方法可以重写lazy-property中的代码(也许使用类型提示之类的),这样Jedi就可以理解来自lazy-property装饰方法的类型应该是相同的,就好像没有装饰器一样。
这个装饰器的实现实际上非常简单,它基本上就是:
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有没有人知道我如何重构这个类,以便让绝地明白它应该假设装饰者不改变返回值的类型?
任何帮助都会非常感谢,干杯。
发布于 2019-10-18 07:18:21
你的问题是绝地不能真的对付super().__init__(fget=fget, fset=fset, fdel=fdel, doc=doc)。它并不真正理解你在那里做什么。如果你在那行后面写self.fget = fget,绝地就能理解你的例子。
为了更深入地挖掘,绝地武士试图了解分支。在您的例子中,它认为result = self.fget(instance)的结果就是它必须推断的结果,因为self.fget is not None会推断为True。它会推断出True,因为property的self.fget在类型化存根中被定义为def fget(self) -> Any: ...,这基本上意味着它肯定存在。因此,存根基本上与您的情况中的实际情况有点不同(它们可能在那里略有错误)。
但是,还请注意,编写缓存属性是以前已经做过的事情。最好的实现之一是Django中的@cached_property,所以您也可以直接从那里复制:
https://docs.djangoproject.com/en/2.2/_modules/django/utils/functional/#cached_property
https://stackoverflow.com/questions/58413609
复制相似问题