Python与......以及自定义上下文管理器

时间:2016-01-12 17:19:11

标签: python

我在Python中编写了一个简单的上下文管理器来处理单元测试(并尝试学习上下文管理器):

class TestContext(object):
    test_count=1
    def __init__(self):
        self.test_number = TestContext.test_count
        TestContext.test_count += 1

    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_value, exc_traceback):
        if exc_value == None:
            print 'Test %d passed' %self.test_number
        else:
            print 'Test %d failed: %s' %(self.test_number, exc_value)
        return True

如果我按如下方式编写测试,一切正常。

test = TestContext()
with test:
   print 'running test %d....' %test.test_number
   raise Exception('this test failed')

但是,如果我尝试使用... as,我不会获得对TestContext()对象的引用。运行这个:

with TestContext() as t:
    print t.test_number

引发异常'NoneType' object has no attribute 'test_number'

我哪里错了?

3 个答案:

答案 0 :(得分:26)

假设您需要访问with语句__enter__ needs to return self中创建的上下文管理器。如果您不需要访问它,__enter__可以返回您想要的任何内容。

  

with语句将此方法的返回值绑定到语句的as子句中指定的目标(如果有)。

这样可行。

class TestContext(object):
    test_count=1
    def __init__(self):
        self.test_number = TestContext.test_count
        TestContext.test_count += 1

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):
        if exc_value == None:
            print 'Test %d passed' % self.test_number
        else:
            print 'Test %d failed: %s' % (self.test_number, exc_value)
        return True

答案 1 :(得分:8)

def __enter__(self):
    return self

会让它发挥作用。从此方法返回的值将分配给as变量。

另见the Python doc

  

如果目标包含在with语句中,则__enter__()的返回值将分配给它。

如果您只需要该号码,您甚至可以将上下文管理器的逻辑更改为

class TestContext(object):
    test_count=1
    def __init__(self):
        self.test_number = TestContext.test_count
        TestContext.test_count += 1

    def __enter__(self):
        return self.test_number

    def __exit__(self, exc_type, exc_value, exc_traceback):
        if exc_value == None:
            print 'Test %d passed' % self.test_number
        else:
            print 'Test %d failed: %s' % (self.test_number, exc_value)
        return True

然后再做

with TestContext() as test_number:
    print test_number

答案 2 :(得分:4)

根据PEP 343,with EXPR as VAR语句VAR的结果分配给EXPR,而是EXPR.__enter__()的结果test。第一个示例有效,因为您自己引用了if myListTags.contains({(($0 as? NSString)?.localizedCaseInsensitiveCompare(searchBar.text!) ?? .OrderedAscending) == .OrderedSame }) { } 变量。