如何在代码执行期间更新传递给上下文管理器的参数?

时间:2016-11-25 02:25:05

标签: python arguments contextmanager

node被传递给上下文管理器,我想在开始时锁定,然后做一些工作,最后解锁节点。但是如果在with子句中执行期间更改了node,我该如何将更新后的node传递给unlockFunc

此代码在python 2.7中运行

from contextlib import contextmanager


@contextmanager
def call(begin, end, *args, **kwargs):
    begin(*args, **kwargs)
    try:
        yield
    finally:
        end(*args, **kwargs)


def lockFunc(*args):
    print 'in lockFunc'
    print 'lock %s' %args[0]


def unlockFunc(*args):
    print 'in unlockFunc'
    print 'unlock %s' %args[0]


node = 'old-node'
with call(lockFunc, unlockFunc, node):

    print 'in with'
    # update node value here
    node = 'new-node'

但输出是

in lockFunc
lock old-node
in with
in unlockFunc
unlock old-node

如何让unlockFunc知道node已被更改。

编辑:我已尝试将node列入清单,但这不起作用。

EDIT2: 我尝试使用列表,它以这种方式工作。

node = ['old-node']
with call(lockFunc, unlockFunc, node):

    print 'in with'
    node[0] = 'new-node'

2 个答案:

答案 0 :(得分:1)

问题是node = 'new-node'没有改变contextmanager引用的对象;它会更改标识符node所指的内容。

你需要告诉对象改变,你只能用一个可变对象来做;字符串不可变。列表可以工作,但我认为一个类可能更清楚一点:

from contextlib import contextmanager

class Node(object):
    def __init__(self,value):
        self.value=value

    def update(self, newvalue):
        self.value = newvalue

    def __str__(self):
        return str(self.value)

@contextmanager
def call(begin, end, *args, **kwargs):
    begin(*args, **kwargs)
    try:
        yield
    finally:
        end(*args, **kwargs)


def lockFunc(*args):
    print 'in lockFunc'
    print 'lock %s' %args[0]


def unlockFunc(*args):
    print 'in unlockFunc'
    print 'unlock %s' %args[0]


node = Node('old-node')
with call(lockFunc, unlockFunc, node):

    print 'in with'
    # update node value here
    node.update('new-node')

产生

in lockFunc
lock old-node
in with
in unlockFunc
unlock new-node

(Ubuntu 14.04,Python 2.7.6)

答案 1 :(得分:0)

我找到了更好的解决方案。

class call(object):

    def __init__(self,begin, end, *args, **kwargs):
        self.begin = begin
        self.end = end
        self.args = args
        self.kwargs = kwargs

    def __enter__(self):
        self.begin(*self.args, **self.kwargs)
        return self

    def __exit__(self,exc_type,exc_val,trcback):
        self.end(*self.args, **self.kwargs)

def lockFunc(*args):
    print 'in lockFunc', args
    print 'lock %s' %args


def unlockFunc(*args):
    print 'in unlockFunc'
    print 'unlock %s' %args

node = 'old-node'

with call(lockFunc, unlockFunc, node) as c:
    print 'in with'
    # update node value here
    c.args = ('new-node',)