函数的属性如何在包装中存活?

时间:2016-05-12 16:34:05

标签: python python-decorators

假设我有以下函数,它具有一个属性,用于标记回调子系统中的特殊处理:

def my_func(msg):
    print msg

my_func.my_marker = SPECIAL_CONSTANT

问题在于,如果其他位代码用my_func或其他装饰器包裹functools.partial,那么my_marker将会丢失。

my_partial = partial(my_func, 'hello world')
print my_partial.my_marker
>>> AttributeError...

有没有办法在包装时保护函数的属性?有没有更好的方法来存储我当前存储在my_marker中的元数据?似乎存储对原始函数的引用也会遇到同样的问题。

3 个答案:

答案 0 :(得分:2)

如果您知道您使用的部分内容实际上是部分内容,则可以使用它的func属性。

电子。克。

from functools import partial

SPECIAL_CONSTANT = 'bam'


def my_func(msg):
    print msg

my_func.my_marker = SPECIAL_CONSTANT

my_partial = partial(my_func, 'hello world')

print my_partial.func.my_marker

如果你真的需要处理meta_data,也许这是一种更好的方法来编写类并覆盖__call__()方法。

答案 1 :(得分:0)

这是另一种解决方案,使用functools.update_wrapper

from functools import partial, update_wrapper, WRAPPER_ASSIGNMENTS


SPECIAL_CONSTANT = 'bam'


def my_func(msg):
    print msg


my_func.my_marker = SPECIAL_CONSTANT

my_partial = partial(my_func, 'hello world')
update_wrapper(my_partial, my_func, WRAPPER_ASSIGNMENTS + ('my_marker', ))

print my_partial.my_marker

答案 2 :(得分:0)

受到善意评论的启发,cbo的答案和source code

from functools import partial as _partial, update_wrapper

def partial(func, *args, **keywords):
    return update_wrapper(_partial(func, *args, **keywords), func)

显示它正常工作的示例,并提出警告:

def my_func(msg):
    print msg


my_func.my_marker = 'FOO'

my_partial = partial(my_func, 'hello world')

print my_func.my_marker
print my_partial.my_marker

# check other stuff is still there
print my_partial.func
print my_partial.args
print my_partial.keywords

# this works fine for READ ONLY stuff.

# so just remember:

my_partial.my_marker = 'BAR' # this _only_ updates partial, not the original

print my_func.my_marker
print my_partial.my_marker


my_func.my_marker = 'BAZ' # this _only_ updates original, not the partial

print my_func.my_marker
print my_partial.my_marker

可以执行以下操作:

import functools
setattr(functools, 'partial', partial) # from above code

然而,这可能是一个坏主意,因为(1)它需要在任何依赖它的代码之前导入,(2)它可能破坏导入的代码,(3)它可能混淆未来的人和(4)替代方案,保持在当地,很容易。只有在你想强制第三方代码运行你的版本时才这样做。