我有一对python函数,目前在两个值之间翻转一个全局变量.我想把它们变成上下文管理器,所以我可以将它们用作with块,在块内设置变量,但之后恢复它.这是所需的行为:
>>> MODE
'user'
>>> mode_sudo() # Sets MODE to 'sudo'...
>>> MODE
'sudo'
>>> mode_user() # Sets MODE to 'user'...
>>> MODE
'user'
>>> with mode_sudo():
... print MODE
'sudo'
>>> MODE
'user'
Run Code Online (Sandbox Code Playgroud)
这样的嵌合体可能吗?
更新:为了清楚起见,这里是仅限上下文管理器的实现:
from contextlib import contextmanager
@contextmanager
def mode_sudo():
global MODE
old_mode = MODE
MODE = 'sudo'
yield
MODE = old_mode
@contextmanager
def mode_user():
global MODE
old_mode = MODE
MODE = 'user'
yield
MODE = old_mode
Run Code Online (Sandbox Code Playgroud)
用关键字调用这些w/oa会返回一个生成器.有没有办法通过普通香草函数调用和巧克力上下文管理器获得模式翻转行为?
我正在尝试使用Python中的with..as contruct来简化"可逆计算"代码的编写.但是,@contextmanager在类方法上使用似乎会更改未来类实例的默认初始化.Python 2.6和3.1具有相同的行为.这是一个展示此行为的简单示例:
#!/usr/bin/env python
import contextlib
class SymList:
def __init__(self, L=[]):
self.L = L
@contextlib.contextmanager
def SymAdd(self, a):
self.L.append(a)
yield
self.L.append(a)
SL = SymList()
with SL.SymAdd(3):
SL.L.append(5)
print(SL.L) # Expect and see [3, 5, 3]
SL2 = SymList()
print(SL2.L) # Expect [] and see [3, 5, 3]
Run Code Online (Sandbox Code Playgroud)
SL2一个新的实例SymList?SL2.L数据成员如何引用SL.L数据成员?我一直在玩Python自己的上下文管理器.我看到一些奇怪的行为很可能是由于我的实施.
我看到__exit__在'with'上下文中的语句之前调用的代码.例如,以下是代码段:
with ProgressBar(10) as p:
p.update(1)
Run Code Online (Sandbox Code Playgroud)
这是例外:
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
AttributeError: 'NoneType' object has no attribute 'update'
Run Code Online (Sandbox Code Playgroud)
我把调试中的所有__enter__,__exit__和更新我的上下文管理器的方法.它看起来像是__exit__在update()之前调用的.这没有任何意义所以我必须遗漏一些简单的东西.
这是我的简单上下文管理器类:
class ProgressBar(object):
"""Progress bar that normalizes progress to [0 - 100] scale"""
def __init__(self, max_value):
"""Create progress bar with max_value"""
self._current_value = 0.0
self._completed_value = 100.0
self._max_value = float(max_value)
print 'init', max_value
def __enter__(self):
"""Start of context manager, 'with' statement"""
print 'enter'
self._current_value = …Run Code Online (Sandbox Code Playgroud) 我正在用openPython打开一个文件.我将文件处理封装在一个with语句中:
with open(path, 'r') as f:
# do something with f
# this part might throw an exception
Run Code Online (Sandbox Code Playgroud)
这样我就确定我的文件已关闭,即使抛出了异常.
但是,我想处理打开文件失败的情况(OSError抛出一个).一种方法是将整个with块放在一个try:.只要文件处理代码不引发OSError,这就可以工作.
它可能看起来像:
try:
with open(path, 'rb') as f:
except:
#error handling
# Do something with the file
Run Code Online (Sandbox Code Playgroud)
这当然不起作用,真的很难看.这样做有一种聪明的方法吗?
谢谢
PS:我正在使用python 3.3
我想在exit()方法中再次调用代码对象,如果它引发异常(可能是几次,可能有延迟).我知道装饰器很容易,但我的动机是有时候我想重复一些代码片段,我不想提取到一个单独的函数并装饰它.我正在寻找这些方面的东西:
class again(object):
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is not None:
???? # Invoke the code object again
return True # eat exception
Run Code Online (Sandbox Code Playgroud)
它会像这样使用:
x = 0
with again():
print x
x += 1
if x == 1:
raise Exception('I hate 1')
Run Code Online (Sandbox Code Playgroud)
而预期的产出将是:
0
1
Run Code Online (Sandbox Code Playgroud)
我可以找到一种方法来获取代码对象.没有任何上下文管理器属性似乎引用它(我想这不是真正需要的,因为它的工作只是在前后做事).
有可能吗?
为了说明我的问题,这是一个不使用的基本请求contextlib:
import urllib.request
url = "http://www.example.com/"
with urllib.request.urlopen(url) as response:
raw_data = response.read()
Run Code Online (Sandbox Code Playgroud)
并使用相同的请求contextlib:
import contextlib
import urllib.request
url = "http://www.example.com/"
with contextlib.closing(urllib.request.urlopen(url)) as response:
raw_data = response.read()
Run Code Online (Sandbox Code Playgroud)
据我所知,这两个请求具有相同的结果:检索数据,请求在代码块完成时自动关闭,raw_data即使在请求关闭后也可以访问.在使用请求时urllib.request.urlopen,是否有使用优势contextlib.closing或是多余的?一种方法更像Pythonic和/或更常见吗?
我有一个测试类,需要在最后进行一些清理.为了确保用户不会忘记这样做,我想在类中添加一个上下文管理器.我还有一个装饰器,我想在其中使用此上下文管理器来创建测试类的对象并将其传递给装饰函数.它甚至可能吗?
这就是我要做的事情:
class test:
def __init__(self, name):
self._name = name
print "my name is {0}".format(name)
def exit():
print "exiting"
@contextmanager
def testcm(self):
print "inside cm"
try:
yield self
finally:
self.exit()
def randomtest(self, str):
print "Inside random test {0}".format(str)
def decorate(name):
def wrapper(testf):
def testf_wrapper(test):
with test(name).testcm() as testobj:
return testf(testobj)
return testf_wrapper
return wrapper
return decorate
@decorate("whatever")
def testf(testobj):
testobj.randomtest("randomness")
Run Code Online (Sandbox Code Playgroud)
该函数testf接受测试类对象 - testobj并用它做事.之后,由于上下文管理器,testcm确保调用清理函数.
所以有两个问题:
我如何在装饰器中使用上下文管理器,从我所知的装饰器必须返回一个函数,但如果我返回该函数(如上面的代码),上下文管理器将如何调用清理?
如何将装饰器中创建的对象传递给装饰函数,如果我像上面的代码一样传递它,我将如何调用装饰函数?
尝试在Python中打开文件的行为会引发异常。如果我使用with语句打开文件,是否可以捕获open调用和相关__enter__调用引发的异常而又不捕获with块中代码引发的异常?
try:
with open("some_file.txt") as infile:
print("Pretend I have a bunch of lines here and don't want the `except` below to apply to them")
# ...a bunch more lines of code here...
except IOError as ioe:
print("Error opening the file:", ioe)
# ...do something smart here...
Run Code Online (Sandbox Code Playgroud)
I have the following code
from contextlib import contextmanager
@contextmanager
def simple_context_manager():
print("starting context manager")
yield
print("finished context manager")
try:
with simple_context_manager():
raise RuntimeError
except RuntimeError:
print("Caught the error")
print("Moving on")
Run Code Online (Sandbox Code Playgroud)
Right now it prints out
starting context manager
Caught the error
Moving on
Run Code Online (Sandbox Code Playgroud)
which tells me that the context manager isn't closing. How can I get it to close and print the "finished context manager" line?
Since I'm using the decorator, I don't have a dedicated __exit__ function that …