在earlier post我詢問方法,以避免在中間tmp
變量模式,如:可以模擬與上下文管理器的詞法範圍嗎?
tmp = <some operation>
result = tmp[<boolean expression>]
del tmp
...其中tmp
是熊貓對象。例如:
tmp = df.xs('A')['II'] - df.xs('B')['II']
result = tmp[tmp < 0]
del tmp
蜜蜂在我對這個模式引擎蓋主要來自一個嚮往誠實,善良詞法範圍,就不會連經過多年編程的Python死亡。在Python 我湊合着用顯式調用del
,
它發生,我認爲這可能是可以使用上下文管理器模仿詞彙範圍在Python。這將是這個樣子:
with my(df.xs('A')['II'] - df.xs('B')['II']) as tmp:
result = tmp[tmp < 0]
爲了能夠模仿詞彙範圍,上下文管理器類需要有一種方法來del
ETE是被分配返回的值在呼叫範圍內的變量及其(上下文管理器的'輸入'的方法。
例如,對於作弊的大劑量的:
import contextlib as cl
# herein lies the rub...
def deletelexical():
try: del globals()['h']
except: pass
@cl.contextmanager
def my(obj):
try: yield obj
finally: deletelexical()
with my(2+2) as h:
print h
try:
print h
except NameError, e:
print '%s: %s' % (type(e).__name__, e)
# 4
# Name error: name 'h' is not defined
當然,問題是實現deletelexical
真實的。可以做到嗎?
編輯:正如abarnert指出的那樣,如果在周圍的範圍內已經存在tmp
,那麼deletelexical
不會恢復它,因此它很難被看作是詞彙範圍的模擬。正確的實現將不得不保存周圍範圍內的任何現有tmp
變量,並在with語句的末尾替換它們。
例如,在Perl中,我就已經編寫上面的東西,如:
my $result = do {
my $tmp = $df->xs('A')['II'] - $df->xs('B')['II'];
$tmp[$tmp < 0]
};
或在JavaScript:
var result = function() {
var tmp = df.xs('A')['II'] - df.xs('B')['II'];
return tmp[tmp < 0];
}();
編輯:爲響應abarnert的帖子&評論:是的,在Python中可以定義爲
def tmpfn():
tmp = df.xs('A')['II'] - df.xs('B')['II']
return tmp[tmp < 0]
...這確實可以避免使用以後無用的名稱tmp
混淆命名空間,但它是通過將名稱空間與從此無用的名稱tmpfn
混淆而實現的。 JavaScript(以及Perl,BTW等)允許使用匿名函數,而Python不支持。無論如何,我認爲JavaScript的匿名函數是一種有點繁瑣的詞法範圍界定方式;它肯定比沒有好,我使用它很多,但它遠沒有Perl好(後者我的意思不僅僅是Perl的do
聲明,而且還提供了控制範圍的各種其他方式,包括詞法和動態) 。
我不需要提醒大家,只有一小部分Python程序員給出了一個關於詞法範圍的老鼠尾巴。
看起來很像[獲取要在with語句中執行的命令塊](http://stackoverflow.com/q/12485837) – 2013-02-20 20:03:14
我不認爲你可以,至少不是沒有得到深入黑客和實施細節領域,這是不值得的。順便說一句,Python做詞彙範圍確定,你只是想要一個更細緻的方式來引入新的範圍。 – delnan 2013-02-20 20:10:18
首先,在JS中,你只是定義一個本地函數並調用它,它允許你使用本地函數的作用域。你可以在Python中完成同樣的事情。那麼,這有什麼問題?你是否反對賦予這個函數一個名字? – abarnert 2013-02-20 20:10:29