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

Posted

技术标签:

【中文标题】从 Python 运行 TCL 代码(在现有的 TCL shell 上)【英文标题】:Running TCL code (on an existing TCL shell) from Python 【发布时间】:2015-09-13 12:48:37 【问题描述】:

简介

我最近开始在 Linux 下开发一个遗留产品,它包含一个内置的 TCL shell。由于公司限制,我无法控制“幕后”,我可以编写的所有代码都必须在这个 TCL shell 下运行,处理产品的预定义笨拙的 TCL API。

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

问题

鉴于产品已经一个现有的 TCL shell在其中,我浏览过的大多数解决方案(例如 Tkinter)都不能用于从 Python 运行 TCL 代码。我需要将代码“注入”到现有的 shell。

考虑的解决方案

作为一种解决方案,我考虑在 TCL 端建立一个简单的服务器,该服务器运行从 Python 端接收的简单命令。我写了一个小演示,它工作。这使我能够在 Python 中为笨拙的 TCL API 编写一个不错的、基于类的包装器,还可以管理命令队列等。

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

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

提前致谢。

【问题讨论】:

quickdraw.py is a code example where Python function calls are automatically translated into quickdraw commands and piped into the corresponding java process。关键是the rest of the Python code 不需要知道有一个 java 子进程涉及。套接字比管道更强大、更便携(即使在 Windows 上,套接字也可以与 select() 一起使用),尽管在某些情况下管道可能更简单。 pexpect 或许 如果您拥有的 Tcl shell 支持偶数循环,您可以简单地使用 Tcllib comm 包将 python tkinter.Tcl() 解释器与 Tcl shell 连接并通过 TCP/IP 发送命令。之后只需将 tkinter 包装器包装在您的 Python 代码中即可完成。 (请参阅core.tcl.tk/tcllib/doc/trunk/embedded/www/tcllib/files/modules/…,如果您愿意,也记录了有线协议) 【参考方案1】:

首先: 如果你只是想要一个基于类的 OO 系统来编写你的代码,你不需要 python,Tcl 可以做 OO 就好了。 (内置于 8.6,但在旧版本中也有很多选项可以获取 OO 功能、类等,例如 Tcllibs SNIT 或 STOOOP

如果您仍然觉得 Python 是手头任务的最佳工具(例如,由于对某些任务有更好的库支持),您可以使用 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

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

【讨论】:

谢谢!第一行 (set srv [::comm:comm]) 中没有错误,因为 ::comm::comm 需要一个参数,而您并没有真正使用 srv,还是我遗漏了什么?

以上是关于从 Python 运行 TCL 代码(在现有的 TCL shell 上)的主要内容,如果未能解决你的问题,请参考以下文章

在现有的vagrant box上添加端口转发

在现有的 webapp 中集成 BIRT

使用 Python 在现有的 excel 文件中修改和写入数据

如何使用 Pandas 在现有的 excel 文件中保存新工作表?

如何在python中使用pandas在现有的excel工作表中追加列

在现有的 tableview 中使用 Objective-C 实现 UISearchController