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


Groups > comp.lang.python > #110646 > unrolled thread

Meta decorator with parameters, defined in explicit functions

Started byBen Finney <ben+python@benfinney.id.au>
First post2016-06-28 15:02 +1000
Last post2016-07-01 23:53 -0600
Articles 20 on this page of 33 — 10 participants

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Meta decorator with parameters, defined in explicit functions Ben Finney <ben+python@benfinney.id.au> - 2016-06-28 15:02 +1000
    Re: Meta decorator with parameters, defined in explicit functions Paul Rubin <no.email@nospam.invalid> - 2016-06-27 23:08 -0700
    Re: Meta decorator with parameters, defined in explicit functions Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2016-06-28 18:39 +1000
    Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-06-29 19:43 -0700
      Re: Meta decorator with parameters, defined in explicit functions Steven D'Aprano <steve@pearwood.info> - 2016-06-30 13:49 +1000
      Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Peter Otten <__peter__@web.de> - 2016-06-30 09:25 +0200
        Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-06-30 00:43 -0700
          Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2016-06-30 18:00 +1000
          Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Peter Otten <__peter__@web.de> - 2016-06-30 10:41 +0200
      Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions dieter <dieter@handshake.de> - 2016-07-01 09:04 +0200
        Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-07-01 21:25 +0100
          Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Ben Finney <ben+python@benfinney.id.au> - 2016-07-02 11:52 +1000
          Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions dieter <dieter@handshake.de> - 2016-07-02 08:57 +0200
          Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions Ben Finney <ben+python@benfinney.id.au> - 2016-07-02 18:00 +1000
    Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-06-29 19:50 -0700
    Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-01 15:08 -0700
      Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-01 23:09 -0600
        Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-01 23:40 -0700
          Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-02 22:48 -0600
            Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-02 22:37 -0700
              Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-03 05:52 -0600
                Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-03 14:17 -0700
                  Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-03 16:38 -0600
                    Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-03 16:25 -0700
                      Re: Meta decorator with parameters, defined in explicit functions Chris Angelico <rosuav@gmail.com> - 2016-07-04 09:39 +1000
                        Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-03 16:59 -0700
                          Re: Meta decorator with parameters, defined in explicit functions Chris Angelico <rosuav@gmail.com> - 2016-07-04 10:06 +1000
                            Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-03 17:23 -0700
                      Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-03 18:01 -0600
                        Re: Meta decorator with parameters, defined in explicit functions Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-03 17:06 -0700
                          Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-03 18:20 -0600
      Re: Meta decorator with parameters, defined in explicit functions Ben Finney <ben+python@benfinney.id.au> - 2016-07-02 15:32 +1000
      Re: Meta decorator with parameters, defined in explicit functions Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-01 23:53 -0600

Page 1 of 2  [1] 2  Next page →


#110646 — Meta decorator with parameters, defined in explicit functions

FromBen Finney <ben+python@benfinney.id.au>
Date2016-06-28 15:02 +1000
SubjectMeta decorator with parameters, defined in explicit functions
Message-ID<mailman.61.1467090177.2358.python-list@python.org>
Howdy all,

I want an explicit replacement for a common decorator idiom.

There is a clever one-line decorator that has been copy-pasted without
explanation in many code bases for many years::

    decorator_with_args = lambda decorator: lambda *args, **kwargs: lambda func: decorator(func, *args, **kwargs)

My problem with this is precisely that it is clever: it explains nothing
about what it does, has many moving parts that are not named, it is
non-obvious and lacks expressiveness.

Even the widely-cited ActiveState recipe by Peter Hunt from 2005
<URL:http://code.activestate.com/recipes/465427-simple-decorator-with-arguments/>
gives no clue as to what this is doing internally nor what the names of
its parts should be.

I would like to see a more Pythonic, more explicit and expressive
replacement with its component parts easily understood.

