time.struct_time的难以忍受的不透明度



为什么pylint和IDES的智能特征难以识别time.struct_time的实例?以下代码包含一些存在的类别/不存在的类属性的微不足道测试,命名为元组和命名托普尔的time.struct_time。一切都按照Pylint,Intellij和Vscode的预期工作 - 在每种情况下都报告了对丢失属性的访问,但time.struct_time除外 - 它在任何这些工具中均未产生任何警告或错误。他们为什么不能说出它是什么,它的属性是什么?

import time
from collections import namedtuple
t = time.localtime()
e = t.tm_mday
e = t.bad # this is not reported by linters or IDEs. 
class Clz:
    cvar = 'whee'
    def __init__(self):
        self.ivar = 'whaa'
o = Clz()
e = Clz.cvar
e = o.ivar
e = Clz.bad
e = o.bad
Ntup = namedtuple('Ntup', 'thing')
n = Ntup(thing=3)
e = n.thing
e = n.bad

问题的上下文是pipenv中的以下错误 -

# Halloween easter-egg.          
if ((now.tm_mon == 10) and (now.tm_day == 30)) 

显然,通行路径从未经过测试,但似乎在这里也没有典型的静态分析工具。对于标准库中的类型来说,这很奇怪。

(可以在https://github.com/kennethreitz/pipenv/commit/033b969d094ba2d80f80f8ae217c8c604bc401601603)

time.struct_time是C中定义的对象,这意味着它不能静态地内置。自动完成软件可以解析Python代码,并对哪些类和名称支持的类别进行合理的猜测,但他们不能为C定义对象做到这一点。

大多数系统使用的工作是生成存根文件。通常通过在运行时内外对象(导入模块并记录所找到的属性)。例如,CodeIntel(Komodo IDE的一部分)使用称为CIX的XML文件格式。但是,这更容易出错,因此此类系统然后在Grution的一边 err,并且不会明确将未知属性标记为错误。

如果您在Python 3中进行编码,则可以考虑使用类型提示。对于C扩展,您仍然需要存根文件,但是社区现在非常擅长维护这些文件。标准库存根文件保留在一个称为 typeshed 的项目中。

您必须在项目中添加类型提示:

#!/usr/bin/env python3
import time
from collections import namedtuple

t: time.struct_time = time.localtime()
e: int = t.tm_mday
e = t.bad  # this is not reported by linters or IDEs.

class Clz:
    cvar: str = 'whee'
    ivar: str
    def __init__(self) -> None:
        self.ivar = 'whaa'

o = Clz()
s = Clz.cvar
s = o.ivar
s = Clz.bad
s = o.bad
Ntup = namedtuple('Ntup', 'thing')
n = Ntup(thing=3)
e = n.thing
e = n.bad

但是,随后将Flake8工具与Flake8-Mypy插件结合使用,将检测到不良属性:

$ flake8 test.py
test.py:8:5: T484 "struct_time" has no attribute "bad"
test.py:22:5: T484 "Clz" has no attribute "bad"
test.py:23:5: T484 "Clz" has no attribute "bad"
test.py:28:5: T484 "Ntup" has no attribute "bad"

pycharm也基于这项工作,也许可以检测到相同的无效用途。它当然直接支持PYI文件。

最新更新