首页 > 解决方案 > 使用 Python 装饰器对结果取模

问题描述

我正在学习 Python 中的装饰器,但在使用的装饰器上遇到了一些问题:

@curry
def modulo(mod,f):
    if mod:
        @fun.wraps(f)
        def wrapper(*args, **kw):
            result = f(*args, **kw)
            return tuple(r % mod for r in result)
    else:
        return f
    return wrapper

curry 装饰器是一个简单的柯里化,所以我可以在下面调用 mod 作为参数:

def _fib(p=1,q=-1,mod=None):
    ''' Fibonacci sequence '''
    @modulo(mod)
    def next_fib(pair):
        x,y = pair
        return y, p*x - q*y
    
    yield from ( y for x,y in iterate(next_fib,(1,0)) )

它有效,看起来又漂亮又干净。但是,假设我想要另一个 [密切相关的] 卢卡斯序列生成器:

def _luc(p=1,q=-1,mod=None):
    ''' Lucas sequence '''
    @modulo(mod)
    def next_luc(pair):
        x,y = pair
        return y, p*x - q*y
    
    yield from ( y for x,y in iterate(next_luc,(p-2,2)) )

如果我把它们放在一起,我会遇到某种冲突:

>>> F = _fib()
>>> print(take(10,F))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

>>> L = _luc()
>>> print(take(10,L))
" ... TypeError: cannot unpack non-iterable function object"

单独调用它们按预期工作,并返回正确的模块化术语。

我的问题是双重的:这是一个命名空间冲突,它们都指的是模()吗?你会怎么做这样的事情?

辅助功能:

import itertools as it
import functools as fun

def curry(f):
    argc = f.__code__.co_argcount
    f_args = []
    f_kwargs = {}
    @fun.wraps(f)
    def wrapper(*args, **kwargs):
        nonlocal f_args, f_kwargs
        f_args += args
        f_kwargs.update(kwargs)
        if len(f_args)+len(f_kwargs) == argc:
            return f(*f_args, **f_kwargs)
        else:
            return wrapper          
    return wrapper

def iterate(f,x):
    ''' x, f(x), f(f(x)), f(f(f(x))), ... '''
    return it.accumulate(it.repeat(x), lambda fx, _: f(fx))

def take(n,iterable):
    return [x for x in it.islice(iterable,n)]

标签: pythonpython-decorators

解决方案


我发现扩展原始模包装器可以解决问题!感谢Thomas_Breydo建议更改咖喱函数

def modulo(mod):
    def wrapper(f):
        @fun.wraps(f)
        def deco(*args,**kwargs):
            if mod:
                return tuple(n%mod for n in f(*args,**kwargs) )
            else:
                return f(*args,**kwargs)
        return deco
    return wrapper

这解决了我的问题。


推荐阅读