[英]Python alternative assignment when exceptions occur using context manager
[英]Python context manager for temporary variable assignment
我經常需要用別的東西臨時切換一個變量的值,做一些依賴於這個變量的計算,然后將變量恢復到它的原始值。 例如:
var = 0
# Assign temporary value and do computation
var_ori = var
var = 1
do_something_with_var() # Function that reads the module level var variable
# Reassign original value
var = var_ori
這似乎是使用上下文管理器( with
語句)的明顯機會。 Python 標准庫是否包含任何這樣的上下文管理器?
我知道這種事情通常由其他更好的方法處理,而不是臨時更改變量。 然而,我並不是要求明顯的解決方法。
在我的實際工作案例中,我無法更改do_something_with_var
函數。 實際上,這甚至不是一個函數,而是作為元編程的一部分在全局命名空間上下文中求值的一串代碼。 我給出的例子是我能想到的最簡單的例子,它使我的問題與臨時變量有關。 我沒有要求獲得我的示例代碼的解決方法(正確版本),而是要求獲得我書面問題的答案。
不,因為上下文管理器不能像那樣在調用者的范圍內分配變量。 (任何認為您可以使用locals
或inspect
來做的人,請嘗試使用您在函數中提出的上下文管理器。它不會工作。)
有一些實用程序可以處理不是局部變量的事情,例如模塊全局變量、其他對象屬性和字典……但它們是unittest.mock.patch
及其相關函數,因此您應該強烈考慮其他替代方案在非測試環境中使用它們之前。 像“暫時修改這個東西然后恢復它”這樣的操作往往會導致代碼混亂,並且可能表明您使用了過多的全局狀態。
對您問題的簡單回答:
Python 標准庫是否包含任何這樣的上下文管理器?
是“不,沒有。”
我的錯誤,也許是這樣的,它不是內置的:
class ContextTester(object):
"""Initialize context environment and replace variables when completed"""
def __init__(self, locals_reference):
self.prev_local_variables = locals_reference.copy()
self.locals_reference = locals_reference
def __enter__(self):
pass
def __exit__(self, exception_type, exception_value, traceback):
self.locals_reference.update(self.prev_local_variables)
a = 5
def do_some_work():
global a
print(a)
a = 8
print("Before context tester: {}".format(a))
with ContextTester(locals()) as context:
print("In context tester before assignment: {}".format(a))
a = 6
do_some_work()
print("In context tester after assignment: {}".format(a))
print("After context tester: {}".format(a))
輸出:
Before context tester: 5
In context tester before assignment: 5
6
In context tester after assignment: 8
After context tester: 5
為了清楚起見,你知道它實際上在做一些事情:
class ContextTester(object):
"""Initialize context environment and replace variables when completed"""
def __init__(self, locals_reference):
self.prev_local_variables = locals_reference.copy()
self.locals_reference = locals_reference
def __enter__(self):
pass
def __exit__(self, exception_type, exception_value, traceback):
#self.locals_reference.update(self.prev_local_variables)
pass
a = 5
def do_some_work():
global a
print(a)
a = 8
print("Before context tester: {}".format(a))
with ContextTester(locals()) as context:
print("In context tester before assignment: {}".format(a))
a = 6
do_some_work()
print("In context tester after assignment: {}".format(a))
print("After context tester: {}".format(a))
a = 5
print("Before context tester: {}".format(a))
with ContextTester(locals()) as context:
print("In context tester before assignment: {}".format(a))
a = 6
print("In context tester after assignment: {}".format(a))
print("After context tester: {}".format(a))
輸出:
Before context tester: 5
In context tester before assignment: 5
6
In context tester after assignment: 8
After context tester: 8
Before context tester: 5
In context tester before assignment: 5
In context tester after assignment: 6
After context tester: 6
你也可以這樣做:
def wrapper_function(func, *args, **kwargs):
prev_globals = globals().copy()
func(*args, **kwargs)
globals().update(prev_globals)
應該注意的是,如果您嘗試在函數中使用 with 語句,您將希望使用 globals() 作為對局部變量的引用,它可能會產生意想不到的后果,無論如何仍然可能。
我根本不建議這樣做,但應該可行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.