On 02Aug2019 11:26, bob gailer <bgai...@gmail.com> wrote:
And now for something completely different...
Decorators are not required to return a function!
I use them to create a dictionary that maps function names to the corresponding function object.

That is an interesting idea! But I want to counter it, briefly.

This is very useful when associating actions with user-entered commands. Example:

def collect(func=None, d={}):
    if not func: return d
    d[func.__name__] = func

@collect
def add(a,b):
    return a+b

# adds item to dictionary d (key = 'add', value = func)
# repeat for other user-command functions
# finally:
cmd_dict = collect() # returns the dictionary
cmd = input('enter a command>')
func = cmd_dict.get(cmd)

I think you're conflating 2 things: having the decorator have a side effect outside the bare "do stuff around the call of an inner function", and returning a callable.

The feature of your remark is the side effect, which is useful. Not returning a callable is orthognal, and a misfeature.

Let me show you why:

   Python 3.7.4 (default, Jul 11 2019, 01:07:48)
   [Clang 8.0.0 (clang-800.0.42.1)] on darwin
   Type "help", "copyright", "credits" or "license" for more information.
   >>> d={}
   >>> def collect(f): d[f.__name__]=f
   ...
   >>> def g(x): print(x*2)
   ...
   >>> @collect
   ... def h(x): print(x*3)
   ...
   >>> g(8)
   16
   >>> h(8)
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: 'NoneType' object is not callable

The return value of the decorator is bound to the function name in the current scope,typically the current module for a normal function or the enclosing class for a method.

Your decorator returns None (I'm ignoring the d={} funkiness for now). Therefore a side effect of using the decorator is that every function "foo" you use with this decorator defines the name "foo" in the current scope as None.

As you can see in the example above, that makes the h() function not usable on its own. (And litters the namespace with a useless "h" name whose value is None.)

Had my version of your decorator looked like this:

   def collect(f):
       d[f.__name__] = f
       return f

then h() would have remained independently useful, at no cost to the functionality of your decorator.

So I'm arguing that while you _can_ return None from a decorator (which is what is actually happening in your "not returning" phrasing), it remains _useful_ and _easy_ to return the decorated function itself unchanged.

I've concerns about your d={} trick too, but we can discuss those in another subthread if you like.

I'm hoping to convince you that your otherwise nifty @collect decorator could do with returning the function unchanged after doing its work.

Finally, there is another important reason to return the function (or another callable): nesting decorators. Look at this piece of code from a project I'm working on:

   @classmethod
   @auto_session
   @require(lambda console: isinstance(console, Console))
   @require(lambda top_node: isinstance(top_node, DirTreeNode))
   @require(lambda top_node: not hasattr(top_node, 'can_uuid'))
   def from_fstree(cls, console, top_node, *, session):

This is a method, but otherwise the situation is no different. Each of these decorators does a little task and returns a callable, ready for further decoration by outer decorators. So every one of them returns a suitable callable.

If your @collect decorator returned the function, it too could be happily placed in such a nesting of decorators and everyone is happy. Because it does not, it does not play well with others, because an outer decorator would not have a callable to work with; it would get the None that your @collect returns.

This is the other argument for always returning a callable: to interoperate with other decorators, or of course anything else which works with a callable.

Cheers,
Cameron Simpson <c...@cskk.id.au>
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Reply via email to