我经常需要暂时将变量的值替换为其他内容,执行一些依赖于此变量的计算,然后将变量恢复为其原始值。 E.g:
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
功能。实际上这甚至不是一个函数,而是一串代码,它在全局命名空间的上下文中作为一些元编程的一部分进行评估。我给出的例子是我能想到的最简单的例子,它保留了我对临时变量的问题。我没有要求获得我的示例代码的解决方法(正确版本),而是要在我的书面问题上得到答案。
答案 0 :(得分:4)
不,因为上下文管理员无法在调用者的范围内分配变量。 (任何认为您可以使用$ xcode-select --install
$ sudo chown -R (whoami):admin /usr/local
$ sudo xcode-select --reset
$ softwareupdate --install
$ sudo xcodebuild -license
或locals
执行此操作的人,请尝试使用您在函数内部提出的上下文管理器。它无法工作。)
有是实用程序,可以使用不是局部变量的东西,例如模块全局变量,其他对象属性和dicts ...但是它们是{{3及其相关函数,因此在非测试环境中使用它们之前,应该强烈考虑其他替代方法。像"这样的操作暂时修改这个东西,然后恢复它"往往会导致令人困惑的代码,并可能表明你使用了太多的全局状态。
答案 1 :(得分:2)
您问题的简单答案:
Python标准库是否包含任何此类上下文管理器?
是"不,它没有。"
答案 2 :(得分:1)
我的错误,也许是这样的,它不是内置的:
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()作为对本地人的引用,它可能会产生意想不到的后果,反正可能仍然存在。
我根本不建议这样做,但应该有用。