-- 
 \     “[H]ow deep can a truth be — indeed, how true can it be — if it |
  `\             is not built from facts?” —Kathryn Schulz, 2015-10-19 |
_o__)                                                                  |
Ben Finney

[toc] | [next] | [standalone]


#110650

FromPaul Rubin <no.email@nospam.invalid>
Date2016-06-27 23:08 -0700
Message-ID<87y45ponf7.fsf@nightsong.com>
In reply to#110646
Ben Finney <ben+python@benfinney.id.au> writes:
>     decorator_with_args = lambda decorator: lambda *args, **kwargs:
> lambda func: decorator(func, *args, **kwargs)
> I would like to see a more Pythonic, more explicit and expressive
> replacement with its component parts easily understood.

How's this:

    from functools import partial
    def dwa(decorator):
        def wrap(*args,**kwargs):
                return partial(decorator, *args, **kwargs)
        return wrap

[toc] | [prev] | [next] | [standalone]


#110671

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2016-06-28 18:39 +1000
Message-ID<577237de$0$11110$c3e8da3@news.astraweb.com>
In reply to#110646
On Tuesday 28 June 2016 15:02, Ben Finney wrote:

> Howdy all,
> 
> I want an explicit replacement for a common decorator idiom.
> 
> There is a clever one-line decorator that has been copy-pasted without
> explanation in many code bases for many years::
> 
>     decorator_with_args = lambda decorator: lambda *args, **kwargs: lambda
>     func: decorator(func, *args, **kwargs)

I've never seen it before, and I'll admit I really had to twist my brain to 
understand it, but I came up with an example showing the traditional style of 
decorator-factory versus this meta-decorator.

# Standard idiom.

def chatty(name, age, verbose=True):  # the factory
    def decorator(func):  # the decorator returned by the factory
        if verbose:
            print("decorating function...")
        @functools.wraps(func)
        def inner(*args, **kwargs):
            print("Hi, my name is %s and I am %d years old!" % (name, age))
            return func(*args, **kwargs)
        return inner
    return decorator

@chatty("Bob", 99)
def calculate(x, y, z=1):
    return x+y-z


# Meta-decorator variant.

decorator_with_args = (lambda decorator: lambda *args, **kwargs: lambda func: 
decorator(func, *args, **kwargs))

@decorator_with_args
def chatty(func, name, age, verbose=True):
    if verbose:
        print("decorating function...")
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print("Hi, my name is %s and I am %d years old!" % (name, age))
        return func(*args, **kwargs)
    return inner

@chatty("Bob", 99)
def calculate(x, y, z=1):
    return x+y-1



I agree -- it's very clever, and completely opaque in how it works. The easy 
part is expanding the lambdas:

def decorator_with_args(decorator):
    def inner(*args, **kwargs):
        def innermost(func):
            return decorator(func, *args, **kwargs)
        return innermost
    return inner


but I'm not closer to having good names for inner and innermost than you.


-- 
Steve

[toc] | [prev] | [next] | [standalone]


#110798

FromLawrence D’Oliveiro <lawrencedo99@gmail.com>
Date2016-06-29 19:43 -0700
Message-ID<0690f476-95ad-4dec-87e5-42ecee07fdcd@googlegroups.com>
In reply to#110646
On Tuesday, June 28, 2016 at 5:03:08 PM UTC+12, Ben Finney wrote:
> There is a clever one-line decorator that has been copy-pasted without
> explanation in many code bases for many years::
> 
>     decorator_with_args = lambda decorator: lambda *args, **kwargs: lambda func: decorator(func, *args, **kwargs)
> 
> My problem with this is precisely that it is clever: it explains nothing
> about what it does, has many moving parts that are not named, it is
> non-obvious and lacks expressiveness.

It is written in a somewhat roundabout way: why not just

    decorator_with_args = lambda decorator, *args, **kwargs : lambda func : decorator(func, *args, **kwargs)

? Could it be this was not valid in earlier versions of Python?

Anyway, it’s a function of a function returning a function. Example use (off the top of my head):

    my_decorator = decorator_with_args(actual_func_to_call)(... remaining args for actual_func_to_call)

(for the original version) or

    my_decorator = decorator_with_args(actual_func_to_call,... remaining args for actual_func_to_call)

(for the simpler version). Then an example use would be

    @my_decorator
    def some_func...

which would call “actual_func_to_call” with some_func plus all those extra args, and assign the result back to some_func.

> I would like to see a more Pythonic, more explicit and expressive
> replacement with its component parts easily understood.

I don’t know why this fear and suspicion of lambdas is so widespread among Python users ... former Java/C# programmers, perhaps?

[toc] | [prev] | [next] | [standalone]


#110801

FromSteven D'Aprano <steve@pearwood.info>
Date2016-06-30 13:49 +1000
Message-ID<577496e3$0$1617$c3e8da3$5496439d@news.astraweb.com>
In reply to#110798
On Thu, 30 Jun 2016 12:43 pm, Lawrence D’Oliveiro wrote:

> On Tuesday, June 28, 2016 at 5:03:08 PM UTC+12, Ben Finney wrote:
>> There is a clever one-line decorator that has been copy-pasted without
>> explanation in many code bases for many years::
>> 
>>     decorator_with_args = lambda decorator: lambda *args, **kwargs:
>>     lambda func: decorator(func, *args, **kwargs)
>> 
>> My problem with this is precisely that it is clever: it explains nothing
>> about what it does, has many moving parts that are not named, it is
>> non-obvious and lacks expressiveness.
> 
> It is written in a somewhat roundabout way: why not just
> 
>     decorator_with_args = lambda decorator, *args, **kwargs : lambda func
>     : decorator(func, *args, **kwargs)
> 
> ? Could it be this was not valid in earlier versions of Python?

Your version has a much inferior API than the original. You can't wrap your
decorators ahead of time, you have to keep calling decorator_with_args each
time you want to use them. Contrast your version:


# LDO's version
import functools
decorator_with_args = (
        lambda decorator, *args, **kwargs : 
        lambda func : decorator(func, *args, **kwargs)
        )

def chatty(func, name, age, verbose=True):
    if verbose:
        print("decorating function...")
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print("Hi, my name is %s and I am %d years old!" % (name, age))
        return func(*args, **kwargs)
    return inner

@decorator_with_args(chatty, "Bob", 99)
def calculate(x, y, z=1):
    return x+y-z

@decorator_with_args(chatty, "Sue", 35, False)
def spam(n):
    return ' '.join(['spam']*n)



Here's the original. It's a much better API, as the decorator "chatty" only
needs to be wrapped once, rather than repeatedly. For a library, it means
that now you can expose "chatty" as a public function, and keep
decorator_with_args as an internal detail, instead of needing to make them
both public:


# original meta decorator version

import functools
decorator_with_args = (
        lambda decorator: 
        lambda *args, **kwargs: 
        lambda func: decorator(func, *args, **kwargs)
        )

@decorator_with_args
def chatty(func, name, age, verbose=True):
    if verbose:
        print("decorating function...")
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print("Hi, my name is %s and I am %d years old!" % (name, age))
        return func(*args, **kwargs)
    return inner

@chatty("Bob", 99)
def calculate(x, y, z=1):
    return x+y-z

@chatty("Sue", 35, False)
def spam(n):
    return ' '.join(['spam']*n)



Think of the use-case where you are the author of a library that provides
various decorators. `decorator_with_args` is an implementation detail of
your library: *you* say:

@decorator_with_args
def chatty(func, name, age, verbose=True): ...

@decorator_with_args
def logged(func, where_to_log): ...

@decorator_with_args
def memoise(func, cache_size): ...


and then offer chatty, logged and memoise as public functions to the users
of your library, who just write:

@memoise(1000)
def myfunc(arg): ...

etc. as needed. But with your version, you have to make decorator_with_args
a public part of the API, and require the user to write:

@decorator_with_args(memoise, 1000)
def myfunc(arg): ...


which I maintain is a much inferior API for the users of your library.



> I don’t know why this fear and suspicion of lambdas is so widespread among
> Python users ... former Java/C# programmers, perhaps?

Not so much fear as a little healthy respect for them, I think.




-- 
Steven
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.

[toc] | [prev] | [next] | [standalone]


#110825 — Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions

FromPeter Otten <__peter__@web.de>
Date2016-06-30 09:25 +0200
SubjectFear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions
Message-ID<mailman.127.1467271548.2358.python-list@python.org>
In reply to#110798
Lawrence D’Oliveiro wrote:

> On Tuesday, June 28, 2016 at 5:03:08 PM UTC+12, Ben Finney wrote:
> 
>> I would like to see a more Pythonic, more explicit and expressive
>> replacement with its component parts easily understood.
> 
> I don’t know why this fear and suspicion of lambdas is so widespread among
> Python users ... former Java/C# programmers, perhaps?

If there is "fear" I don't share it. However, for

foo = lambda <args>: <expr>

there is syntactic sugar in Python that allows you to write it as

def foo(<args>):
    return <expr>

with the nice side effects that it improves the readability of tracebacks 
and allows you to provide a docstring.

So yes, assigning a lambda to a name raises my "suspicion".

If a lambda is provided as an argument or as part of an expression I wonder 
how it is tested, and if even if it is trivial like

def reduce(items, func=lambda x, y: x + y): ...

the alternative

def reduce(items, func=add): ...

looks more readable in my eyes even though somewhere -- under the rug or in 
the operator module -- you need

def add(x, y):
   """
   >>> add(3, 4)
   7
   """
   return x + y

>>     decorator_with_args = lambda decorator: lambda *args, **kwargs: 
lambda func: decorator(func, *args, **kwargs)
> 
> Ah, I see why there are 3 lambdas, instead of 2. It’s so that you can 
write

I have a suspicion that there would not have been a correction "I see why 
there are three functions instead of two" ;)

[toc] | [prev] | [next] | [standalone]


#110828 — Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions

FromLawrence D’Oliveiro <lawrencedo99@gmail.com>
Date2016-06-30 00:43 -0700
SubjectRe: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions
Message-ID<3d4178b2-8484-417f-8d76-5a2154b2c5e1@googlegroups.com>
In reply to#110825
On Thursday, June 30, 2016 at 7:26:01 PM UTC+12, Peter Otten wrote:
> foo = lambda <args>: <expr>
> 
> there is syntactic sugar in Python that allows you to write it as
> 
> def foo(<args>):
>     return <expr>
> 
> with the nice side effects that it improves the readability of tracebacks 
> and allows you to provide a docstring.

True, but then again the original had three lambdas, so one line would have to become at least 3×2 = 6 lines, more if you want docstrings.

> def reduce(items, func=lambda x, y: x + y): ...

There was a reason why “reduce” was removed from being a builtin function in Python 2.x, to being banished to functools in Python 3.

> the alternative
> 
> def reduce(items, func=add): ...
> 
> looks more readable in my eyes even though somewhere ...

Just use “sum” in this case.

[toc] | [prev] | [next] | [standalone]


#110829 — Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2016-06-30 18:00 +1000
SubjectRe: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions
Message-ID<5774d1a2$0$1593$c3e8da3$5496439d@news.astraweb.com>
In reply to#110828
On Thursday 30 June 2016 17:43, Lawrence D’Oliveiro wrote:

> On Thursday, June 30, 2016 at 7:26:01 PM UTC+12, Peter Otten wrote:
>> foo = lambda <args>: <expr>
>> 
>> there is syntactic sugar in Python that allows you to write it as
>> 
>> def foo(<args>):
>>     return <expr>
>> 
>> with the nice side effects that it improves the readability of tracebacks
>> and allows you to provide a docstring.
> 
> True, but then again the original had three lambdas, so one line would have
> to become at least 3×2 = 6 lines, more if you want docstrings.

I hear that we've passed "Peak Newlines" now, so adding extra lines will get 
more and more expensive. I guess languages like C and Java will soon have to be 
abandoned, and everyone will move to writing minified Javascript and Perl one-
liners.


>> def reduce(items, func=lambda x, y: x + y): ...
> 
> There was a reason why “reduce” was removed from being a builtin function in
> Python 2.x, to being banished to functools in Python 3.

Yes, and that reason is that Guido personally doesn't like reduce.



-- 
Steve

[toc] | [prev] | [next] | [standalone]


#110832 — Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions

FromPeter Otten <__peter__@web.de>
Date2016-06-30 10:41 +0200
SubjectRe: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions
Message-ID<mailman.128.1467276097.2358.python-list@python.org>
In reply to#110828
Lawrence D’Oliveiro wrote:

> On Thursday, June 30, 2016 at 7:26:01 PM UTC+12, Peter Otten wrote:
>> foo = lambda <args>: <expr>
>> 
>> there is syntactic sugar in Python that allows you to write it as
>> 
>> def foo(<args>):
>>     return <expr>
>> 
>> with the nice side effects that it improves the readability of tracebacks
>> and allows you to provide a docstring.
> 
> True, but then again the original had three lambdas, so one line would
> have to become at least 3×2 = 6 lines, more if you want docstrings.
> 
>> def reduce(items, func=lambda x, y: x + y): ...
> 
> There was a reason why “reduce” was removed from being a builtin function
> in Python 2.x, to being banished to functools in Python 3.

You do understand what an example is?

 
>> the alternative
>> 
>> def reduce(items, func=add): ...
>> 
>> looks more readable in my eyes even though somewhere ...
> 
> Just use “sum” in this case.

Nah, the implementation is of course

def reduce(items, func=lambda x, y: x + y):
    """
    >>> list(reduce([1,2,3]))
    [1, 3, 6]

    >>> list(reduce([42]))
    [42]

    >>> reduce([])
    Traceback (most recent call last):
        ...
    TypeError: reduce() with empty sequence
    """
    items = iter(items)
    try:
        first = next(items)
    except StopIteration:
        raise TypeError("reduce() with empty sequence")

    def _reduce(accu=first):
        for item in items:
            yield accu
            accu = func(accu, item)
        yield accu

    return _reduce()

Yes, I'm kidding...

[toc] | [prev] | [next] | [standalone]


#110888 — Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions

Fromdieter <dieter@handshake.de>
Date2016-07-01 09:04 +0200
SubjectRe: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions
Message-ID<mailman.153.1467356702.2358.python-list@python.org>
In reply to#110798
Peter Otten <__peter__@web.de> writes:

> Lawrence D’Oliveiro wrote:
>
>> On Tuesday, June 28, 2016 at 5:03:08 PM UTC+12, Ben Finney wrote:
>> 
>>> I would like to see a more Pythonic, more explicit and expressive
>>> replacement with its component parts easily understood.
>> 
>> I don’t know why this fear and suspicion of lambdas is so widespread among
>> Python users ... former Java/C# programmers, perhaps?

Maybe, it's the name ("lambda").

In Javascript, anonymous functions are widespread (and extensively
used for e.g. callback definitions) - but it uses the much more familiar
"function" (rather than "lambda") for this purpose.

[toc] | [prev] | [next] | [standalone]


#110920 — Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-07-01 21:25 +0100
SubjectRe: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions
Message-ID<87bn2h85rn.fsf@bsb.me.uk>
In reply to#110888
dieter <dieter@handshake.de> writes:
<snip>
>> Lawrence D’Oliveiro wrote:
<snip>
>>> I don’t know why this fear and suspicion of lambdas is so widespread among
>>> Python users ... former Java/C# programmers, perhaps?

By replying I'm not accepting the premise -- I have no idea if there is
widespread fear and suspicion of lambdas among Python users but it seems
unlikely.

> Maybe, it's the name ("lambda").
>
> In Javascript, anonymous functions are widespread (and extensively
> used for e.g. callback definitions)

Yes, but in Python they are restricted to a single expression.  It's
therefore quite likely that programmers who want the semantics of an
anonymous function just define a named function and use that instead.
That saves you from having to decide, up front, if an expression is
going to be enough or from having to change it later if you find that it
isn't.

> - but it uses the much more familiar
> "function" (rather than "lambda") for this purpose.

... or the new arrow notation.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#110926 — Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions

FromBen Finney <ben+python@benfinney.id.au>
Date2016-07-02 11:52 +1000
SubjectRe: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions
Message-ID<mailman.7.1467424342.2295.python-list@python.org>
In reply to#110920
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> By replying I'm not accepting the premise -- I have no idea if there
> is widespread fear and suspicion of lambdas among Python users but it
> seems unlikely.

I can testify, as the person who started this thread, that there is no
fear or suspicion of lambda here. I use it quite frequently without
qualm for creating self-explanatory functions that need no name.

Rather, the motivation was that a complex thing, with many moving parts,
has an unexplained implementation: a nested set of functions without
names to explain their part in the pattern.

That these are then immediately bound to a name, to me defeats the
purpose of using lambda in the first place. If you want a named
function, lambda is not the tool to reach for; we have the ‘def’
statement for that.

But by using ‘lambda’ the author avoided one of the more important parts
of publishing the code: making it readable and self-explanatory. If
they'd chosen a name for each function, that would at least have
prompted them to explain what they're doing.

So ‘lambda’ is great, and I use it without worry for creating simple
self-explanatory nameless functions. But it's not the right tool for
this job: This is not self-explanatory, and the component functions
should not be nameless.

-- 
 \       “It is forbidden to steal hotel towels. Please if you are not |
  `\          person to do such is please not to read notice.” —hotel, |
