首页 / 知识
Python上下文管理器
2023-11-12 13:33:00
本节严格意义上并非新的重定向方式,而是利用Pyhton上下文管理器优化上节的代码实现。借助于上下文管理器语法,可不必向重定向使用者暴露sys.stdout。
首先考虑输出抑制,基于上下文管理器语法实现如下:
importsys,cStringIO,contextlib
classDummyFile:
defwrite(self,outStr):pass
@contextlib.contextmanager
defMuteStdout():
savedStdout=sys.stdout
sys.stdout=cStringIO.StringIO()#DummyFile()
try:
yield
exceptException:#捕获到错误时,屏显被抑制的输出(该处理并非必需)
content,sys.stdout=sys.stdout,savedStdout
printcontent.getvalue()#;raise
#finally:
sys.stdout=savedStdout
使用示例如下:
withMuteStdout():
print"I'llshowupwhenisexecuted!"#不屏显不写入
raise#屏显上句
print"I'mhidingmyselfsomewhere:)"#不屏显
再考虑更通用的输出重定向:
importos,sys
fromcontextlibimportcontextmanager
@contextmanager
defRedirectStdout(newStdout):
savedStdout,sys.stdout=sys.stdout,newStdout
try:
yield
finally:
sys.stdout=savedStdout
使用示例如下:
defGreeting():print'Hello,boss!'
withopen('out.txt',"w+")asfile:
print"I'mwritingtoyou..."#屏显
withRedirectStdout(file):
print'Ihopethisletterfindsyouwell!'#写入文件
print'Checkyourmailbox.'#屏显
withopen(os.devnull,"w+")asfile,RedirectStdout(file):
Greeting()#不屏显不写入
print'Ideserveapayraise:)'#不屏显不写入
print'DidyouhearwhatIsaid?'#屏显
可见,with内嵌块里的函数和print语句输出均被重定向。注意,上述示例不是线程安全的,主要适用于单线程。
当函数被频繁调用时,建议使用装饰器包装该函数。这样,仅需修改该函数定义,而无需在每次调用该函数时使用with语句包裹。示例如下:
importsys,cStringIO,functools
defMuteStdout(retCache=False):
defdecorator(func):
@functools.wraps(func)
defwrapper(*args,**kwargs):
savedStdout=sys.stdout
sys.stdout=cStringIO.StringIO()
try:
ret=func(*args,**kwargs)
ifretCache==True:
ret=sys.stdout.getvalue().strip()
finally:
sys.stdout=savedStdout
returnret
returnwrapper
returndecorator
若装饰器MuteStdout的参数retCache为真,外部调用func()函数时将返回该函数内部print输出的内容(可供屏显);若retCache为假,外部调用func()函数时将返回该函数的返回值(抑制输出)。
MuteStdout装饰器使用示例如下:
@MuteStdout(True)
defExclaim():print'Iamproudofmyself!'
@MuteStdout()
defMumble():print'Ilackconfidence...';return'sad'
printExclaim(),Exclaim.__name__#屏显'Iamproudofmyself!Exclaim'
printMumble(),Mumble.__name__#屏显'sadMumble'
在所有线程中,被装饰函数执行期间,sys.stdout都会被MuteStdout装饰器劫持。而且,函数一经装饰便无法移除装饰。因此,使用该装饰器时应慎重考虑场景。
接着,考虑创建RedirectStdout装饰器:
defRedirectStdout(newStdout=sys.stdout):
defdecorator(func):
defwrapper(*args,**kwargs):
savedStdout,sys.stdout=sys.stdout,newStdout
try:
returnfunc(*args,**kwargs)
finally:
sys.stdout=savedStdout
returnwrapper
returndecorator
使用示例如下:
file=open('out.txt',"w+")
@RedirectStdout(file)
defFunNoArg():print'Noargument.'
@RedirectStdout(file)
defFunOneArg(a):print'Oneargument:',a
defFunTwoArg(a,b):print'Twoarguments:%s,%s'%(a,b)
FunNoArg()#写文件'Noargument.'
FunOneArg(1984)#写文件'Oneargument:1984'
RedirectStdout()(FunTwoArg)(10,29)#屏显'Twoarguments:10,29'
printFunNoArg.__name__#屏显'wrapper'(应显示'FunNoArg')
file.close()
注意FunTwoArg()函数的定义和调用与其他函数的不同,这是两种等效的语法。此外,RedirectStdout装饰器的最内层函数wrapper()未使用"functools.wraps(func)"修饰,会丢失被装饰函数原有的特殊属性(如函数名、文档字符串等)。
以上内容为大家介绍了Python上下文管理器,希望对大家有所帮助,如果想要了解更多Python相关知识,请关注我们
最新内容
相关内容
为何你的Python代码应是扁平与稀疏
为何你的Python代码应是扁平与稀疏的,代码,培训,信息,观察,设计,工具,嵌套,闻闻,程序员,沉思,Python之禅之所以得名,正是由于它那简明扼要的规Python可执行文件和模块
Python可执行文件和模块,标准,培训,模块,文件,属性,上面,内容,变量,函数,源码,python源代码文件按照功能可以分为两种类型:用于执行的可执行程Python重命名和删除文件
Python重命名和删除文件,培训,文件,方法,文件名,语法,模块,例子,参数,以上,两个,python的os模块提供了帮你执行文件处理操作的方法,比如重命名Python基础之numpy中的常见函数有
Python基础之numpy中的常见函数有哪些,数组,基础,培训,元素,方向,矩阵,函数,乘积,维度,索引,有些Python小白对numpy中的常见函数不太了解,今天python怎么使用文件夹下的脚本?
python怎么使用文件夹下的脚本?,工作,培训,文件夹,脚本,文件,所在,方法,示例,路径,以上,python中使用文件夹下脚本的方法:将当前的工作目录(即python的三角函数在哪?
python的三角函数在哪?,标准,培训,函数,反函数,方法,下面,以上,更多,内容,python中的三角函数在python的标准库math中,math已经包含在你的标python如何调用另一个文件夹中的内
python如何调用另一个文件夹中的内容?,系统,培训,文件,模块,内容,路径,函数,所在,前缀,语句,python中调用另外一个文件夹中的内容:1、同一文件python中函数怎么表示?
python中函数怎么表示?,名称,标准,培训,代码,函数,圆括号,字符串,表达式,选择性,自变量,python中函数定义规则:·函数代码块以def关键词开头,后python有函数重载吗?
python有函数重载吗?,情况,代码,设计,名字,培训,函数,参数,功能,类型,两个,python中没有函数重载。为了考虑为什么python不提供函数重载,首先python中怎么读取doxc文件?
python中怎么读取doxc文件?,培训,文档,文件,路径,命令,以上,更多,内容,python中可以使用python-docx库读取doxc文件,我们可以使用pipinstallpython如何删除某个目录文件夹?
python如何删除某个目录文件夹?,名字,代码,培训,文件夹,方法,文件,目录,语法,路径,格式,python删除某个目录文件夹及文件的方法:#!/usr/bin/enpython map()函数怎么用?
python map()函数怎么用?,培训,函数,序列,列表,参数,元素,示例,字符串,语法,例子,pythonmap()会根据提供的函数对指定序列做映射。第一个参数