Skip to main content
 首页 » 编程设计

python之与 Python fn 模块一起使用的函数

2025年05月04日9bhlsheji

我找到了这个函数式编程库 fn 并且我找到了以下函数柯里化(Currying)代码

>>> from fn.func import curried 
>>> @curried 
... def sum5(a, b, c, d, e): 
...     return a + b + c + d + e 
... 
>>> sum5(1)(2)(3)(4)(5) 
15 
>>> sum5(1, 2, 3)(4, 5) 
15 

但是当我运行它时我得到了

Traceback (most recent call last): 
  File "<stdin>", line 1, in <module> 
  File "/home/adrian/.local/lib/python2.7/site-packages/fn/func.py", line 83, in _curried 
    return curried(partial(func, *args, **kwargs)) 
  File "/home/adrian/.local/lib/python2.7/site-packages/fn/func.py", line 69, in curried 
    @wraps(func) 
  File "/usr/lib/python2.7/functools.py", line 33, in update_wrapper 
    setattr(wrapper, attr, getattr(wrapped, attr)) 
AttributeError: 'functools.partial' object has no attribute '__module__' 

有没有可能解决这个问题?

请您参考如下方法:

与 python2 相比,

wraps 行为在 python3 中有所不同,特别是 `update_wrapper``,该代码将按原样与 python3 一起使用,但您需要使用 py3 中的 wraps 实现才能使其工作.

我会提交错误报告,但与此同时,functools 的相关函数在这里:

from functools import wraps, partial, WRAPPER_ASSIGNMENTS,WRAPPER_UPDATES 
def update_wrapper(wrapper, 
                   wrapped, 
                   assigned = WRAPPER_ASSIGNMENTS, 
                   updated = WRAPPER_UPDATES): 
    """Update a wrapper function to look like the wrapped function 
       wrapper is the function to be updated 
       wrapped is the original function 
       assigned is a tuple naming the attributes assigned directly 
       from the wrapped function to the wrapper function (defaults to 
       functools.WRAPPER_ASSIGNMENTS) 
       updated is a tuple naming the attributes of the wrapper that 
       are updated with the corresponding attribute from the wrapped 
       function (defaults to functools.WRAPPER_UPDATES) 
    """ 
    for attr in assigned: 
        try: 
            value = getattr(wrapped, attr) 
        except AttributeError: 
            pass 
        else: 
            setattr(wrapper, attr, value) 
    for attr in updated: 
        getattr(wrapper, attr).update(getattr(wrapped, attr, {})) 
    # Issue #17482: set __wrapped__ last so we don't inadvertently copy it 
    # from the wrapped function when updating __dict__ 
    wrapper.__wrapped__ = wrapped 
    # Return the wrapper so this can be used as a decorator via partial() 
    return wrapper 
 
def wraps(wrapped, 
          assigned = WRAPPER_ASSIGNMENTS, 
          updated = WRAPPER_UPDATES): 
    """Decorator factory to apply update_wrapper() to a wrapper function 
       Returns a decorator that invokes update_wrapper() with the decorated 
       function as the wrapper argument and the arguments to wraps() as the 
       remaining arguments. Default arguments are as for update_wrapper(). 
       This is a convenience function to simplify applying partial() to 
       update_wrapper(). 
    """ 
    return partial(update_wrapper, wrapped=wrapped, 
                   assigned=assigned, updated=updated) 

curry wrapper :

def curried(func): 
    """A decorator that makes the function curried 
    Usage example: 
    >>> @curried 
    ... def sum5(a, b, c, d, e): 
    ...     return a + b + c + d + e 
    ... 
    >>> sum5(1)(2)(3)(4)(5) 
    15 
    >>> sum5(1, 2, 3)(4, 5) 
    15 
    """ 
    @wraps(func) 
    def _curried(*args, **kwargs): 
        f = func 
        count = 0 
        while isinstance(f, partial): 
            print(f) 
            if f.args: 
                count += len(f.args) 
            f = f.func 
 
        spec = getargspec(f) 
 
        if count == len(spec.args) - len(args): 
            return func(*args, **kwargs) 
 
        return curried(partial(func, *args, **kwargs)) 
    return _curried 

要仅修复 python2 的 curried 函数,您只能保留 func 具有的 WRAPPER_ASSIGNMENTS 中的属性:

#change this line  
 
@wraps(func, (attr for attr in WRAPPER_ASSIGNMENTS if hasattr(func, attr))) 
    def _curried(*args, **kwargs): 
        f = func 
        count = 0 
        while isinstance(f, partial): 
            print(f) 
            if f.args: 
                count += len(f.args) 
            f = f.func 
 
        spec = getargspec(f) 
 
        if count == len(spec.args) - len(args): 
            return func(*args, **kwargs) 
 
        return curried(partial(func, *args, **kwargs)) 
    return _curried