2017-02-23 46 views
3

我创建了一个装饰厂由一个自定义的日志记录功能参数,像这样:如何在Python 3中修饰部分应用的函数?

def _log_error(logger): 
    def decorator(f): 
     @wraps(f) 
     def wrapper(*args, **kwargs): 
      try: 
       return f(*args, **kwargs) 
      except Exception as e: 
       logger(e) 
       return None 
     return wrapper 
    return decorator 

我现在想用它来装点一个部分应用的函数foo:

foo = partial(bar, someparam) 

我已经尝试了所有的以下内容:

@_log_error(logger) 
foo = partial(bar, someparam) 

log_error = _log_error(logger) 
@log_error 
foo = partial(...) 

foo = partial(...) 
@log_error 
foo 

@log_error 
(foo = partial(...)) 

AFAICT都log_error = _log_error(logger)/@log_error@_log_error(logger)似乎产生的dec的完全有效的方法orator并且它在正常声明的函数上工作正常。但是,当试图在部分应用的函数上使用时,我在foo =开始处得到语法错误,并且在使用装饰器时产生优秀的资源,而在一般情况下functools.partial在这个特定情况下没有给我任何提示。

回答

5

修饰师不能在作业上工作。但由于使用装饰是一回事调用装饰,你可以做

foo = _log_error(logger)(partial(bar, someparam)) 
1

两种方法都可行

这里的另一种方式,您可以使用Either做到这一点 - 这个答案会从布赖恩其灵感Lonsdorf的理论家系列:Professor Frisby Introduces Composable Functional JavaScript

,我们会采取一些什么,我们那里了解到,写一些超甜功能蟒蛇代码

class Map (dict): 
    def __init__(self, **xw): 
    super(Map, self).__init__(**xw) 
    self.__dict__ = self 

def Left (x): 
    return Map(
    fold = lambda f, g: f(x), 
    bimap = lambda f, g: Left(f(x)) 
) 

def Right (x): 
    return Map(
    fold = lambda f, g: g(x), 
    bimap = lambda f, g: Right(g(x)) 
) 

注:这是一个非常不全实施LeftRight,但它足以让这个特定的工作做好。要充分利用这种超强数据类型的全部功能,您需要完整的实现。


泛型促进代码重用

我们会设置几个通用的功能

def identity (x): 
    return x 

def try_catch (f): 
    try: 
    return Right(f()) 
    except Exception as e: 
    return Left(e) 

def partial (f, *xs, **xw): 
    def aux (*ys, **yw): 
    return f(*xs, *ys, **xw, **yw) 
    return aux 

现在,我们有足够的定义log_error - 语法是有点靠不住用Python编写curried函数,但一切都按预期工作。

用简单的英文:我try申请f并取回一个值。如果该值是一个错误(Left),拨打logger,否则返回值(identity

def log_error (logger): 
    def wrapper (f): 
    def aux (*xs, **xw): 
     return try_catch (lambda: f(*xs, **xw)).bimap(logger, identity) 
    return aux 
    return wrapper 

全部放在一起

现在,让我们尝试用一个小功能

def foo (x,y,z): 
    return (x + y) * z 

你想要做的是把一个部分应用的功能包装在你的我们荷兰国际集团定制记录器

foo_logger = log_error(lambda err: print("ERROR:" + str(err))) (partial(foo,'a')) 

foo_logger('b',3).fold(print, print) 
# ('a' + 'b') * 3 
# 'ab' * 3 
# => ababab 

foo_logger(1,3).fold(print, print) 
# ('a' + 1) * 3 
# ERROR: Can't convert 'int' object to str implicitly 
# => None 

了解结果

正如你所看到的,当没有错误存在(Right),评价只是不断移动和计算的值传递给print

当发生错误时(Left),记录器将记录它并将错误消息记录到控制台。因为日志记录功能没有返回值,所以None传递给print

+0

Monads in Python!打的好。 –

相关问题