2011-05-24 50 views
4

我想用一个同名的过程和调用约定来替换“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) 

回答

4

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的回答是更接近我怎么会常换一个命令,它的优点也可以使用非过程命令 - 但这种解决方案的优点是可以很好地绑定代码,这样以后就不会出错了。它也不会在任何错误跟踪中引入额外的堆栈帧,这有助于简化调试。

+0

有关Tcl的'error'与Python的'exit''的注释同样适用于Eric的答案,但应该注意的是,在Tcl中使用'error'(或'return -code error')是惯用的,而让代码吹这个过程不是非常睦邻的理由。 – 2011-05-24 19:30:42

+0

在你的第二个“它有优势”的时候,目前还不清楚你是在谈论埃里克的答案还是你自己的答案。 – bukzor 2011-05-24 21:07:50

+0

您的方法的一个缺点是,它会让您在原始过程中从新注入的代码中“污染”。例如,如果'wrapper'中的东西创建了新的变量,那么原始代码就会看到这些变量,这可能会导致意外的行为和非常棘手的错误。我的方法可以保护您免受这种风险。 – 2011-05-25 04:57:54

10

可以使用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

+1:'error“arg1不好”“可能是更直接的翻译,而不是单独的'puts'和'exit'命令。 – 2011-05-24 18:23:22

+1

@glenn:或许,尽管可以捕获[error],但Python exit命令afaik无条件退出解释器,所以语义有点不同。 – 2011-05-24 18:26:17

+1

+1:几个注释:8.6有'tailcall',它可以让你将最后一行改写为'tailcall __orig_N $ arg1 $ arg2',以便从调用堆栈中获得更完整的elision,并且**非常重要重命名跨命名空间边界的过程或解析范围更改。 (男孩,我*讨厌*那个特殊的错误特征!) – 2011-05-24 19:27:07