运行 来自 Python 的 TCL 代码(在现有 TCL shell 上)

Running TCL code (on an existing TCL shell) from Python

简介

我最近开始研究 Linux 下的遗留产品,它包含内置 TCL shell。由于公司限制,我无法控制"behind the scenes",我能写的所有代码都必须在这个TCLshell下运行,处理预定义的笨拙TCLAPI 的产品。

我发现自己好几次想知道是否可以将一些 Python 修补到此设置中,因为某些解决方案在 Python 中似乎比在 TCL 中更合法。通过修补 Python 我的意思是:要么从 TCL 代码本身调用 Python 代码(例如,可以使用 Elmer 完成),要么使用 Python 从产品外部包装 TCL API(对此我找不到 "classic" 解决方案)。

问题

鉴于该产品已经 现有的 TCL shell ,我浏览了大多数解决方案(例如 Tkinter) 不能用于 运行 来自 Python 的 TCL 代码。我需要 "inject" 代码到现有的 shell.

考虑的解决方案

作为解决方案,我考虑在 TCL 端启动一个简单的服务器,它从 Python 端接收 运行s 简单命令。我写了一个小演示,它起作用了。这使我能够在 Python 中为笨拙的 TCL API 编写一个基于 class 的包装器,还可以管理命令队列等

我想到的另外两个解决方案是从 Python 派生软件并使用 read/write 文件描述符或通过 FIFO 而不是套接字连接。

但是,我想知道我是否真的做对了,或者您能提出更好的解决方案吗?

提前致谢。

首先: 如果你只是想要一个基于 class 的 OO 系统来编写你的代码,你不需要 python,Tcl 可以很好地实现 OO。 (内置于 8.6,但有很多选项可以获得 OO 功能,classes 等在旧版本中也是如此,例如 Tcllibs SNIT or STOOOP

如果您仍然觉得 Python 是完成手头任务的最佳工具(例如,由于对某些任务有更好的库支持),您可以 'remote control' 使用 Tcllib 通讯包的 Tcl 解释器.这需要在你想要控制的 Tcl shell 中有一个有效的事件循环,否则它很容易做到。

在您的 Tcl shell 中,安装 Tcllib 通讯包。 (再次询问您是否需要帮助)

完成后,在 Tcl 中启动通信服务器 shell。

package require comm
set id [::comm::comm self]
# write ID to a file
set fd [open idfile.txt w]
puts $fd $id
close $fd
proc stop_server {} {set ::forever 1 }
# enter the event loop
vwait forever

在 python 方面,您做的几乎相同,只是在 Tkinter 代码中。

基本上是这样的:

import Tkinter
interp = Tkinter.Tcl()
interp.eval('package require comm')

# load the id
with open('idfile.txt') as fd:
    comm_id = fd.read().strip()

result = interp.eval(
    'comm::comm send {0!s} {1!s}'.format(comm_id, '{puts "Hello World"}')

使用那个 python 代码和你的 shell,你应该会看到 Hello World 打印在你的 shell 中。

阅读 comm 手册以获取更多详细信息,如何保护事物、获取回调等。comm

如果您不喜欢 tkinter 的负担,您也可以为 comm 实现有线协议,在 Twisted 中或使用 Python 3.x 中新的异步支持应该不会太难。 在线协议记录在: comm wire protocol