Scala 中的 Python 风格装饰器

标签 python scala decorator

在 Python 中我可以做这样的事情:

def wrap(f):
    def wrapper(*args, **kwargs):
        print "args: ", args, kwargs
        res = f(*args, **kwargs)
        print "result: ", res
        return res
    return wrapper

这让我可以包装任何函数,而不管它们采用什么参数。例如:

In [8]: def f(thing):
    print "in f:", thing
    return 3

In [9]: wrapped_f = wrap(f)

In [10]: wrapped_f(2)
args:  (2,) {}
in f: 2
result:  3
Out[10]: 3

有没有办法在 Scala 中做类似的事情(编写一个可以应用于任何函数的包装器,无论其输入/输出类型如何)?

最佳答案

您当然可以使用宏来做到这一点。您可以将方法调用转换为具有部分应用程序的函数:

object Foo {
  def bar(i: Int): Int = i + 1
}

val fn = Foo.bar _

defined object Foo
fn: Int => Int = <function1>

现在您有一个对象,在本例中为 Function1[Int, Int] 类型,您可以将其传递给 Scala 宏,它可能是这样的(未测试):

object DecoratorMacros {

  import reflect.macros.blackbox
  import language.experimental.macros

  def decorate[A <: Function](fn: A): [A] = macro decorate_impl[A]

  def decorate_impl[A: c.WeakTypeTag](c: blackbox.Context) = {
    import c.universe._
    val type = weakTypeOf[A]
    ...
  }
}

在宏的主体中,您可以检查 fn: A 的整个类型签名,其中将包括参数。然后您可以编写代码来实现您想要的副作用,并返回一个您可以调用的函数。像这样:

DecoratorMacros.decorate(Foo.bar _)(42)

宏相当复杂,但如果您认为这是一条您想走的路,我可以详细说明。

关于Scala 中的 Python 风格装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29311116/

相关文章:

Scala 不可变 Set 是可变的吗?

python - 更改嵌套函数装饰器中的值

python - Save.numpy masked array to a .numpy array with NaNs where mask == True

python - 如何在numpy中沿轴执行外减法

Python:使用正则表达式进行数据验证

mysql - 尝试添加 MySQL/slick 后出现奇怪的 Play Framework 2.2 异常

scala - 用另一个列表中的单词过滤一个列表中的单词

python - 可以同时接受 init args 和 call args 的装饰器?

python - 装饰器可以在运行时使用 lambda 表达式吗?

python - 并排连接两个列表