python decorator function with arguments
Question: 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()?


Answer: 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.

