我想用一個同名的過程和調用約定來替換「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