我想用一个同名的过程和调用约定来替换“proc N”的定义,但只需要一些额外的错误检测代码。tcl:包装一个相同名称的过程
在python中,我可以在下面做我想做的事情,但我没有掌握如何在tcl中使用名称空间和函数句柄。
__orig_N = N
def N(arg1, arg2):
if arg1 != 'GOOD VALUE':
exit('arg1 is bad')
return __orig_N(arg1, arg2)
我想用一个同名的过程和调用约定来替换“proc N”的定义,但只需要一些额外的错误检测代码。tcl:包装一个相同名称的过程
在python中,我可以在下面做我想做的事情,但我没有掌握如何在tcl中使用名称空间和函数句柄。
__orig_N = N
def N(arg1, arg2):
if arg1 != 'GOOD VALUE':
exit('arg1 is bad')
return __orig_N(arg1, arg2)
Tcl对程序有很好的反省。这使您可以重写的过程中更多的代码添加:
# Assume there are no defaults; defaults make this more complicated...
proc N [info args N] [concat {
# Use 'ne' for string comparison, '!=' for numeric comparison
if {$arg1 ne "GOOD VALUE"} {
error "arg1 is bad"
# The semicolon is _important_ because of the odd semantics of [concat]
};
} [info body N]]
OK,这不是做到这一点的唯一途径 - Eric的回答是更接近我怎么会常换一个命令,它的优点也可以使用非过程命令 - 但这种解决方案的优点是可以很好地绑定代码,这样以后就不会出错了。它也不会在任何错误跟踪中引入额外的堆栈帧,这有助于简化调试。
可以使用rename
命令重命名现有PROC:
rename N __orig_N
proc N {arg1 arg2} {
if { $arg1 != "GOOD_VALUE" } {
puts stderr "arg1 is bad"
exit 1
}
return [uplevel 1 __orig_N $arg1 $arg2]
}
这实际上是一点点比蟒蛇原来更复杂,在使用uplevel
有效地从elides包装整个调用堆栈 - 在你的情况下可能并不需要,但是能够做到这一点很好。
+1:'error“arg1不好”“可能是更直接的翻译,而不是单独的'puts'和'exit'命令。 – 2011-05-24 18:23:22
@glenn:或许,尽管可以捕获[error],但Python exit命令afaik无条件退出解释器,所以语义有点不同。 – 2011-05-24 18:26:17
+1:几个注释:8.6有'tailcall',它可以让你将最后一行改写为'tailcall __orig_N $ arg1 $ arg2',以便从调用堆栈中获得更完整的elision,并且**非常重要重命名跨命名空间边界的过程或解析范围更改。 (男孩,我*讨厌*那个特殊的错误特征!) – 2011-05-24 19:27:07
有关Tcl的'error'与Python的'exit''的注释同样适用于Eric的答案,但应该注意的是,在Tcl中使用'error'(或'return -code error')是惯用的,而让代码吹这个过程不是非常睦邻的理由。 – 2011-05-24 19:30:42
在你的第二个“它有优势”的时候,目前还不清楚你是在谈论埃里克的答案还是你自己的答案。 – bukzor 2011-05-24 21:07:50
您的方法的一个缺点是,它会让您在原始过程中从新注入的代码中“污染”。例如,如果'wrapper'中的东西创建了新的变量,那么原始代码就会看到这些变量,这可能会导致意外的行为和非常棘手的错误。我的方法可以保护您免受这种风险。 – 2011-05-25 04:57:54