_o__)                                               Kowloon, Hong Kong |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#110947 — Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions

Fromdieter <dieter@handshake.de>
Date2016-07-02 08:57 +0200
SubjectRe: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions
Message-ID<mailman.18.1467442638.2295.python-list@python.org>
In reply to#110920
Ben Finney <ben+python@benfinney.id.au> writes:
> ...
> Rather, the motivation was that a complex thing, with many moving parts,
> has an unexplained implementation: a nested set of functions without
> names to explain their part in the pattern.

In a previous reply, I have tried to explain (apparently without success)
that the "thing" is not "complex" at all but a simple signature
transform for a decorator definitition and that the nested function
implementation is natural for this purpose.

[toc] | [prev] | [next] | [standalone]


#110950 — Re: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions

FromBen Finney <ben+python@benfinney.id.au>
Date2016-07-02 18:00 +1000
SubjectRe: Fear and suspicion of lambdas, was Re: Meta decorator with parameters, defined in explicit functions
Message-ID<mailman.21.1467446458.2295.python-list@python.org>
In reply to#110920
dieter <dieter@handshake.de> writes:

> Ben Finney <ben+python@benfinney.id.au> writes:
> > ... Rather, the motivation was that a complex thing, with many
> > moving parts, has an unexplained implementation: a nested set of
> > functions without names to explain their part in the pattern.
>
> In a previous reply, I have tried to explain (apparently without
> success) that the "thing" is not "complex" at all

