簡體   English   中英

用於臨時變量賦值的 Python 上下文管理器

[英]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函數。 實際上,這甚至不是一個函數,而是作為元編程的一部分在全局命名空間上下文中求值的一串代碼。 我給出的例子是我能想到的最簡單的例子,它使我的問題與臨時變量有關。 我沒有要求獲得我的示例代碼的解決方法(正確版本),而是要求獲得我書面問題的答案。

不,因為上下文管理器不能像那樣在調用者的范圍內分配變量。 (任何認為您可以使用localsinspect來做的人,請嘗試使用您在函數中提出的上下文管理器。它不會工作。)

一些實用程序可以處理不是局部變量的事情,例如模塊全局變量、其他對象屬性和字典……但它們是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM