I've read and understood this article about function decorators: https://www.artima.com/weblogs/viewpost.jsp?thread=240845 Specifically I'm talking about the section "Decorator Functions with Decorator Arguments"
I'm running into a problem, though. I'm trying to write a decorator function with arguments to modify arguments into a class constructor. I have two ways to write this.
First some imports:
import scipy.stats as stats
import numpy as np
Way 1 (similar to the aforementioned article's example):
def arg_checker1(these_first_args):
def check_args(func):
def wrapped(*args):
for arg in args[:these_first_args]:
assert isinstance(arg, np.ndarray) and arg.ndim == 2
return func(*args)
return wrapped
return check_args
or way 2:
def arg_checker2(these_first_args, func):
def wrapped(*args):
for arg in args[:these_first_args]:
assert isinstance(arg, np.ndarray) and arg.ndim == 2
return func(*args)
return wrapped
I just want an error to be thrown when the first 'these_first_args' to the function aren't 2-d np arrays. But take a look what happens when I try to use it (not with a @ but using it directly as a function)
class PropDens1:
def __init__(self, samp_fun):
self.samp = arg_checker1(samp_fun, 2) #right here
class PropDens2:
def __init__(self, samp_fun):
self.samp = arg_checker2(2, samp_fun) #right here
q_samp = lambda xnm1, yn, prts : stats.norm.rvs(.9*xnm1,1.,prts)
q1 = PropDens1(q_samp) #TypeError: arg_checker1() takes exactly 1 argument (2 given)
q2 = PropDens2(q_samp) #no error
The second one seems to work with a few examples. Is there a better way to do this, though? If not, why does this work?
I think this is why I don't get it. Here's the example in that linked paper:
def decoratorFunctionWithArguments(arg1, arg2, arg3):
def wrap(f):
print "Inside wrap()"
def wrapped_f(*args):
print "Inside wrapped_f()"
print "Decorator arguments:", arg1, arg2, arg3
f(*args)
print "After f(*args)"
return wrapped_f
return wrap
Why doesn't he actually have to pass the function-to-be-wrapped (f in this case) as an argument into the decoratorFunctionWithArguments()?
答案 0 :(得分:3)
The exception is telling you exactly what is wrong. You call arg_checker1
with 2 args but you defined it with only one. You should write:
self.samp = arg_checker1(2)(samp_fun)
Which is somewhat equivalent to:
@arg_checker1(2)
def q_samp(...):
...
Anyway, you way 1 is the way to go, since it will work fine with the @
syntax.