Your explanation was clear. I disagree with it; the code is not at all
obvious in its intention or operation.

Naming the parts descriptively, and writing a brief synopsis docstring
for each function, is a way to address that. Which is my motivation for
this thread.

> but a simple signature transform for a decorator definitition

You're making my case for me: To anyone who doesn't already know exactly
what's going on, that is not at all obvious from the code as presented
in the first message.

> and that the nested function implementation is natural for this
> purpose.

The nested function implementation is not the problem, as I hope I've
made clear elsewhere in this thread.

-- 
 \         “People's Front To Reunite Gondwanaland: Stop the Laurasian |
  `\              Separatist Movement!” —wiredog, http://kuro5hin.org/ |
_o__)                                                                  |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#110799

FromLawrence D’Oliveiro <lawrencedo99@gmail.com>
Date2016-06-29 19:50 -0700
Message-ID<d1508c7f-9f0e-42c4-92b1-bae9d8660291@googlegroups.com>
In reply to#110646
On Tuesday, June 28, 2016 at 5:03:08 PM UTC+12, Ben Finney wrote:
>     decorator_with_args = lambda decorator: lambda *args, **kwargs: lambda func: decorator(func, *args, **kwargs)

Ah, I see why there are 3 lambdas, instead of 2. It’s so that you can write

    decorator_func = decorator_with_args(actual_func)

then you can use it like this:

    @decorator_func(...additional args for actual_func...)
    def some_func...

to invoke actual_func(some_func, ... additional args for actual_func...) on some_func, and assign the result back to some_func.

[toc] | [prev] | [next] | [standalone]


#110921

FromLawrence D’Oliveiro <lawrencedo99@gmail.com>
Date2016-07-01 15:08 -0700
Message-ID<21916e7b-9e19-4cef-94e0-bac331540ca2@googlegroups.com>
In reply to#110646
On Tuesday, June 28, 2016 at 5:03:08 PM UTC+12, Ben Finney wrote:
> There is a clever one-line decorator that has been copy-pasted without
> explanation in many code bases for many years::
> 
>     decorator_with_args = lambda decorator: lambda *args, **kwargs: lambda func: decorator(func, *args, **kwargs)
> 

For those who want docstrings, I’ll give you docstrings:

    def decorator_with_args(decorator) :
        "given function decorator(func, *args, **kwargs), returns a decorator which," \
        " given func, returns the result of decorator(func, *args, **kwargs)."

        def decorate(*args, **kwargs) :

            def generated_decorator(func) :
                return \
                    decorator(func, *args, **kwargs)
            #end generated_decorator

        #begin decorate
            generated_decorator.__name__ = "decorator_{}".format(decorator.__name__)
            generated_decorator.__doc__ = "decorator which applies {} to the previously-specified arguments".format(decorator.__name__)
            return \
                generated_decorator
        #end decorate

    #begin decorator_with_args
        decorate.__name__ = "decorate_with_{}".format(decorator.__name__)
        decorate.__doc__ = "generates a decorator which applies {} to the given arguments".format(decorator.__name__)
        return \
            decorate
    #end decorator_with_args

[toc] | [prev] | [next] | [standalone]


#110942

FromIan Kelly <ian.g.kelly@gmail.com>
Date2016-07-01 23:09 -0600
Message-ID<mailman.15.1467436194.2295.python-list@python.org>
In reply to#110921
On Fri, Jul 1, 2016 at 4:08 PM, Lawrence D’Oliveiro
<lawrencedo99@gmail.com> wrote:
> On Tuesday, June 28, 2016 at 5:03:08 PM UTC+12, Ben Finney wrote:
>> There is a clever one-line decorator that has been copy-pasted without
>> explanation in many code bases for many years::
>>
>>     decorator_with_args = lambda decorator: lambda *args, **kwargs: lambda func: decorator(func, *args, **kwargs)
>>
>
> For those who want docstrings, I’ll give you docstrings:
>
>     def decorator_with_args(decorator) :
>         "given function decorator(func, *args, **kwargs), returns a decorator which," \
>         " given func, returns the result of decorator(func, *args, **kwargs)."
>
>         def decorate(*args, **kwargs) :
>
>             def generated_decorator(func) :
>                 return \
>                     decorator(func, *args, **kwargs)
>             #end generated_decorator
>
>         #begin decorate
>             generated_decorator.__name__ = "decorator_{}".format(decorator.__name__)
>             generated_decorator.__doc__ = "decorator which applies {} to the previously-specified arguments".format(decorator.__name__)
>             return \
>                 generated_decorator
>         #end decorate
>
>     #begin decorator_with_args
>         decorate.__name__ = "decorate_with_{}".format(decorator.__name__)
>         decorate.__doc__ = "generates a decorator which applies {} to the given arguments".format(decorator.__name__)

You should use functools.wraps instead of clobbering the decorated
function's name and docstring:

        @functools.wraps(decorator)
        def decorate(*args, **kwargs):
            ...

>         return \
>             decorate

Just to satisfy my own curiosity, do you have something against
putting the return keyword and the returned expression on the same
line?

[toc] | [prev] | [next] | [standalone]


#110946

FromLawrence D’Oliveiro <lawrencedo99@gmail.com>
Date2016-07-01 23:40 -0700
Message-ID<facf7142-25f5-4a8b-ab37-771884ab8d64@googlegroups.com>
In reply to#110942
On Saturday, July 2, 2016 at 5:10:06 PM UTC+12, Ian wrote:
> You should use functools.wraps instead of clobbering the decorated
> function's name and docstring:

Where am I doing that?
> Just to satisfy my own curiosity, do you have something against
> putting the return keyword and the returned expression on the same
> line?

Yes.

[toc] | [prev] | [next] | [standalone]


#110973

FromIan Kelly <ian.g.kelly@gmail.com>
Date2016-07-02 22:48 -0600
Message-ID<mailman.33.1467521333.2295.python-list@python.org>
In reply to#110946
On Sat, Jul 2, 2016 at 12:40 AM, Lawrence D’Oliveiro
<lawrencedo99@gmail.com> wrote:
> On Saturday, July 2, 2016 at 5:10:06 PM UTC+12, Ian wrote:
>> You should use functools.wraps instead of clobbering the decorated
>> function's name and docstring:
>
> Where am I doing that?

Using the implementation you posted:

>>> @decorator_with_args
... def my_decorator(func, *args, **kwargs):
...     """Returns func unmodified."""
...     return func
...
>>> my_decorator.__doc__
'generates a decorator which applies my_decorator to the given arguments'

[toc] | [prev] | [next] | [standalone]


#110976

FromLawrence D’Oliveiro <lawrencedo99@gmail.com>
Date2016-07-02 22:37 -0700
Message-ID<46690e10-1534-4f99-a40f-a148b4a21a27@googlegroups.com>
In reply to#110973
On Sunday, July 3, 2016 at 4:49:15 PM UTC+12, Ian wrote:
>
> On Sat, Jul 2, 2016 at 12:40 AM, Lawrence D’Oliveiro wrote:
>>
>> On Saturday, July 2, 2016 at 5:10:06 PM UTC+12, Ian wrote:
>>>
>>> You should use functools.wraps instead of clobbering the decorated
>>> function's name and docstring:
>>
>> Where am I doing that?
> 
> Using the implementation you posted:
> 
>>>> @decorator_with_args
> ... def my_decorator(func, *args, **kwargs):
> ...     """Returns func unmodified."""
> ...     return func
> ...
>>>> my_decorator.__doc__
> 'generates a decorator which applies my_decorator to the given arguments'

That is a function that I am generating, so naturally I want to give it a useful docstring. Am I “clobbering” any objects passed in by the caller, or returned by the caller? No, I am not.

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.python


csiph-web