2011-05-24 40 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

相關問題