Vim的全自动补全在Python中对"from"导入失败

3 投票
1 回答
926 浏览
提问于 2025-04-16 01:03

在Python中,当使用“from”导入时,自动补全功能似乎会失效,而正常的导入却没有问题。

举个例子,我有这两个文件:

Test.py:

class Test:
    def method(self):
        pass

main.py:

from Test import Test

class Test2:
    def __init__(self):
       self.x = Test()

如果我尝试对self.x使用自动补全,它会提示“找不到模式”。但是,如果我把导入语句改成:

import Test

并把self.x的声明改成:

self.x = Test.Test()

那么我就能正常使用自动补全了(比如它会建议“method”)。

我使用的是Vim 7.2.245和默认的Python代码补全插件(pythoncomplete)。我需要设置什么变量吗?还是说这种情况是正常的?

更新

根据Jared的回答,我意外发现了一些事情:

自动补全在这个情况下不起作用:

from StringIO import StringIO

class Test:
    def __init__(self):
        self.x = StringIO()
        self.x.<C-x><C-o>

s = Test()

但在这个情况下却可以正常工作:

from StringIO import StringIO

class Test:
    def __init__(self):
        self.x = StringIO()
        self.x.<C-x><C-o>

s = Test()
s.x = StringIO()

唯一的区别是x的重新声明(实际上,如果我去掉__init__里面的声明,它也能正常工作)。

我又测试了一下我的例子,我觉得问题不在于“from”导入,而是在另一个类中使用了导入的类。如果我把文件main.py改成:

from Test import Test

class Test2:
    def __init__(self):
       self.x = Test()
       self.x.<C-x><C-o>

y = Test()
y.<C-x><C-o>

第一次尝试使用自动补全失败,但第二次就正常了。所以看起来这可能是插件的一个bug :)

1 个回答

2

更新:哦,我查看了你的例子,发现我能完成

x = Test()
x.<C-x><C-o>

但是不能完成

o = object()
o.x = Test()
o.x.<C-x><C-o>

...我打算再深入研究一下

更新 2: 怪博士的复仇

然后...事情就变得奇怪了。

from StringIO import StringIO
class M:
    pass
s = M()
s.x = StringIO()
s.x.<C-x><C-o>

可以完成。但是这个

from StringIO import StringIO
class M: pass
s = M()
s.x = StringIO()
s.x.<C-x><C-o>

你发现有什么不同吗? 在语法上没有 -- 只是多了一些空格

然而这却导致了完成失败。所以这里肯定有个解析的错误(为什么他们不直接使用 ast 模块,我也不知道...)

[更新结束]

乍一看,我无法重现你的问题;这是我的测试文件:

from os import path
path.<C-x><C-o>

我能完成。现在,我知道这并不完全是你的情况,但这表明 pythoncomplete 知道 'from'。

接下来是更深入的例子:

from StringIO import StringIO
s = StringIO()
s.<C-x><C-o>

而且...可以完成!你能试试这个例子,看看它在内置模块中是否对你有效吗? 如果是这样,你可能需要检查一下路径...

如果还是不行,而且你愿意深入研究,可以看看 pythoncomplete.vim 的第 555 行 [在我的 ubuntu 机器上是 /usr/share/vim/vim72/autoload/pythoncomplete.vim]:

            elif token == 'from':                                    
                mod, token = self._parsedotname()                    
                if not mod or token != "import":                     
                    print "from: syntax error..."                    
                    continue                                         
                names = self._parseimportlist()                      
                for name, alias in names:                            
                    loc = "from %s import %s" % (mod,name)           
                    if len(alias) > 0: loc += " as %s" % alias       
                    self.scope.local(loc)                            
                freshscope = False                                   

如你所见,这里处理 from 语句。

祝好

撰写回答