Note that there are some explanatory texts on larger screens.

plurals
  1. PODecorator which conditionally activates another decorator?
    text
    copied!<p>I have some functions which, under normal circumstances, are called with arguments provided by user input. It is, however, valid to call some of these functions with certain series of arguments which are determined at runtime based on some system state.</p> <p>I would like for the user to be able to <em>optionally</em> instruct my program to call these functions with all valid input and return the results of each call. I think a decorator which would work something like an activation switch for functions which have another decorator which indicates which series of arguments to use would work well.</p> <p>Additionally, I <em>need</em> to preserve the function signature and metadata. It's vital to the operation of my program.</p> <p>This is what I've tried, but it doesn't work. It is based upon <a href="http://micheles.googlecode.com/hg/decorator/documentation.html#id9" rel="nofollow">this example</a>.</p> <pre><code>&gt;&gt;&gt; from decorator import decorator &gt;&gt;&gt; def the_list(): ... return ["foo", "bar", "baz"] ... &gt;&gt;&gt; import itertools &gt;&gt;&gt; @decorator ... def do_all(func): ... # this will do nothing (besides wrap in a tuple) unless func is decorated with @gets_arg_from ... if hasattr(func, 'get_from'): ... return tuple(func(*args) for args in itertools.product(*(list_fun() for list_fun in func.get_from))) ... else: ... return (func(),) ... &gt;&gt;&gt; def gets_arg_from(*list_funcs): ... # this will do nothing to func unless decorated with @do_all ... def gets_arg_from(func, *args, **kwargs): ... func.get_from = list_funcs ... return func(*args, **kwargs) ... return decorator(gets_arg_from) ... &gt;&gt;&gt; @gets_arg_from(the_list) ... def print_func(word): ... # this will print its argument unless decorated with @do_all ... # at that point it will print every element returned by the_list() ... print word ... &gt;&gt;&gt; print_func("foo") foo &gt;&gt;&gt; all = decorator(do_all, print_func) &gt;&gt;&gt; all() Traceback (most recent call last): File "&lt;stdin&gt;", line 1, in &lt;module&gt; TypeError: print_func() takes exactly 1 argument (0 given) &gt;&gt;&gt; print_func.get_from Traceback (most recent call last): File "&lt;stdin&gt;", line 1, in &lt;module&gt; AttributeError: 'function' object has no attribute 'get_from' </code></pre> <p>What I expected was:</p> <pre><code>&gt;&gt;&gt; all() ("foo", "bar", "baz") </code></pre> <p>What I've noticed is wrong:</p> <ol> <li><code>gets_arg_from</code> doesn't add the <code>get_from</code> attribute to <code>func</code>.</li> <li>Something about me using the notation <code>@gets_arg_from(the_list)</code> is wrong. It thinks I am trying to pass two arguments (but why would that be a problem anyway?)</li> </ol> <hr> <p>As for my motivation, I think of decorators for this because there are literally hundreds of these routines, their implementation details (as well as their functional correctness) is subject to frequent change, and I don't want to use <code>inspect</code> to reason what to do based on their argument names nor do I want to hard-code the <code>do_all</code> functionality for each function for which it makes sense. Class methods might work, but for my purpose, they're semantically contrived. Furthermore, for the sake of others who may have to maintain my code, I think it is easier to ask them to apply a decorator and not to worry about the rest rather than to use certain argument names or place the function in a certain class or whatever. I realize this question may sound strange, so I figured this footnote might help make me look less like a madman.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload