没有Yield的Context Manager

时间:2015-12-29 21:55:24

标签: python contextmanager

我是否可以拥有一个偶尔不会产生的上下文管理器,在这种情况下,with语句中的代码根本不会被执行?

import contextlib

@contextlib.contextmanager
def MayNotYield(to_yield):
  if to_yield:
    yield

with MayNotYield(True):  
  print 'This works.'

with MayNotYield(False):  
  print 'This errors.'

我可以要求用户用try-catch包装with语句,但这不是首选。我也可以做以下事情,但它也很难看。

import contextlib

@contextlib.contextmanager
def AlwaysYields(to_yield):
  if to_yield:
    yield 1
  else:
    yield 2

with AlwaysYields(True) as result:
  if result == 1:
    print 'This works.'

3 个答案:

答案 0 :(得分:5)

不幸的是,the context manager protocol没有给上下文管理员一个说“不要运行with块" (除了在__enter__中引发例外)。如果您仍在使用上下文管理器,我认为您的第二种方法是__enter__返回一个值来表示是否应该运行该块是最好的方法。如果由于某些其他原因您不需要上下文管理器,您可以使用简单的if语句:

if do_stuff:
    # do the stuff

答案 1 :(得分:0)

鉴于在上下文管理器实现中具有条件的目标,在可能将with块的内容提取到其自身函数中的情况下,还有另一种可能性。您可以将此可调用对象传递给上下文管理器,并让上下文管理器根据布尔值从上下文管理器返回传递的可调用对象或伪空操作。 with块将始终执行,但是该动作可能会或可能不会被调用。

let view = UIView()
    let label = UILabel()
    label.text = "Hello"
    label.sizeToFit()

    view.addSubview(label)
    view.frame.size = label.bounds.size
    view.setNeedsDisplay()
    RunLoop.main.run(mode: .default, before: Date())

    let size = view.bounds.size
    let layer = view.layer

    DispatchQueue.global().async {
        UIGraphicsBeginImageContext(size)
        layer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        DispatchQueue.main.async {
            let imageView = UIImageView(image: image)
            imageView.backgroundColor = .lightGray
            imageView.bounds.size = view.bounds.size // retain `view`
            imageView.center = CGPoint(x: 200, y: 300)
            self.view.addSubview(imageView)
        }
    }

您将需要根据上下文管理器管理的资源(如果有)以及可调用对象的必需签名来定制此解决方案。

答案 2 :(得分:0)

另一种选择是仅使用常规生成器,而不是使用上下文管理器;普通生成器将没有此限制。但是您必须将其与“ for”构造一起使用,而不是与“ with”一起使用:

def MayNotYield(to_yield):
   if to_yield:
      yield

for _ in MayNotYield(True):
   print('This prints.')

for _ in MayNotYield(False):
   print('This does not.')