繁体   English   中英

如何在Python 3中修饰部分应用的函数?

[英]How do I decorate a partially applied function in 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)似乎是生成装饰器的完全有效的方法,它在正常声明的函数上工作正常。 但是当尝试使用部分应用的函数时,我在foo =的开头得到语法错误,并且在使用装饰器和functools.partial时获得优秀资源的googling通常没有给我任何关于这个特定情况的东西。

装饰器不适用于作业。 但是因为使用装饰器与调用装饰器是一样的,所以你可以这样做

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

无论哪种方式都有效

这是使用Either的另一种方式 - 这个答案的灵感来自Brian Lonsdorf的egghead系列: Frisby教授推出可组合功能JavaScript

我们将学习一些我们在那里学到的知识并编写一些超级甜蜜的功能python代码

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函数的语法有点log_error ,但一切都按预期工作。

用简单的英语:我们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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM