通过TKinter使用[时钟格式]改变proc如何返回""

Stu*_*art 0 python tkinter tcl type-conversion

我正在使用TKinter从Python访问现有的Tcl库.其中一个Tcl过程在列表中查找值,如果未找到该值则返回"".Python代码将返回值视为unicode,并检查它是否等于"".这完全有效,直到在Tcl代码中调用[时钟格式].之后,Python代码将返回值视为元组.我可以为Python代码添加一些额外的逻辑来处理这个问题,但似乎有一些更大的问题正在发生,可能会产生其他影响.

示例Python程序:

import Tkinter

_tclsh = Tkinter.Tcl()

_tclsh.eval('proc returnBlank { } { return "" }')
_tclsh.eval('proc returnNotBlank { } { return "not blank" }')

print "Before calling clock"
_tclsh.eval('set shouldBeBlank [returnBlank]')
shouldBeBlank = _tclsh.getvar('shouldBeBlank')
print "shouldBeBlank is ", shouldBeBlank, " with type ", type(shouldBeBlank)

_tclsh.eval('set shouldNotBeBlank [returnNotBlank]')
shouldNotBeBlank = _tclsh.getvar('shouldNotBeBlank')
print "shouldNotBeBlank is ", shouldNotBeBlank, " with type ", type(shouldNotBeBlank)

print "\nCalling [clock seconds]"
_tclsh.eval('puts [clock seconds]')
_tclsh.eval('set shouldBeBlank [returnBlank]')
shouldBeBlank = _tclsh.getvar('shouldBeBlank')
print "shouldBeBlank is ", shouldBeBlank, " with type ", type(shouldBeBlank)

_tclsh.eval('set shouldNotBeBlank [returnNotBlank]')
shouldNotBeBlank = _tclsh.getvar('shouldNotBeBlank')
print "shouldNotBeBlank is ", shouldNotBeBlank, " with type ", type(shouldNotBeBlank)

print "\nCalling [clock format [clock seconds]]"
_tclsh.eval('puts [clock format [clock seconds]]')
_tclsh.eval('set shouldBeBlank [returnBlank]')
shouldBeBlank = _tclsh.getvar('shouldBeBlank')
print "shouldBeBlank is ", shouldBeBlank, " with type ", type(shouldBeBlank)

_tclsh.eval('set shouldNotBeBlank [returnNotBlank]')
shouldNotBeBlank = _tclsh.getvar('shouldNotBeBlank')
print "shouldNotBeBlank is ", shouldNotBeBlank, " with type ", type(shouldNotBeBlank)
Run Code Online (Sandbox Code Playgroud)

结果输出是:

Before calling clock
shouldBeBlank is    with type  <type 'unicode'>
shouldNotBeBlank is  not blank  with type  <type 'str'>

Calling [clock seconds]
1431623835
shouldBeBlank is    with type  <type 'unicode'>
shouldNotBeBlank is  not blank  with type  <type 'str'>

Calling [clock format [clock seconds]]
Thu May 14 13:17:15 EDT 2015
shouldBeBlank is  ()  with type  <type 'tuple'>
shouldNotBeBlank is  not blank  with type  <type 'str'>
Run Code Online (Sandbox Code Playgroud)

如您所见,只有空字符串受到影响,并且调用[clock]不会导致问题; 只有[时钟格式].

任何帮助将不胜感激.

注意:我尝试了不同的方法来返回空字符串,但它们不会影响输出.我试过了:

_tclsh.eval('proc returnBlank { } { return }')
_tclsh.eval('proc returnBlank { } { return {} }')
Run Code Online (Sandbox Code Playgroud)

sch*_*enk 5

这是Tkinter猜测字符串类型的方式的问题.

在Tcl中,空列表或空字符串之间没有任何有意义的区别,因此字节码编译器可以随意更改内部类型,在这种情况下对于Tcl最方便.

Tcl Tcl_Obj在C实现中使用一个结构,它最多可以同时保存两个类型的信息(一个总是字符串,另一个是Tcl解释器的当前视图,具体取决于对象的最后用法).

因此,如果某些代码试图'猜测'Tcl对象的类型,它会执行以下(不可靠)技巧,它会查看Tcl对象的内部值并假设是否设置了类型指针,该对象是类型.

所以看这个:

import Tkinter
tclsh = Tkinter.Tcl()
tclsh.eval('set x ""')
v = tclsh.getvar('x')
print type(v)
tclsh.eval('lindex $x 0')
v = tclsh.getvar('x')
print type(v)
Run Code Online (Sandbox Code Playgroud)

首先是'str',后来是'tuple'.因此,如果您将变量用作列表,会发生这种情况,但为什么它会修改您的procs返回值?

这是因为字节编译时积极的文字共享.空字符串是一个常见的字面值,通常只有一个对象(如Pythons None或小整数).

你可以使用一个小技巧来解决这个问题,如果你真的需要,只需要强制进行类型转换(称为"闪烁",请参阅http://wiki.tcl.tk/3033).

例如,如果要在Tcl中强制使用整数内部表示:

set x "2"
incr x 0
# X now has internal type Integer

lindex $x 0
# X now has internal type tuple

append x ""
# X now has the internal type unicode
Run Code Online (Sandbox Code Playgroud)

等等.当你尝试映射两种语言类型系统时,如果它们差别很大,你会看到DBAPI层中的类似效果,或者尝试通过xmlrpc或json调用函数时,这是一个怪癖.