Python嵌套函数范围

时间:2012-11-20 23:46:13

标签: python

我有一个python哈希,其中包含函数名称到函数的映射。我想修改每个哈希条目以调用关联的函数BUT然后也调用最终的自定义函数。这有点像退出钩子。

def original():
    print "original work"

变为

def replacement():
    original()
    print "notify somebody..."

我的问题是我认为我正在接受我的范围等,错误,因为以下代码的输出不符合预期。也许如果我可以问是否有更好的方法来做到这一点?我想坚持修改原始的cb,因为它的第三方代码和更少的地方我改变得更好。

#!/usr/bin/python 

def a():
    print "a"

def b():
    print "b"

def c():
    print "c"


orig_fxn_cb = dict()

" basic name to function callback hash "
orig_fxn_cb['a'] = a
orig_fxn_cb['b'] = b
orig_fxn_cb['c'] = c

" for each call back routine in the hash append a final action to it "
def appendFxn(fxn_cb):
    appended_fxn_cb_new = dict()
    for i in orig_fxn_cb.keys():
        cb = fxn_cb[i]
        def fxn_tail():
            cb()
            print cb.__name__, "tail" 

        appended_fxn_cb_new[i] = fxn_tail
        appended_fxn_cb_new[i]()
    return appended_fxn_cb_new

" make up a modified callback hash "
xxx = appendFxn(orig_fxn_cb)
print xxx

for i in xxx:
    print xxx[i]()

3 个答案:

答案 0 :(得分:4)

你好吗:

from functools import wraps

def notifier(f):
    @wraps(f)
    def wrapped(*args, **kwargs)
        res = f(*args, **kwargs)
        print "notify somebody..."
        return res
    return wrapped

@notifier
def original():
    print "original work"

# or: original = notifier(original)

original()
original work
notify somebody...

答案 1 :(得分:2)

您遇到的问题与您在cb函数中使用的appendFxn变量有关。您的内部函数定义按名称访问此值,因此它们最终都会引用相同的内部回调函数(在迭代中最后出现的那个)。

您可以使用包装函数中的默认参数来解决此问题:

def appendFxn(fxn_cb):
    appended_fxn_cb_new = dict()
    for i in orig_fxn_cb.keys():
        cb = fxn_cb[i]
        def fxn_tail(cb = cb):           # fix is here!
            cb()
            print cb.__name__, "tail" 

        appended_fxn_cb_new[i] = fxn_tail
        appended_fxn_cb_new[i]()
    return appended_fxn_cb_new

使用默认参数将cb当前值绑定到内部函数中的cb名称。这样,即使原始cb变量设置为新值,现有函数也将保留旧值。 (如果需要,您也可以创建函数参数cb = fxn_cb[i]并删除外部cb变量。)

答案 2 :(得分:0)

我不知道预期的输出是什么,它似乎在这里工作正常。它用一个调用原始文件的副本替换字典中的所有函数,然后打印原始名称和“尾部”。当它取代函数时,它也会执行它们。最后,您遍历生成的字典并再次执行它们。

如果多次调用appendFxn,可能会给您带来意外行为的是for i in orig_fxn_cb.keys():行。它引用了全局orig_fxn_cb而不是传递的fxn_cb参数,因此进一步调用不会更改地图中的函数。