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

How to update argument passed to context manager during code execution?

node 传递给上下文管理器,我想在开始时锁定它,然后做一些工作,最后解锁节点。但是,如果 node 在 with 子句内的执行过程中发生了变化,我该如何将更新后的 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 列表,但这不起作用。

编辑2: 我试过使用列表,它是这样工作的。

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

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

问题是 node = 'new-node' 不会更改上下文管理器引用的对象;它改变了标识符 node 所指的内容。

你需要告诉对象改变,你只能用可变对象来做;字符串不可变。列表会起作用,但我认为 class 可能更清楚一些:

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)

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

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',)