2014-05-11 36 views
4

的Python 3.4提供了這個整齊的工具暫時將stdout:Python中暫時改變一個變量的值

# From https://docs.python.org/3.4/library/contextlib.html#contextlib.redirect_stdout 
with redirect_stdout(sys.stderr): 
    help(pow) 

The code不是超級複雜,但我不想把它一遍又一遍寫,尤其是因爲有些人認爲已經進入了它,使其重入:

class redirect_stdout: 
    def __init__(self, new_target): 
     self._new_target = new_target 
     # We use a list of old targets to make this CM re-entrant 
     self._old_targets = [] 

    def __enter__(self): 
     self._old_targets.append(sys.stdout) 
     sys.stdout = self._new_target 
     return self._new_target 

    def __exit__(self, exctype, excinst, exctb): 
     sys.stdout = self._old_targets.pop() 

我不知道是否有使用with語句來臨時更改變量的值的一般方法。來自sys的兩個其他使用案例是sys.stderrsys.excepthook

在一個完美的世界裏,像這樣的工作:

foo = 10 
with 20 as foo: 
    print(foo) # 20 
print (foo) # 10 

我懷疑我們可以作出這樣的工作,但也許這樣的事情是可能的:

foo = 10 
with temporary_set('foo', 20): 
    print(foo) # 20 
print (foo) # 10 

我可以排序得到的這項工作在globals()左右,但沒有人會選擇使用。

更新:雖然我認爲我的「foo = 10」示例說明了我正在嘗試執行的操作,但它們並未傳達實際用例。這裏有兩個:

  1. 重定向標準錯誤,就像redirect_stdout
  2. 臨時更改sys.excepthook。我以交互方式進行了大量開發,並且當我爲excepthook添加了某些東西時(通過將原始函數包裝在我自己的某個函數中,比如說使用日誌記錄模塊來記錄異常),我通常希望它在某個時候被刪除。這樣我就不會有越來越多的函數包裝自己了。 This question面臨一個密切相關的問題。
+0

你能激勵這樣一個成語嗎?它會在哪種情況下有用? –

回答

1

closure怎麼樣?

#!/usr/bin/python 

def create_closure(arg): 
    var = arg 

    def hide_me(): 
     return var 

    return hide_me 


x = 10 
clo = create_closure(x) 

x *= 2 
x2 = clo() 
x += 1 

print "x: {0}".format(x) 
print "x2: {0}".format(x2) 

這產生了:

x: 21 
x2: 10 

而且,由於這是一種封閉件,它可以被基本上擴展到保持一大堆其他變量和狀態的,然後或者純粹用於在未來的封閉形式中,或者在完成後用作恢復狀態的板岩。

+0

有趣。 @arshajii表示,封閉是如何實現的,你無法用臨時變量來做到這一點?換句話說,不是'clo = create_closure(x)'而只是設置'tmp = x'? – kuzzooroo

+0

好吧,作爲一個閉包,它具有可以隨處傳播的優點:通過其他函數,範圍等,它將始終具有該價值。如果不僅僅用於簡單的int,它可能更有用。即存儲一個包含多個不同變量,結構等的狀態。您還可以爲不同的值集創建多於一個的值,這在將屬性存儲在不同的點和具有該屬性的事物時可能會派上用場。 (我上面的示例是爲了說明一般概念而設計的。) – khampson

+0

想象一下,包含代表狀態的10個不同變量的閉包,並且表示您想要在應用程序中有4組不同的點代表不同的點。你可以在任何時候回想那些東西,將它們傳遞出去,將它們存儲在一個由時間或其他東西所控制的字典中,等等。所有這些都比一些單獨聲明的局部變量更加富有表現力和更容易被追蹤。封閉本質上是這種使用類型的堆棧框架。 – khampson

5

我知道這個問題是慈祥的老人,但是我走過來了同樣的問題,這裏是我的解決方案:

class test_context_manager(): 
    def __init__(self, old_object, new_object): 
     self.new = new_object 
     self.old = old_object 
     self.old_code = eval(old_object) 
    def __enter__(self): 
     globals()[self.old] = self.new 
    def __exit__(self, type, value, traceback): 
     globals()[self.old] = self.old_code 

,因爲它使大量使用全局變量它不漂亮,但它似乎工作。

例如:

x = 5 
print(x) 
with test_context_manager("x", 7): 
    print(x) 

print(x) 

結果:

5 
7 
5 

或具有功能:

def func1(): 
    print("hi") 

def func2(): 
    print("bye") 

x = 5 
func1() 
with test_context_manager("func1", func2): 
    func1() 

func1() 

結果:

hi 
bye 
hi 
+0

不錯。我認爲如果你使用'exec(「{} = {}」.format(self.old,repr(self.new)),globals())',你可以得到更一般的東西。有了這個改變,我也可以處理字符串。 – kuzzooroo

+0

不錯。這是一個有用的補充。我只用函數和整數對它進行了測試。 – arthaigo

+0

通過徹底擺脫exec,現在更加通用。現在,可以傳遞任意的次要對象。 – arthaigo

相關問題