Vim documentation: if_pyth

*if_pyth.txt* For Vim version 8.0. 最近更新: 2017年7月 VIM 参考手册 by Paul Moore 译者: lang2,Willis http://vimcdoc.sf.net Vim 的 Python 编程接口 *python* *Python* 1. 命令 |python-commands| 2. vim 模块 |python-vim| 3. 缓冲区对象 |python-buffer| 4. 范围对象 |python-range| 5. 窗口对象 |python-window| 6. 标签页对象 |python-tabpage| 7. vim.bindeval 对象 |python-bindeval-objects| 8. pyeval()、py3eval() Vim 函数 |python-pyeval| 9. 动态调入 |python-dynamic| 10. Python 3 |python3| 11. Python X |python_x| 12. 编译时带 Python 支持 |python-building| {Vi 无此功能} Vim 的 Python 2.x 接口仅当 |+python| 特性被编译进 Vim 时才有效。 Vim 的 Python 3 接口仅当 |+python3| 特性被编译进 Vim 时才有效。 可以同时使用两者,但请阅读 |python-2-and-3|============================================================================== 1. 命令 *python-commands* *:python* *:py* *E263* *E264* *E887* :[range]py[thon] {stmt} 执行 Python 语句 {stmt}。一个判断 ":python" 命令是否可 用的简单检查: > :python print "Hello" :[range]py[thon] << {endmarker} {script} {endmarker} 执行 Python 脚本 {script}。 备注: 此命令在没有编译进 Python 特性时无效。为了避免这 样的错误,参阅 |script-here|{endmarker} 前面_不能_有任何空白字符。如果在 "<<" 之后省略了 {endmarker},在 {script} 之后一定要有一个点 '.'。这和 |:append||:insert| 命令的道理是一样 的。这种形式的 |:python| 命令主要用于在 Vim 脚本中嵌入 Python 代码。 例子: > function! IcecreamInitialize() python << EOF class StrawberryIcecream: def __call__(self): print 'EAT ME' EOF endfunction 要看运行的 Python 版本: > :python import sys :python print(sys.version) 备注: Python 对于缩进是非常敏感的。要确保 "class" 所在行及 "EOF" 没有任何缩 进。 *:pydo* :[range]pydo {body}[range] 里的每一行执行 Python 函数 "def _vim_pydo(line, linenr): {body}",其中的函数参数设为每 行不带尾部 <EOL> 的文本,以及行号。该函数应该返回字符 串或者 None。如果返回字符串,它会用来替代当前执行的 行。缺省 [range] 为整个文件: "1,$"。 {Vi 无此功能} 示例: > :pydo return "%s\t%d" % (line[::-1], len(line)) :pydo if line: return "%4d: %s" % (linenr, line) < *:pyfile* *:pyf* :[range]pyf[ile] {file} 执行 {file} 文件中包含的 Python 脚本。整个参数被用作一 个文件名。 {Vi 无此功能} 这些命令根本上都差不多 - 它们都将当前范围 |python-range| 设定为指定的行范围, 并对其执行 Python 代码。 :python 的情况所执行的代码来自命令行。 :pyfile 的情况所执行的代码来自一个指定的文件。 Python 命令不能在 |sandbox| 里使用。 需要传递参数的话,你得使用 sys.argv[]。例如: > :python import sys :python sys.argv = ["foo", "bar"] :pyfile myscript.py 下面是一些例子 *python-examples* > :python from vim import * :python from string import upper :python current.line = upper(current.line) :python print "Hello" :python str = current.buffer[42] (注意 如同导入 (import) 模块一样,变动对后续命令持续有效。这和 Python 的解释 程序是一样的。) ============================================================================== 2. vim 模块 *python-vim* Python 的代码所有对 Vim 的操作 (只有一个例外 - 看下面的 |python-output|) 都是 通过 "vim" 模块来进行的。该模块包括两个方法,三个常量,以及一个异常对象。在使 用它们之前你得先导入 (import) vim 模块。 总览 > :py print "Hello" # 显示信息 :py vim.command(cmd) # 执行 Ex 命令 :py w = vim.windows[n] # 获取窗口 "n" :py cw = vim.current.window # 获取当前窗口 :py b = vim.buffers[n] # 获取缓冲区 "n" :py cb = vim.current.buffer # 获取当前缓冲区 :py w.height = lines # 设定窗口高度 :py w.cursor = (row, col) # 设定光标位置 :py pos = w.cursor # 获取 tuple (行,列) :py name = b.name # 获取缓冲区的文件名 :py line = b[n] # 获取缓冲区内的一行 :py lines = b[n:m] # 获取数行 :py num = len(b) # 获取统计的行数 :py b[n] = str # 在缓冲区里写入一行文本 :py b[n:m] = [str1, str2, str3] # 一次性写入多行文本 :py del b[n] # 删除一行 :py del b[n:m] # 删除数行 "vim" 模块中的方法 vim.command(str) *python-command* 执行 vim (ex-模式) 命令 str。无返回值。 例如: > :py vim.command("set tw=72") :py vim.command("%s/aaa/bbb/g") < 下面的定义可以执行普通模式命令: > def normal(str): vim.command("normal "+str) # 注意使用单引号标识出含有双引号的字符串 normal('"a2dd"aP') < *E659* ":python" 在 Python 2.2 及之前版本上不能嵌套使用。下面命令只对 Python 2.3 之后版本适用: > :py vim.command("python print 'Hello again Python'") vim.eval(str) *python-eval* 使用 vim 内部的表达式处理器来对表达式 str 求值。(参阅 |expression|)。 返回表达式的结果: -如果 Vim 表达式计算结果是字符串或者数值,那么返回一个字符串。 -如果 Vim 表达式计算结果是 Vim 列表,那么返回一个列表 -如果 Vim 表达式计算结果是 Vim 字典,那么返回一个字典 字典和列表被递归扩展。 例: > :py text_width = vim.eval("&tw") :py str = vim.eval("12+12") # 注意: 结果是个字符串! # 使用 string.atoi() # 把它转换成数字 :py tagList = vim.eval('taglist("eval_expr")') < 后一个将返回一个 python 类型的字典列表,例如: [{'cmd': '/^eval_expr(arg, nextcmd)$/', 'static': 0, 'name': ~ 'eval_expr', 'kind': 'f', 'filename': './src/eval.c'}] ~ vim.bindeval(str) *python-bindeval* 类似于 |python-eval|,但返回 |python-bindeval-objects| 中描述的特殊 对象。这些 python 对象可用于修改 (|List||Dictionary|) 或调用 (|Funcref|) vim 对象。 vim.strwidth(str) *python-strwidth* 类似于 |strwidth()|: 返回 str 占据的显示单元数,制表符算作一个单元。 vim.foreach_rtp(callable) *python-foreach_rtp*'runtimepath' 的每个路径调用给定的 callable,直到某次 callable 返回 非 None 值、抛出例外、或者没有更多的路径为止。如果因为 callable 返回 非 None 而停止,vim.foreach_rtp 函数返回 callable 返回的值。 vim.chdir(*args, **kwargs) *python-chdir* vim.fchdir(*args, **kwargs) *python-fchdir* 运行 os.chdir 或 os.fchdir,然后做合适的 vim 的事情。 备注: 你不应直接使用这些函数,用 os.chdir 或 os.fchdir 代替。如果 os.fchdir 不存在,则 vim.fchdir 的行为未定义。 "vim" 模块中的异常对象 vim.error *python-error* 当遇到 Vim 的错误时,Python 引起一个 vim.error 类的异常。 例: > try: vim.command("put a") except vim.error: # nothing in register a "vim" 模块中的常量 注意 这些其实并非真正的常量 - 你还是可以对它们赋值。但这毫无意义,因 为你会丢失该 vim 对象本来代表的值。 vim.buffers *python-buffers* 一个映射对象,用来提供对 vim 缓冲区的操作。该对象支持以下操作: > :py b = vim.buffers[i] # 索引 (只读) :py b in vim.buffers # 成员测试 :py n = len(vim.buffers) # 成员个数 :py for b in vim.buffers: # 遍历缓冲区列表 < vim.windows *python-windows* 一个序列对象,用来提供对 vim 窗口的操作。该对象支持以下操作: > :py w = vim.windows[i] # 索引 (只读) :py w in vim.windows # 成员测试 :py n = len(vim.windows) # 成员个数 :py for w in vim.windows: # 顺序存取 < 注意: vim.windows 对象总是访问当前标签页。|python-tabpage|.windows 对 象和父 |python-tabpage| 对象绑定,总是使用该标签页的窗口 (如果该标签页 该删除,抛出 vim.error)。你可以得到两者的引用而无需保存 vim 模块对象或 |python-tabpage| 的引用。此时它们不会失去自己的属性。 vim.tabpages *python-tabpages* 一个序列对象,用来提供 vim 标签页的操作。该对象支持以下操作: > :py t = vim.tabpages[i] # 索引 (只读) :py t in vim.tabpages # 成员测试 :py n = len(vim.tabpages) # 成员个数 :py for t in vim.tabpages: # 顺序存取 < vim.current *python-current* 一个用来提供对各种各样当前 "current" 对象进行操作的对象。它包括一些特 定的属性: vim.current.line 当前行 (读写) 字符串 vim.current.buffer 当前缓冲区 (读写) 缓冲区 vim.current.window 当前窗口 (读写) 窗口 vim.current.tabpage 当前标签页 (读写) 标签页 vim.current.range 当前行范围 (只读) 范围 最后一种情况需要一些额外的解释。当用 :python 或 :pyfile 命令指定一个范 围之后,该范围将成为 "当前范围"。一个范围就如同一个缓冲区,只不过所操 作的对象界限于所有行的一个子集。请参阅 |python-range|。 注意: 赋值给 vim.current.{buffer,window,tagpage} 时,分别期待合法的 |python-buffer||python-window||python-tabpage| 对象。赋值触发 到给定缓冲区、窗口、标签页的正常切换 (带有 |autocommand| 自动命令)。这 是在 python 里切换 UI 对象的唯一方法: 不能给 |python-tabpage|.window 属性赋值。要想进行切换但不执行自动命令,可用 > py << EOF saved_eventignore = vim.options['eventignore'] vim.options['eventignore'] = 'all' try: vim.current.buffer = vim.buffers[2] # 切换到缓冲区 2 finally: vim.options['eventignore'] = saved_eventignore EOF vim.vars *python-vars* vim.vvars *python-vvars* 类似字典的对象,分别对应全局 (|g:|) 和 vim (|v:|) 变量。等价于 `vim.bindeval("g:")`,但更快。 vim.options *python-options* 部分支持映射协议 (即读写子项目) 的对象,用于对全局选项进行读写访问。 注意: 和 |:set| 不同,此对象只能访问全局选项,不能用于读写局部变量的 值或以任何方式去访问只限局部的变量。如果没有指定名字的全局变量,抛出 KeyError (也即,对 |global-local| 或只限全局的选项,不会抛出此例外, 但对局部于窗口或局部于缓冲区的则会)。|python-buffer| 对象可用于访问局 部于缓冲区的选项,|python-window| 选项则可用于访问局部于窗口的选项。 可通过 vim 模块的 "Options" 属性取得此对象的类型。 Python 的输出 *python-output* Vim 将所有 Python 代码的输出都显示在信息区。普通的输出会以一般信息出 现,错误会以出错信息出现。 用具体实现的术语来讲,这表示所有 sys.stdout (包括 print 语句的输出) 以 一般信息形式出现,而所有 sys.stderr (包括 error tracebacks) 都会被显示 成出错信息。 *python-input* Vim 并不支持用 Python 来输入 (通过 sys.stdin,包括 input() 和 raw_input())。这些调用可能会导致崩溃。这个问题可能以后会修正。 *python2-directory* *python3-directory* *pythonx-directory* Python 'runtimepath' 处理 *python-special-path* 在 python 中,vim.VIM_SPECIAL_PATH 特殊目录用于代表 'runtimepath' 的路径列表: 如果 sys.path 包含此目录而且 sys.path_hooks 包含 vim.path_hooks,python 会试图 载入 'runtimepath' 的每个 {rtp} 对应的 {rtp}/python2 (或 python3) 和 {rtp}/pythonx (同时适用于两个 python 版本) 模块。 实现大致如下,但以 C 编写: > from imp import find_module, load_module import vim import sys class VimModuleLoader(object): def __init__(self, module): self.module = module def load_module(self, fullname, path=None): return self.module def _find_module(fullname, oldtail, path): idx = oldtail.find('.') if idx > 0: name = oldtail[:idx] tail = oldtail[idx+1:] fmr = find_module(name, path) module = load_module(fullname[:-len(oldtail)] + name, *fmr) return _find_module(fullname, tail, module.__path__) else: fmr = find_module(fullname, path) return load_module(fullname, *fmr) # It uses vim module itself in place of VimPathFinder class: it does not # matter for python which object has find_module function attached to as # an attribute. class VimPathFinder(object): @classmethod def find_module(cls, fullname, path=None): try: return VimModuleLoader(_find_module(fullname, fullname, path or vim._get_paths())) except ImportError: return None @classmethod def load_module(cls, fullname, path=None): return _find_module(fullname, fullname, path or vim._get_paths()) def hook(path): if path == vim.VIM_SPECIAL_PATH: return VimPathFinder else: raise ImportError sys.path_hooks.append(hook) vim.VIM_SPECIAL_PATH *python-VIM_SPECIAL_PATH* 字符串常数,和 vim 路径钩联合使用。如果 vim 安装的路径钩被要求处理任何 非 vim.VIM_SPECIAL_PATH 常数的路径,抛出 ImportError。在唯一可能的另一 种情况下,使用特殊载入程序。 注意: 不能直接使用该常数的值,必须使用 vim.VIM_SPECIAL_PATH 对象。 vim.find_module(...) *python-find_module* vim.path_hook(path) *python-path_hook* 用于实现上述路径载入的方法或对象。除非你想对 sys.meta_path 进行处理而 可以看看 vim.path_hook,请不要直接使用它们。将来的 vim 版本不一定保证 任何这里描述的对象会继续存在。 vim._get_paths *python-_get_paths* 用于产生给路径钩搜索的路径列表的方法。可以用于调试,但不要假定将来的 vim 版本中此方法会继续存在。 返回 'runtimepath' 中每个 {rtp} 对应的 {rtp}/python2 (或 {rtp}/python3) 和 {rtp}/pythonx 的目录列表。 ============================================================================== 3. 缓冲区对象 *python-buffer* 缓冲区对象代表 vim 缓冲区。你可以用以下这几种办法来获取缓冲区的列表: - 通过 vim.current.buffer (|python-current|) - 通过 vim.buffers 的索引访问 (|python-buffers|) - 通过一个窗口的 "buffer" 属性 (|python-window|) 缓冲区对象有两个只读属性 - name - 缓冲区的文件全名,还有 number - 缓冲区号。 该对象还包括三个方法 (append,mark 及 range;见下)。 你也可以将缓冲区对象视为序列对象。这样的话,它们就可以被看作字符串的列表进行存 取 (它们是可变的)。每一个元素是缓冲区中的一行。所有通常的序列存取操作,包括索 引,索引赋值,切片 (slice) 及切片赋值,等等,都可以被使用。注意 索引 (切片) 操 作的结果是一个字符串 (字符串列表)。这产生了一个意想不到的结果 - b[:] 和 b 是不 同的。确切一些,"b[:] = None" 会清空整个缓冲区,而 "b = None" 仅仅更新变量 b 的值,完全不会影响到缓冲区。 缓冲区索引从 0 开始算起,这与通常的 Python 语法一致。但这和 Vim 的行号从 1 算 起有分歧。这一点在处理标记 (见下) 是要特别留意,因为标记是以行号区分的。 缓冲区对象的属性有: b.vars 类似字典的对象,可用于访问 |buffer-variable|。 b.options 映射对象 (支持子项目的读写和删除),用于访问局部于缓冲 区的选项和 |global-local| 选项的缓冲区局部值。如果选项 局部于窗口,请使用 |python-window|.options,使用此对象 会抛出 KeyError。如果选项是 |global-local| 而没有局部 的部分,返回 None。 b.name 字符串,可读写。包含缓冲区名 (完整路径)。 备注: 给 b.name 赋值时激活 |BufFilePre||BufFilePost| 自动事件。 b.number 缓冲区编号。可用作 |python-buffers| 的键。只读。 b.valid True 或 False。如果对应的缓冲区被删除 (wipe),缓冲区对 象就成为非法。 缓冲区对象的方法有: b.append(str) 对缓冲区附加一行 b.append(str, nr) 同上,在第 "nr" 行之后 b.append(list) 对缓冲区附加一系列行 备注: append 方法可以带一个字符串列表作为参数,这和 Python 中内建的列表对象的对应方法是不同的。 b.append(list, nr) 同上,在第 "nr" 行之后 b.mark(name) 返回一个 tuple (行,列) 用来代表该位置上的一个命名标记 (也可以用于 []"<> 等标记) b.range(s,e) 返回一个范围对象 (参见 |python-range|) 用来代表指定缓 冲区中行 s 与 行 e (包含 s 和 e |inclusive|) 之间的部 分。 注意: 当增加一行的时候,这一行里一定不要含有换行符 '\n'。行尾的 '\n' 可以, 但会被忽略,所以下面的操作是可以的: :py b.append(f.readlines()) 可通过 vim 模块的 "Buffer" 属性取得缓冲区对象的类型。 例如 (假定 b 是当前缓冲区) > :py print b.name # 输出缓冲区的名字 :py b[0] = "hello!!!" # 替换最顶上的一行 :py b[:] = None # 删除整个缓冲区 :py del b[:] # 删除整个缓冲区 :py b[0:0] = [ "a line" ] # 在第一行前添加一行 :py del b[2] # 删除一行 (第三行) :py b.append("bottom") # 在缓冲区结尾添加一行 :py n = len(b) # 总行数 :py (row,col) = b.mark('a') # 命名标记 :py r = b.range(1,5) # 缓冲区内的一个范围 :py b.vars["foo"] = "bar" # 给 b:foo 变量赋值 :py b.options["ff"] = "dos" # 设置 fileformat :py del b.options["ar"] # 等同于 :set autoread< ============================================================================== 4. 范围对象 *python-range* 范围对象代表一个 vim 缓冲区内的一个部分。你可以用以下的方法之一来获取一个缓冲 区对象: - 通过 vim.current.range (|python-current|) - 通过一个缓冲区的 range() 方法 (|python-buffer|) 一个范围对象在操作上几乎和一个缓冲区对象完全一样。不过,其操作的目标仅显于范围 指定的行 (当然,这个行范围会随着切片赋值,行删除,或者 range.append() 等等操作 而改变)。 范围对象的属性有: r.start 首行在缓冲区内的索引 r.end 尾行在缓冲区内的索引 范围对象的方法有: r.append(str) 给范围附加一行 r.append(str, nr) 同上,在第 "nr" 行之后 r.append(list) 给范围附加一系列行 备注: append 方法可以带一个字符串列表作为参数,这和 Python 中内建的列表对象的对应方法是不同的。 r.append(list, nr) 同上,在第 "nr" 行之后 可通过 vim 模块的 "Range" 属性取得范围对象的类型。 例如 (假设 r 是当前范围): # 发送范围内的所有行给缺省打印机 vim.command("%d,%dhardcopy!" % (r.start+1,r.end+1)) ============================================================================== 5. 窗口对象 *python-window* 窗口对象代表一个 vim 窗口。你可以用以下几种方法来获取一个窗口对象: - 通过 vim.current.window (|python-current|) - 通过对 vim.windows 的索引操作 (|python-windows|) - 通过对标签页的 "windows" 属性的索引操作 (|python-tabpage|) - 通过标签页的 "window" 属性 (|python-tabpage|) 你只能通过窗口对象的属性来控制它。这些对象没有方法,也没有序列等其它接口。 窗口的属性包括: buffer (只读) 窗口中显示的缓冲区 cursor (读写) 窗口中的当前光标位置 这是一个 tuple (行,列)。 height (读写) 行数表示的窗口高度 width (读写) 列数表示的窗口宽度 vars (只读) 窗口 |w:| 变量。不能给本属性赋值,但可以用此属 性修改窗口变量 options (只读) 局部于窗口的选项。不能给本属性赋值,但可以用此 属性修改窗口选项。只能用于访问局部于窗口的选 项,对局部于缓冲区的选项要用 |python-buffer|, 对全局选项用 |python-options|。如果选项是 |global-local| 的而没有局部值,返回 None。 number (只读) 窗口编号。首个窗口的编号为 1。如果不能决定才 会返回 0 (例如当窗口对象属于其他标签页时)。 row、col (只读) 窗口在屏幕上的位置,以显示单元计。首个位置为 零。 tabpage (只读) 窗口的标签页。 valid (读写) True 或 False。当对应窗口关闭时窗口对象成为非 法。 height 属性只有当屏幕被水平分割时才可写。 width 属性只有当屏幕被垂直分割时才可写。 可通过 vim 模块的 "Window" 属性取得窗口对象的类型。 ============================================================================== 6. 标签页对象 *python-tabpage* 标签页对象代表一个 vim 标签页。你可以用以下几种方法来获取之: - 通过 vim.current.tabpage (|python-current|) - 通过对 vim.tabpages 的索引操作 (|python-tabpages|) 你可以通过该对象来访问标签页里的窗口。这些对象没有方法,也没有序列等其它接口。 标签页的属性包括: number 标签页编号,和 |tabpagenr()| 相同。 windows 类似于 |python-windows|,但对应当前标签页 vars 标签页 |t:| 变量。 valid True 或 False。当对应标签页关闭时标签页对象成为非法。 可通过 vim 模块的 "TabPage" 属性取得标签页对象的类型。 ============================================================================== 7. vim.bindeval 对象 *python-bindeval-objects* vim.Dictionary 对象 *python-Dictionary* 类字典对象,用于访问 vim |Dictionary| 类型。 属性: 属性 描述 ~ locked 以下值之一 *python-.locked* 值 描述 ~ zero 变量没有上锁 vim.VAR_LOCKED 变量已上锁,但可以解锁 vim.VAR_FIXED 变量已上锁,且不可以解锁 读写。可以通过给本属性赋值 `True``False` 来给变量解锁。 不支持递归上锁。 scope 以下值之一 值 描述 ~ zero 字典无作用域 vim.VAR_DEF_SCOPE |g:||l:| 字典 vim.VAR_SCOPE 其他作用域的字典, 见 |internal-variables| 方法 (备注: 方法不支持关键字参数): 方法 描述 ~ keys() 返回字典所有键的列表。 values() 返回字典所有值的列表。 items() 返回字典所有内容的二元组的列表。 update(iterable)、update(dictionary)、update(**kwargs) 把新的键值加入字典。 get(key[, default=None]) 从字典读入 key 对应值,如果不存在返回 default。 pop(key[, default]) 从字典中删除给定 key 并返回对应值。如果找不到 key 且给出 default 返回 default,不然抛出 KeyErrror。 popitem() 从字典中删除随机键,并返回 (键, 值) 对。 has_key(key) 检查字典中是否包含给定的键 key,类似于 `key in dict`。 __new__(), __new__(iterable), __new__(dictionary), __new__(update) 用 `vim.Dictionary()` 可以建立新的 vim 字典。 `d=vim.Dictionary(arg)` 等价于 `d=vim.bindeval('{}');d.update(arg)`。无参数的版本构建空 字典。 示例: > d = vim.Dictionary(food="bar") # 构造函数 d['a'] = 'b' # 子项目赋值 print d['a'] # 读取子项目 d.update({'c': 'd'}) # .update(dictionary) d.update(e='f') # .update(**kwargs) d.update((('g', 'h'), ('i', 'j'))) # .update(iterable) for key in d.keys(): # .keys() for val in d.values(): # .values() for key, val in d.items(): # .items() print isinstance(d, vim.Dictionary) # True for key in d: # 遍历所有键 class Dict(vim.Dictionary): # 子类 < 注意: 遍历键时不应对字典进行修改。 vim.List 对象 *python-List* 类序列对象,用于访问 vim |List| 类型。 支持 `.locked` 属性,见 |python-.locked|。还支持以下方法: 方法 描述 ~ extend(item) 给列表加入项目 item。 __new__(), __new__(iterable) 用 `vim.List()` 可以建立新的 vim 列表。 `l=vim.List(iterable)` 等价于 `l=vim.bindeval('[]');l.extend(iterable)`。无参数的版 本方法构建空列表。 示例: > l = vim.List("abc") # 构造函数,返回: ['a', 'b', 'c'] l.extend(['abc', 'def']) # .extend() 方法 print l[1:] # 分片 (slicing) l[:0] = ['ghi', 'jkl'] # 分片赋值 print l[0] # 读取项目 l[0] = 'mno' # 赋值 for i in l: # 遍历 print isinstance(l, vim.List) # True class List(vim.List): # 子类 vim.Function 对象 *python-Function* 类函数对象,相当于 vim |Funcref| 对象。接受特殊关键字参数 `self`,见 |Dictionary-function|。也可用 `vim.Function(name)` 构造函数,等价于 `vim.bindeval('function(%s)'%json.dumps(name))`。 属性 (只读): 属性 描述 ~ name 函数名。 args `None` 或用作参数的 |python-List| 对象。注意 这是参数列表 的备份,每次请求参属性时都会重新构建。列表的修改被忽略 ( 但不适用于参数列表里的容器: 类似于 |copy()| 而不是 |deepcopy()|)。 self `None` 或用作 self 字典的 |python-Dictionary| 对象。注意 调用函数对象时显式的 `self` 参数覆盖此属性。 auto_rebind 布尔值。如果为真,此 Python 对象建立和在 Vim 脚本里存贮的 字典里的的偏函数会在此字典被访问时自动重新绑定此字典。这 体现了 Vim 内部 `dict.func` (auto_rebind=True) 和 `function(dict.func,dict)` (auto_rebind=False) 的差异。 如果 `self` 属性为 `None`,此属性无意义。 构造函数额外接受 `args``self``auto_rebind` 关键字。如果给出 `args` 和/或 `self` 参数,构造偏函数,见 |function()|。只有给定 `self` 时才使用 `auto_rebind`,否则无论是否给出,总是假定为 `True`。如果给出 `self`,缺省 为 `False`。 示例: > f = vim.Function('tr') # 构造函数 print f('abc', 'a', 'b') # 调用 tr('abc', 'a', 'b') vim.command(''' function DictFun() dict return self endfunction ''') f = vim.bindeval('function("DictFun")') print f(self={}) # 相当于 call('DictFun', [], {}) print isinstance(f, vim.Function) # True p = vim.Function('DictFun', self={}) print f() p = vim.Function('tr', args=['abc', 'a']) print f('b') ============================================================================== 8. pyeval() 和 py3eval() Vim 函数 *python-pyeval* 为了访问双向接口的方便,可用 |pyeval()||py3eval()| 函数来计算 Python 表达 式然后返回计算结果给 Vim 脚本。也可用 |pyxeval()|============================================================================== 9. 动态调入 *python-dynamic* MS-Windows 和 Unix 上,可以动态调入 Python 库。|:version| 输出这时应包括 |+python/dyn||+python3/dyn|。 这意味着 Vim 只有在必要时才寻找 Python DLL 文件或共享库。如果不使用 Python 接 口,你就不需要它。这样,即使没有该文件,你也可使用 Vim。 MS-Windows ~ 要使用 Python 接口,Python DLL 必须在搜索路径上。控制台窗口里输入 "path" 可以 看到 (搜索路径) 当前使用的目录。也可用 'pythondll''pythonthreedll' 选项来 指定 Python DLL。 DLL 的名字应该匹配 Vim 编译时所使用的 Python 版本。目前,用于 Python 2 的名字 为 "python27.dll",也就是 Python 2.7。用于 Python 3 的是 python35.dll (Python 3.5)。要确信这一点,编辑 "gvim.exe" 文件并查找 "python\d*.dll\c"。 Unix ~ 'pythondll''pythonthreedll' 选项可用来指定 Python 共享库文件,而不用编译时 指定的 DYNAMIC_PYTHON_DLL 或 DYNAMIC_PYTHON3_DLL 文件。共享库的版本必须和 Vim 编译使用的 Python 2.x 或 Python 3 版本保持一致。 ============================================================================== 10. Python 3 *python3* *:py3* *:python3* `:py3``:python3` 命令和 `:python` 类似。判断 `:py3` 命令是否可用的一个简单 检查: > :py3 print("Hello") 要看运行的 Python 版本: > :py3 import sys :py3 print(sys.version) < *:py3file* `:py3file` 命令和 `:pyfile` 类似。 *:py3do* `:py3do` 命令和 `:pydo` 类似。 Vim 可以用四种方式编译 (:version 输出结果): 1. 无 Python 支持 (-python、-python3) 2. 只有 Python 2 支持 (+python 或 +python/dyn、-python3) 3. 只有 Python 3 支持 (-python、+python3 或 +python3/dyn) 4. Python 2 和 3 支持 (+python/dyn、+python3/dyn) 关于第四种特殊情况的更多细节: *python-2-and-3* 要同时支持 Python 2 和 Python 3,两者必须都是动态载入。 在 Linux/Unix 系统上用这种方式并导入全局符号的时候,使用第二个 Python 版本会导 致系统崩溃。所以,要么载入全局符号但只激活一个 Python 版本,要么考虑不载入全局 符号。后者使 Python 导入 ("import") 某些期待 Vim 提供某些符号的库的时候会失 败。 *E836* *E837* Vim 的配置脚本根据一个特定的 Python 标准库 (termios) 对所有的库进行猜测。如果 对两个 Python 版本导入该库均成功,那么可以在 Vim 中同时使用两者。否则在一个会 话中,只允许使用先用到的版本。使用第二个版本会得到 E836 或 E837 的错误信息。 这里 Vim 的行为取决于配置所在的系统。如果两个 Python 版本都用了 --enable-shared 进行配置,两者会同时激活。但没有链接进 libPython 的第三方库仍 然会有问题。 要回避这些问题,有以下几个方案: 1. 重新编译有问题的库,把它链接进相应的 libpython.so 里。 2. 重新编译 Vim,只用一个 Python 版本。 3. 配置完后,撤销 auto/config.h 中 PY_NO_RTLD_GLOBAL 的定义。这可能会使 Vim 崩 溃。 *E880* 从 python 抛出 SystemExit 例外不是退出 vim 的好方法,要用: > :py vim.command("qall!") < *has-python* 以下方法可用来测试哪个 Python 版本可用: > if has('python') echo '有 Python 2.x' elseif has('python3') echo '有 Python 3.x' endif 注意 不过,当 Python 2 和 3 同时存在且都是动态载入,这些 has() 调用会试图载入 它们。如果两个版本不能同时载入,单单对 Python 2 或 3 是否可用的检查就会导致另 一个版本不能调入。 ============================================================================== 11. Python X *python_x* *pythonx* 大多数 python 代码可以用 python 2.6+ 和 python 3 兼容的方式编写,因而我们提供 了 pyx+ 函数和命令。其工作方式和 Python 2 和 3 变种完全相同,但根据 'pyxversion' 设置选择 Python 版本。 应在 |.vimrc| 中设置 'pyxversion',可为 Python 命令选择 Python 2 或 Python 3。 如果在运行时改变此设置,可能会冒丢失插件状态 (如初始化) 的风险。 要用的模块可放在 {rtp}/pythonx 目录里。见 |pythonx-directory|*:pyx* *:pythonx* `:pyx``:pythonx` 命令的工作方式类似于 `:python`。要看 `:pyx` 命令是否可用 的简单检查: > :pyx print("Hello") 要看运行的 Python 版本: > :pyx import sys :pyx print(sys.version) < *:pyxfile* *python_x-special-comments* `:pyxfile` 命令的工作方式类似于 `:pyfile`。不过你可以加上以下注释之一强制 Vim 使用 `:pyfile``:py3file`: > #!/任何字符串/python2 " Shebang。必须是文件的首行。 #!/任何字符串/python3 " Shebang。必须是文件的首行。 # requires python 2.x " 最大行数取决于 'modelines'。 # requires python 3.x " 最大行数取决于 'modelines'。 和普通模式行不同,不检查文件尾部。如果找不到这样注释,使用 'pyxversion' 设置。 *W20* *W21* 如果 Vim 不支持所选的 Python 版本,安静地打印一行消息。用 `:messages` 可读该消 息。 *:pyxdo* `:pyxdo` 命令的工作方式类似于 `:pydo`*has-pythonx* 可以这样测试 pyx* 系列命令是否可用: > if has('pythonx') echo 'pyx* 命令可用. (Python ' . &pyx . ')' endif 如果编译时只有 |+python||+python3| 之一,has() 返回 1。 如果编译时 |+python||+python3| 两者兼有,测试结果取决于 'pyxversion' 设 置。如果 'pyxversion' 为 0,先测试 Python 3,如果不可用再测试 Python 2。如果 'pyxversion' 为 2 或 3,只测试对应的 Python 2 或 3。 注意 为了使 `has('pythonx')` 能工作,可能会试图动态载入 Python 3 或 2。这可能 有副作用,尤其是 Vim 只能载入两者之一的时候。 如果用户希望首选 Python 2 而使用 Python 3 作后备,需要在 |.vimrc| 里显式设置 'pyxversion'。例如: > if has('python') set pyx=2 elseif has('python3') set pyx=3 endif ============================================================================== 12. 编译时带 Python 支持 *python-building* 编译时带 Python 2 或 3 支持的若干提示。 UNIX 关于如何打开 Python 接口的支持,见 src/Makefile。 Ubuntu 上需要为 Python 2 安装以下包: python python-dev Python 3: python3 pytyon3-dev Python 3.6: python3.6 pytyon3.6-dev 如果有多于一个 Python 3 版本,在运行 configure 前链接 python3 到你选择的那 个版本。 ==============================================================================