Python 3.4提供了这个简洁的工具来临时重定向stdout:
# 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.stderr
和sys.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"例子澄清了我试图做的事情,他们没有传达实际的用例。这是两个:
答案 0 :(得分:6)
我知道这个问题有点陈旧,但当我遇到同样的问题时,这是我的解决方案:
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
答案 1 :(得分:2)
我通常使用这个自定义的 attr_as
上下文管理器:
from contextlib import contextmanager
@contextmanager
def attr_as(obj, field:str, value) -> None:
old_value = getattr(obj, field)
setattr(obj, field, value)
yield
setattr(obj, field, old_value)
然后,您可以将它与在 setattr
中用于 attr_as
的参数集完全相同。
class Foo:
def __init__(self):
self.x = 1
foo = Foo()
with attr_as(foo, 'x', 2):
print(foo.x)
bar = 3
with attr_as(sys.modules[__name__], 'bar', 4):
print(bar)
请注意,如果您需要保留属性的存在/不存在而不仅仅是值,也可以多加几行:
from contextlib import contextmanager
@contextmanager
def attr_as(obj, field:str, value) -> None:
old_exists = hasattr(obj, field)
if old_exists:
old_value = getattr(obj, field)
setattr(obj, field, value)
yield
if old_exists:
setattr(obj, field, old_value)
else:
delattr(obj, field)
答案 2 :(得分: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
由于这是一个闭包,它可以大大扩展以保留一大堆其他变量和状态,然后或者纯粹以封闭形式继续使用,或者用作以后恢复状态的平板你已经完成了。
答案 3 :(得分:1)
以@arthaigo的答案为基础, 一个更简洁的版本是:
float oy_plus_oz = orientation.y + orientation.z;
float cos_oy_plus_oz = cos(oy_plus_oz);
float ox_plus_oy_plus_oz = orientation.x + oy_plus_oz;
float ox_minus_oy_plus_oz = orientation.x - oy_plus_oz;
float oy_minus_oz = orientation.y - orientation.z;
float ox_plus_oy_minus_oz = orientation.x + oy_minus_oz;
float ox_minus_oy_minus_oz = orientation.x - oy_minus_oz;
float cos_ox_plus_oy_plus_oz = cos(ox_plus_oy_plus_oz);
float cos_ox_minus_oy_plus_oz = cos(ox_minus_oy_plus_oz);
float two_mult_sx = 2 * scale.x;
float cos_oy_minus_oz = cos(oy_minus_oz);
float cos_ox_plus_oy_minus_oz = cos(ox_plus_oy_minus_oz);
float cos_ox_minus_oy_minus_oz = cos(ox_minus_oy_minus_oz);
float ox_plus_oy = orientation.x + orientation.y;
float ox_minus_oy = orientation.x - orientation.y;
float cos_ox_plus_oy = cos(ox_plus_oy);
float cos_ox_minus_oy = cos(ox_minus_oy);
答案 4 :(得分:0)
我刚刚找到了另一种聪明的方法,使用here中记载的unittest.mock
。
这很笼统,因为可以指定包含许多变量的字典:
import unittest.mock
a = b = 1
with unittest.mock.patch.dict(locals(), a=2, b=3):
print(a, b) # shows 2, 3
print(a, b) # shows 1, 1
即使在当前作用域中先前未定义变量,它也可以工作。
with unittest.mock.patch.dict(locals(), c=4):
assert 'c' in locals()
assert 'c' not in locals()