Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #8554

Re: Using decorators with argument in Python

From Ben Finney <ben+python@benfinney.id.au>
Newsgroups comp.lang.python
Subject Re: Using decorators with argument in Python
References <d35e1e82-410b-471b-a3c7-379c1822adb0@m22g2000yqh.googlegroups.com>
Date 2011-06-29 08:19 +1000
Message-ID <87hb79mweh.fsf@benfinney.id.au> (permalink)
Organization Unlimited download news at news.astraweb.com

Show all headers | View raw


Jigar Tanna <poisonousrattle5@gmail.com> writes:

> where I came across a special case of using arguments with decorators

A decorator is a function which takes exactly one parameter, and returns
a function based on that parameter.

    <URL:http://docs.python.org/glossary.html#term-decorator>
    <URL:http://docs.python.org/reference/compound_stmts.html#function>

So a decorator always takes an argument: the function to be decorated.

> Below is the code for memoization where I was looking at the
> concept...

[…]

> def memoize(get_key=get_key, cache=cache) :
>     def _memoize( function) :
>         print function
>         def __memoize(*args, **kw) :
>             key = get_key(function, *args, **kw)
>             try:
>                 return cache[key]
>             except KeyError:
>                 cache[key] = function( *args, **kw)
>                 return cache[key]
>         return __memoize
>     return _memoize

Note that the function ‘memoize’ is not a decorator. It's a decorator
creator; it returns a decorator.

That is, you pass this function zero, one, or two arguments, and it
defines a new function with the name ‘_memoize’; *that* function is then
returned. That function is the decorator, and will receive exactly one
parameter when you decorate a function.

> @memoize()

‘memoize()’ calls the ‘memoize’ function, which creates and returns the
decorator. That return value is then used (because of the ‘@’ syntax) to
decorate the function whose definition follows.

> def factory(n) :
>     return n * n

This function is created, and then immediately passed as the single
argument to the decorator that ‘memoize()’ returned above. The return
value from that decorator then gets bound to the name ‘factory’.

(Side note: it's unfortunate the writer of ‘memoize’ didn't wrap the
decorated function better. In this implementation, the resulting
function will be bound to the name ‘factory’, but will consider its name
to be ‘_memoize’. It will also lack the docstring of the ‘factory’
function. For a better way, see ‘functools.wraps’.)

> coming across to certain views from people, it is not a good practice
> to use decorators with arguments (i.e. @memoize() )

Correcting your mental model: those are not decorators. They are
creating a decorator, by calling a function that returns a decorator.

And if you've come across views that say there's something wrong with
that, those views are mistaken. There are many good reasons to call a
function to return a decorator, and “I get a different decorator
depending on what arguments I give to this decorator-creator” is the
pattern.

> and instead it is good to just use @memoize.

That wouldn't work in this case, of course, since the function ‘memoize’
is not a decorator: it doesn't take the function-to-be-decorated as an
argument.

In other cases where the decorator is available immediately as a defined
function (e.g. ‘functools.partial’ or the built-in ‘property’), there is
of course no problem using that.

But it's not always the case that you have that decorator yet, and
calling another function (with whatever arguments it needs) to create
the decorator at the point where you need to use it is also fine.

> Can any of you guys explain me advantages and disadvantages of using
> each of them

I hope that explains.

-- 
 \     “Men never do evil so completely and cheerfully as when they do |
  `\        it from religious conviction.” —Blaise Pascal (1623–1662), |
_o__)                                                   Pensées, #894. |
Ben Finney

Back to comp.lang.python | Previous | NextPrevious in thread | Find similar | Unroll thread


Thread

Using decorators with argument in Python Jigar Tanna <poisonousrattle5@gmail.com> - 2011-06-28 09:52 -0700
  Re: Using decorators with argument in Python Lie Ryan <lie.1296@gmail.com> - 2011-06-29 03:06 +1000
    Re: Using decorators with argument in Python John Posner <jjposner@codicesoftware.com> - 2011-06-29 13:23 -0400
    Re: Using decorators with argument in Python Ethan Furman <ethan@stoneleaf.us> - 2011-06-29 12:30 -0700
    Re: Using decorators with argument in Python Ian Kelly <ian.g.kelly@gmail.com> - 2011-06-29 13:29 -0600
    Re: Using decorators with argument in Python Ethan Furman <ethan@stoneleaf.us> - 2011-06-29 14:29 -0700
    Re: Using decorators with argument in Python Ian Kelly <ian.g.kelly@gmail.com> - 2011-06-29 15:26 -0600
    Re: Using decorators with argument in Python Ethan Furman <ethan@stoneleaf.us> - 2011-06-29 14:51 -0700
    Re: Using decorators with argument in Python Duncan Booth <duncan.booth@invalid.invalid> - 2011-06-30 09:00 +0000
    Re: Using decorators with argument in Python John Posner <jjposner@codicesoftware.com> - 2011-07-01 11:18 -0400
  Re: Using decorators with argument in Python Ian Kelly <ian.g.kelly@gmail.com> - 2011-06-28 11:20 -0600
  Re: Using decorators with argument in Python Ben Finney <ben+python@benfinney.id.au> - 2011-06-29 08:19 +1000

csiph-web