有没有办法懒惰评估function.func_name?

时间:2013-05-01 15:19:52

标签: python functional-programming lazy-evaluation

这个问题与我的代码无关 我只想说明我需要对function.func_name

进行延迟评估的原因

我在代码中使用curry装饰器 我通过修改func_name来显示curried参数 因此,当我需要一些调试时,我可以很容易地找出哪些参数已被咖喱

>> My modified version <<
>> The original version <<

我的curry示例:

@curry
def f(a, b, c, flag_foo=True, flag_bar=False):
    pass

>>> f
<function f at 0x100545398>

>>> f(1, flag_bar=True)
<function f(1, flag_bar=True) at 0x1005451b8>

>>> f(1, flag_bar=True)(3, flag_foo=False)
<function f(1, 3, flag_foo=False, flag_bar=True) at 0x1004aee60>

由于在没有调试的情况下永远不会访问func_name,所以 我想避免评估func_name

的开销

但是,function是一个不能被子类化的最终类 有没有办法对function.func_name进行延迟评估?

欢迎任何建议

1 个答案:

答案 0 :(得分:1)

代码:

class Curried(object):
    def __init__(self, func, args=None, kwargs=None):
        self._func = func
        self._args = () if args is None else args[:]
        self._kwargs = {} if kwargs is None else dict(kwargs)
        self._name = None

    def __call__(self, *args, **kwargs):
        if args or kwargs:
            return Curried(self._func,
                           self._args + args,
                           dict(self._kwargs.items() + kwargs.items()))
        else:
            return self._func(*self._args, **self._kwargs)

    def __str__(self):
        if self._name is None:
            self._name = self._get_curried_name()
        return self._name

    def _get_curried_name(self):
        _args = ([str(a) for a in self._args] +
                 ['{}={}'.format(k, v) for k, v in self._kwargs.iteritems()])
        all_args = ", ".join(_args)
        return '<curried {}({}) at 0x{:x}>'.format(
            self._func.func_name, all_args, id(self))

    def curry(func):
        _curried = Curried(func)
        return _curried

测试:

@curry
def f(a, b, c, flag_foo=True, flag_bar=False):
    return 'horray!'

print f
print f(1, 2, flag_bar=True)
print f(1, 2, flag_bar=True)(3, flag_foo=False)
print f(1, 2, flag_bar=True)(3, flag_foo=False)()

结果:

<curried f() at 0x100484210>
<curried f(1, 2, flag_bar=True) at 0x100484250>
<curried f(1, 2, 3, flag_bar=True, flag_foo=False) at 0x100484310>
horray!

这里有一个可调用的类,而不是“纯”函数。您只评估一次名称。当然,如果您需要func_name,可以将此类变量添加为property并返回str(self),这将被评估一次