欢迎来把玩: :D https://github.com/fredwu/ruby_decorators
凌晨 3 点了,累死了,睡觉了睡觉了……
感觉跟 python 的 decorator 差异很大。python 里面用 class 来实现 decorator 的话,__call__
方法的参数是 funtion 类型,返回另一个 function。这里的 call 方法的 this 参数,是所 decorate 的方法的返回值吧?对返回值进行修改,倒跟 golang 里用 defer 修改返回值类似。python 的 decorator 可以对方法/函数进行重新定义,而且可以引用到原方法/函数,不是修改返回值
比如这样一个 python 的 decorator
def double_arguments(func):
def f(*args):
return func(*[x * 2 for x in args])
return f
@double_arguments
def add(a, b, c):
return a + b + c
@double_arguments
def mul(a, b, c):
return a * b * c
print add(1, 2, 3) # => 12
print mul(1, 2, 3) # => 48
double_arguments 会修改 add 和 mul 的定义,使传递给他们的参数都先乘以 2,再传递给原函数 如果 decorator 只能改变返回值,那是实现不了这个效果的 decorator 的实现里面,不仅可以引用到原先定义的函数/方法,也可以引用到实际调用时的参数 所以 ruby 可能可以写成这样?
class Batman < RubyDecorator
def call(func)
lambda {|*args|
func(*args).sub('world', 'batman')
}
end
end
我更新了一下,现在 decorator 的第一个参数是原函数,而非返回值了。:)
class Batman < RubyDecorator
def call(this, *args, &blk)
this.call(*args, &blk).sub('world', 'batman')
end
end
如果 decorator 返回的是 callable object,还可以实现多重 decorate,比如 python 的
@double_arguments
@double_arguments
@double_arguments
def foo(a, b):
return a + b
print foo(1, 2) # => 24 八倍参数
相当于
def foo(a, b):
return a + b
foo = double_arguments(double_arguments(double_arguments(foo)))