Python上下文管理器

发布时间:2022-04-22 09:39:16 人气:28 作者:多测师

  本节严格意义上并非新的重定向方式,而是利用Pyhton上下文管理器优化上节的代码实现。借助于上下文管理器语法,可不必向重定向使用者暴露sys.stdout。

  首先考虑输出抑制,基于上下文管理器语法实现如下:

  import sys, cStringIO, contextlib

  class DummyFile:

  def write(self, outStr): pass

  @contextlib.contextmanager

  def MuteStdout():

  savedStdout = sys.stdout

  sys.stdout = cStringIO.StringIO() #DummyFile()

  try:

  yield

  except Exception: #捕获到错误时,屏显被抑制的输出(该处理并非必需)

  content, sys.stdout = sys.stdout, savedStdout

  print content.getvalue()#; raise

  #finally:

  sys.stdout = savedStdout

  使用示例如下:

  with MuteStdout():

  print "I'll show up when is executed!" #不屏显不写入

  raise #屏显上句

  print "I'm hiding myself somewhere:)" #不屏显

  再考虑更通用的输出重定向:

  import os, sys

  from contextlib import contextmanager

  @contextmanager

  def RedirectStdout(newStdout):

  savedStdout, sys.stdout = sys.stdout, newStdout

  try:

  yield

  finally:

  sys.stdout = savedStdout

  使用示例如下:

  def Greeting(): print 'Hello, boss!'

  with open('out.txt', "w+") as file:

  print "I'm writing to you..." #屏显

  with RedirectStdout(file):

  print 'I hope this letter finds you well!' #写入文件

  print 'Check your mailbox.' #屏显

  with open(os.devnull, "w+") as file, RedirectStdout(file):

  Greeting() #不屏显不写入

  print 'I deserve a pay raise:)' #不屏显不写入

  print 'Did you hear what I said?' #屏显

Python上下文管理器

  可见,with内嵌块里的函数和print语句输出均被重定向。注意,上述示例不是线程安全的,主要适用于单线程。

  当函数被频繁调用时,建议使用装饰器包装该函数。这样,仅需修改该函数定义,而无需在每次调用该函数时使用with语句包裹。示例如下:

  import sys, cStringIO, functools

  def MuteStdout(retCache=False):

  def decorator(func):

  @functools.wraps(func)

  def wrapper(*args, **kwargs):

  savedStdout = sys.stdout

  sys.stdout = cStringIO.StringIO()

  try:

  ret = func(*args, **kwargs)

  if retCache == True:

  ret = sys.stdout.getvalue().strip()

  finally:

  sys.stdout = savedStdout

  return ret

  return wrapper

  return decorator

  若装饰器MuteStdout的参数retCache为真,外部调用func()函数时将返回该函数内部print输出的内容(可供屏显);若retCache为假,外部调用func()函数时将返回该函数的返回值(抑制输出)。

  MuteStdout装饰器使用示例如下:

  @MuteStdout(True)

  def Exclaim(): print 'I am proud of myself!'

  @MuteStdout()

  def Mumble(): print 'I lack confidence...'; return 'sad'

  print Exclaim(), Exclaim.__name__ #屏显'I am proud of myself! Exclaim'

  print Mumble(), Mumble.__name__ #屏显'sad Mumble'

  在所有线程中,被装饰函数执行期间,sys.stdout都会被MuteStdout装饰器劫持。而且,函数一经装饰便无法移除装饰。因此,使用该装饰器时应慎重考虑场景。

  接着,考虑创建RedirectStdout装饰器:

  def RedirectStdout(newStdout=sys.stdout):

  def decorator(func):

  def wrapper(*args,**kwargs):

  savedStdout, sys.stdout = sys.stdout, newStdout

  try:

  return func(*args, **kwargs)

  finally:

  sys.stdout = savedStdout

  return wrapper

  return decorator

  使用示例如下:

  file = open('out.txt', "w+")

  @RedirectStdout(file)

  def FunNoArg(): print 'No argument.'

  @RedirectStdout(file)

  def FunOneArg(a): print 'One argument:', a

  def FunTwoArg(a, b): print 'Two arguments: %s, %s' %(a,b)

  FunNoArg() #写文件'No argument.'

  FunOneArg(1984) #写文件'One argument: 1984'

  RedirectStdout()(FunTwoArg)(10,29) #屏显'Two arguments: 10, 29'

  print FunNoArg.__name__ #屏显'wrapper'(应显示'FunNoArg')

  file.close()

  注意FunTwoArg()函数的定义和调用与其他函数的不同,这是两种等效的语法。此外,RedirectStdout装饰器的最内层函数wrapper()未使用"functools.wraps(func)"修饰,会丢失被装饰函数原有的特殊属性(如函数名、文档字符串等)。

  以上内容为大家介绍了Python上下文管理器,希望对大家有所帮助,如果想要了解更多Python相关知识,请关注多测师。https://www.e70w.com/xwzx/


返回列表
在线客服
联系方式

热线电话

17727591462

上班时间

周一到周五

二维码
线