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


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

Is there a function that applies list of functions to a value?

Started byAdamKal <adamkalinski@gmail.com>
First post2013-08-28 05:52 -0700
Last post2013-08-29 23:06 -0700
Articles 20 on this page of 27 — 12 participants

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


Contents

  Is there a function that applies list of functions to a value? AdamKal <adamkalinski@gmail.com> - 2013-08-28 05:52 -0700
    Re: Is there a function that applies list of functions to a value? Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2013-08-28 16:10 +0300
      Re: Is there a function that applies list of functions to a value? fp2161@gmail.com - 2013-08-29 15:48 -0700
    Re: Is there a function that applies list of functions to a value? Tim Chase <python.list@tim.thechases.com> - 2013-08-28 08:11 -0500
      Re: Is there a function that applies list of functions to a value? Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2013-08-28 16:19 +0300
      Re: Is there a function that applies list of functions to a value? AdamKal <adamkalinski@gmail.com> - 2013-08-28 06:23 -0700
        Re: Is there a function that applies list of functions to a value? Chris Angelico <rosuav@gmail.com> - 2013-08-28 23:26 +1000
        Re: Is there a function that applies list of functions to a value? Tim Chase <python.list@tim.thechases.com> - 2013-08-28 08:43 -0500
          Re: Is there a function that applies list of functions to a value? AdamKal <adamkalinski@gmail.com> - 2013-08-28 06:50 -0700
    Re: Is there a function that applies list of functions to a value? ishish <ishish@domhain.de> - 2013-08-28 14:17 +0100
    Re: Is there a function that applies list of functions to a value? Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de> - 2013-08-28 15:09 +0200
    Re: Is there a function that applies list of functions to a value? Josh English <Joshua.R.English@gmail.com> - 2013-08-28 11:50 -0700
      Re: Is there a function that applies list of functions to a value? fp2161@gmail.com - 2013-08-29 23:17 -0700
        Re: Is there a function that applies list of functions to a value? alex23 <wuwei23@gmail.com> - 2013-08-30 16:36 +1000
          Re: Is there a function that applies list of functions to a value? Fabrice Pombet <fp2161@gmail.com> - 2013-08-30 01:11 -0700
    Re: Is there a function that applies list of functions to a value? fp2161@gmail.com - 2013-08-29 13:50 -0700
      Re: Is there a function that applies list of functions to a value? Chris Angelico <rosuav@gmail.com> - 2013-08-30 07:05 +1000
        Re: Is there a function that applies list of functions to a value? fp2161@gmail.com - 2013-08-29 14:27 -0700
          Re: Is there a function that applies list of functions to a value? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-08-30 02:18 +0000
          Re: Is there a function that applies list of functions to a value? Chris Angelico <rosuav@gmail.com> - 2013-08-30 07:35 +1000
            Re: Is there a function that applies list of functions to a value? fp2161@gmail.com - 2013-08-29 23:14 -0700
              Re: Is there a function that applies list of functions to a value? alex23 <wuwei23@gmail.com> - 2013-08-30 16:23 +1000
                Re: Is there a function that applies list of functions to a value? Fabrice Pombet <fp2161@gmail.com> - 2013-08-30 01:06 -0700
        Re: Is there a function that applies list of functions to a value? fp2161@gmail.com - 2013-08-29 14:48 -0700
          Re: Is there a function that applies list of functions to a value? Terry Reedy <tjreedy@udel.edu> - 2013-08-30 00:38 -0400
      Re: Is there a function that applies list of functions to a value? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-08-30 02:09 +0000
        Re: Is there a function that applies list of functions to a value? fp2161@gmail.com - 2013-08-29 23:06 -0700

Page 1 of 2  [1] 2  Next page →


#53149 — Is there a function that applies list of functions to a value?

FromAdamKal <adamkalinski@gmail.com>
Date2013-08-28 05:52 -0700
SubjectIs there a function that applies list of functions to a value?
Message-ID<aa168508-c469-4b02-9dc1-e0efd023d52b@googlegroups.com>
Hi, 

From time to time I have to apply a series of functions to a value in such a way:

func4(func3(func2(func1(myval))))

I was wondering if there is a function in standard library that would take a list of functions and a initial value and do the above like this:

func_im_looking_for([func1, func2, func3, func4], myval)

I looked in itertools but nothing seamed to do the job. This seams like something vary obvious that was needed many times elsewhere so maybe you could help me?

[toc] | [next] | [standalone]


#53151

FromJussi Piitulainen <jpiitula@ling.helsinki.fi>
Date2013-08-28 16:10 +0300
Message-ID<qotob8i9d0m.fsf@ruuvi.it.helsinki.fi>
In reply to#53149
AdamKal writes:

> Hi, 
> 
> From time to time I have to apply a series of functions to a value
> in such a way:
> 
> func4(func3(func2(func1(myval))))
> 
> I was wondering if there is a function in standard library that
> would take a list of functions and a initial value and do the above
> like this:
> 
> func_im_looking_for([func1, func2, func3, func4], myval)
> 
> I looked in itertools but nothing seamed to do the job. This seams
> like something vary obvious that was needed many times elsewhere so
> maybe you could help me?

If you can have things backwards, or have func_im_looking_for reverse
things first, you can do it this way:

from functools import reduce

def funcall(arg, fun): return fun(arg)

def func1(arg): return 'f1({})'.format(arg)
def func2(arg): return 'f2({})'.format(arg)
def func3(arg): return 'f3({})'.format(arg)

# prints: f1(f2(f3(3.14)))
print(reduce(funcall, (func3, func2, func1), 3.14))

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


#53262

Fromfp2161@gmail.com
Date2013-08-29 15:48 -0700
Message-ID<a0b1329b-20ff-4600-a4fc-2a9aa4529f78@googlegroups.com>
In reply to#53151
On Wednesday, August 28, 2013 3:10:49 PM UTC+2, Jussi Piitulainen wrote:
> AdamKal writes:
> 
> 
> 
> > Hi, 
> 
> > 
> 
> > From time to time I have to apply a series of functions to a value
> 
> > in such a way:
> 
> > 
> 
> > func4(func3(func2(func1(myval))))
> 
> > 
> 
> > I was wondering if there is a function in standard library that
> 
> > would take a list of functions and a initial value and do the above
> 
> > like this:
> 
> > 
> 
> > func_im_looking_for([func1, func2, func3, func4], myval)
> 
> > 
> 
> > I looked in itertools but nothing seamed to do the job. This seams
> 
> > like something vary obvious that was needed many times elsewhere so
> 
> > maybe you could help me?
> 
> 
> 
> If you can have things backwards, or have func_im_looking_for reverse
> 
> things first, you can do it this way:
> 
> 
> 
> from functools import reduce
> 
> 
> 
> def funcall(arg, fun): return fun(arg)
> 
> 
> 
> def func1(arg): return 'f1({})'.format(arg)
> 
> def func2(arg): return 'f2({})'.format(arg)
> 
> def func3(arg): return 'f3({})'.format(arg)
> 
> 
> 
> # prints: f1(f2(f3(3.14)))
> 
> print(reduce(funcall, (func3, func2, func1), 3.14))

I had never thought about the "f({0})".format(arg) trick, that is excellent, thank you!!!

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


#53152

FromTim Chase <python.list@tim.thechases.com>
Date2013-08-28 08:11 -0500
Message-ID<mailman.308.1377695427.19984.python-list@python.org>
In reply to#53149
On 2013-08-28 05:52, AdamKal wrote:
> From time to time I have to apply a series of functions to a value
> in such a way:
> 
> func4(func3(func2(func1(myval))))
> 
> I was wondering if there is a function in standard library that
> would take a list of functions and a initial value and do the above
> like this:
> 
> func_im_looking_for([func1, func2, func3, func4], myval)

At least in Py2.x you can use reduce:

  reduce(lambda value, fn: fn(value), [list_of_functions], myval)

I believe it was moved into functools.reduce() in Py3.x meaning you
might want to do something like

  try:
    reduce # see if it's already in __builtins__
  except NameError: # running Py3...
    from functools import reduce

or

  try:
    from functools import reduce
  except ImportError:
    pass  # it should already be in __builtins__ for pre-2.6

at the top to make sure it's in your global namespace.

-tkc


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


#53155

FromJussi Piitulainen <jpiitula@ling.helsinki.fi>
Date2013-08-28 16:19 +0300
Message-ID<qotioyq9cll.fsf@ruuvi.it.helsinki.fi>
In reply to#53152
Tim Chase writes:

> On 2013-08-28 05:52, AdamKal wrote:
> > From time to time I have to apply a series of functions to a value
> > in such a way:
> > 
> > func4(func3(func2(func1(myval))))
> > 
> > I was wondering if there is a function in standard library that
> > would take a list of functions and a initial value and do the above
> > like this:
> > 
> > func_im_looking_for([func1, func2, func3, func4], myval)
> 
> At least in Py2.x you can use reduce:
> 
>   reduce(lambda value, fn: fn(value), [list_of_functions], myval)

I notice now that I didn't notice, when I just sent the same solution,
that the function list was already backwards to its intended order of
application, so yes, this should work as wanted.

Sorry.

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


#53157

FromAdamKal <adamkalinski@gmail.com>
Date2013-08-28 06:23 -0700
Message-ID<21b63d71-14ce-4a59-9e5a-092156832d0b@googlegroups.com>
In reply to#53152
Thanks! 

I guess this is as simple as it gets then. I was just looking for the "one obvious way to do it".

W dniu środa, 28 sierpnia 2013 15:11:34 UTC+2 użytkownik Tim Chase napisał:
> On 2013-08-28 05:52, AdamKal wrote:
> 
> > From time to time I have to apply a series of functions to a value
> 
> > in such a way:
> 
> > 
> 
> > func4(func3(func2(func1(myval))))
> 
> > 
> 
> > I was wondering if there is a function in standard library that
> 
> > would take a list of functions and a initial value and do the above
> 
> > like this:
> 
> > 
> 
> > func_im_looking_for([func1, func2, func3, func4], myval)
> 
> 
> 
> At least in Py2.x you can use reduce:
> 
> 
> 
>   reduce(lambda value, fn: fn(value), [list_of_functions], myval)
> 
> 
> 
> I believe it was moved into functools.reduce() in Py3.x meaning you
> 
> might want to do something like
> 
> 
> 
>   try:
> 
>     reduce # see if it's already in __builtins__
> 
>   except NameError: # running Py3...
> 
>     from functools import reduce
> 
> 
> 
> or
> 
> 
> 
>   try:
> 
>     from functools import reduce
> 
>   except ImportError:
> 
>     pass  # it should already be in __builtins__ for pre-2.6
> 
> 
> 
> at the top to make sure it's in your global namespace.
> 
> 
> 
> -tkc

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


#53158

FromChris Angelico <rosuav@gmail.com>
Date2013-08-28 23:26 +1000
Message-ID<mailman.310.1377696411.19984.python-list@python.org>
In reply to#53157
On Wed, Aug 28, 2013 at 11:23 PM, AdamKal <adamkalinski@gmail.com> wrote:
> I guess this is as simple as it gets then. I was just looking for the "one obvious way to do it".

The one obvious way to do some things is to post on python-list and
see what comes back :) I love reading over these sorts of threads,
they're good fun.

ChrisA

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


#53159

FromTim Chase <python.list@tim.thechases.com>
Date2013-08-28 08:43 -0500
Message-ID<mailman.311.1377697347.19984.python-list@python.org>
In reply to#53157
On 2013-08-28 06:23, AdamKal wrote:
> Thanks! 
> 
> I guess this is as simple as it gets then. I was just looking for
> the "one obvious way to do it".

When 3 replies from 3 people all arrive within minutes, each
suggesting reduce(), I'd figure it's the "one obvious way to do
it" :-)

-tkc


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


#53160

FromAdamKal <adamkalinski@gmail.com>
Date2013-08-28 06:50 -0700
Message-ID<72faeeaa-d1aa-4514-bde6-23b943ea8e6e@googlegroups.com>
In reply to#53159
W dniu środa, 28 sierpnia 2013 15:43:39 UTC+2 użytkownik Tim Chase napisał:
 
> When 3 replies from 3 people all arrive within minutes, each
> suggesting reduce(), I'd figure it's the "one obvious way to do 
> it" :-)

I guess it's at least a good hint ;)


Thanks to all! :)

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


#53154

Fromishish <ishish@domhain.de>
Date2013-08-28 14:17 +0100
Message-ID<mailman.309.1377695867.19984.python-list@python.org>
In reply to#53149
Am 28.08.2013 13:52, schrieb AdamKal:
> Hi,
>
> From time to time I have to apply a series of functions to a value in
> such a way:
>
> func4(func3(func2(func1(myval))))
>
> I was wondering if there is a function in standard library that would
> take a list of functions and a initial value and do the above like
> this:
>
> func_im_looking_for([func1, func2, func3, func4], myval)
>
> I looked in itertools but nothing seamed to do the job. This seams
> like something vary obvious that was needed many times elsewhere so
> maybe you could help me?

You could try somthing like:


myval = 'whatever'

for i in range(1,4):
	print eval("func%s(%s)" % (i, myval))

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


#53156

FromThomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de>
Date2013-08-28 15:09 +0200
Message-ID<kvksrc$6lr$1@r01.glglgl.de>
In reply to#53149
Am 2013-08-28 14:52 schrieb AdamKal:
> Hi,
>
>  From time to time I have to apply a series of functions to a value in such a way:
>
> func4(func3(func2(func1(myval))))
>
> I was wondering if there is a function in standard library that would take a list of functions and a initial value and do the above like this:
>
> func_im_looking_for([func1, func2, func3, func4], myval)
>
> I looked in itertools but nothing seamed to do the job. This seams like something vary obvious that was needed many times elsewhere so maybe you could help me?

reduce(lambda x, f: f(x), funcs, myval)

would do the job.


Thomas

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


#53179

FromJosh English <Joshua.R.English@gmail.com>
Date2013-08-28 11:50 -0700
Message-ID<cf0fa304-1965-4173-89cd-6167a3427439@googlegroups.com>
In reply to#53149
Reduce tricks are nice, but I prefer clarity sometimes:

def double(x):
    return x*2

def add3(x):
    return x+3


def compose(*funcs):
    for func in funcs:
        if not callable(func):
            raise ValueError('Must pass callable functions')

    def inner(value):
        for func in funcs:
            value = func(value)
        return value

    return inner


add_then_double = compose(add3, double)
double_then_add = compose(double, add3)

print add_then_double(1) # prints 8
print double_then_add(1) # prints 5

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


#53279

Fromfp2161@gmail.com
Date2013-08-29 23:17 -0700
Message-ID<7867a7cb-e419-4f2e-8d3d-30862de93014@googlegroups.com>
In reply to#53179
On Wednesday, August 28, 2013 8:50:53 PM UTC+2, Josh English wrote:
> Reduce tricks are nice, but I prefer clarity sometimes:
> 
> 
> 
> def double(x):
> 
>     return x*2
> 
> 
> 
> def add3(x):
> 
>     return x+3
> 
> 
> 
> 
> 
> def compose(*funcs):
> 
>     for func in funcs:
> 
>         if not callable(func):
> 
>             raise ValueError('Must pass callable functions')
> 
> 
> 
>     def inner(value):
> 
>         for func in funcs:
> 
>             value = func(value)
> 
>         return value
> 
> 
> 
>     return inner
> 
> 
> 
> 
> 
> add_then_double = compose(add3, double)
> 
> double_then_add = compose(double, add3)
> 
> 
> 
> print add_then_double(1) # prints 8
> 
> print double_then_add(1) # prints 5


This is my favourite design, simple, clear, straightforward, very pythonic imho.  So great that I actually dod not notice it, and wrote it again after you! Imho still, the ValueError you are raising is not that important in this context, it would raise an Error anyway.

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


#53281

Fromalex23 <wuwei23@gmail.com>
Date2013-08-30 16:36 +1000
Message-ID<kvpehq$b6g$1@dont-email.me>
In reply to#53279
On 30/08/2013 4:17 PM, fp2161@gmail.com wrote:
> On Wednesday, August 28, 2013 8:50:53 PM UTC+2, Josh English wrote:
>> def compose(*funcs):
>>      for func in funcs:
>>          if not callable(func):
>>              raise ValueError('Must pass callable functions')

> Imho still, the ValueError you are raising is not that important in this context, it would raise an Error anyway.

The main advantage with Josh's approach is that it fails at the point of 
composition, not when the composed function is first used.  It'd be even 
more useful if it aggregated a list of the failing functions and 
returned their names as part of the error.

Personally, I'd go with an assertion:

     assert all(map(callable, funcs)), "Must pass callable functions"

I find that it makes it more obvious that this is part of the function 
contract rather than the actual body.

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


#53286

FromFabrice Pombet <fp2161@gmail.com>
Date2013-08-30 01:11 -0700
Message-ID<b441d980-52ae-4982-85fd-c18edfd8d8d6@googlegroups.com>
In reply to#53281
On Friday, August 30, 2013 8:36:40 AM UTC+2, alex23 wrote:
> On 30/08/2013 4:17 PM, fp2161@gmail.com wrote:
> 
> > On Wednesday, August 28, 2013 8:50:53 PM UTC+2, Josh English wrote:
> 
> >> def compose(*funcs):
> 
> >>      for func in funcs:
> 
> >>          if not callable(func):
> 
> >>              raise ValueError('Must pass callable functions')
> 
> 
> 
> > Imho still, the ValueError you are raising is not that important in this context, it would raise an Error anyway.
> 
> 
> 
> The main advantage with Josh's approach is that it fails at the point of 
> 
> composition, not when the composed function is first used.  It'd be even 
> 
> more useful if it aggregated a list of the failing functions and 
> 
> returned their names as part of the error.
> 
> 
> 
> Personally, I'd go with an assertion:
> 
> 
> 
>      assert all(map(callable, funcs)), "Must pass callable functions"
> 
> 
> 
> I find that it makes it more obvious that this is part of the function 
> 
> contract rather than the actual body.

it is a valid point, but I would contend that it makes this quick and easy code a little bit heavy just for the sake of ensuring that you are composing composable functions... The assertion is definitely better.

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


#53255

Fromfp2161@gmail.com
Date2013-08-29 13:50 -0700
Message-ID<90afb50e-7932-4e05-a90d-7005e1de91b8@googlegroups.com>
In reply to#53149
On Wednesday, August 28, 2013 2:52:46 PM UTC+2, AdamKal wrote:
> Hi, 
> 
> 
> 
> From time to time I have to apply a series of functions to a value in such a way:
> 
> 
> 
> func4(func3(func2(func1(myval))))
> 
> 
> 
> I was wondering if there is a function in standard library that would take a list of functions and a initial value and do the above like this:
> 
> 
> 
> func_im_looking_for([func1, func2, func3, func4], myval)
> 
> 
> 
> I looked in itertools but nothing seamed to do the job. This seams like something vary obvious that was needed many times elsewhere so maybe you could help me?


My way is so obvious that it may not be that interesting...

def func4(f1,f2,f3,f4):
    def anon(x):
        f1(f2(f3(f4(x))))
    return anon

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


#53258

FromChris Angelico <rosuav@gmail.com>
Date2013-08-30 07:05 +1000
Message-ID<mailman.373.1377810340.19984.python-list@python.org>
In reply to#53255
On Fri, Aug 30, 2013 at 6:50 AM,  <fp2161@gmail.com> wrote:
> My way is so obvious that it may not be that interesting...
>
> def func4(f1,f2,f3,f4):
>     def anon(x):
>         f1(f2(f3(f4(x))))
>     return anon

Or have it return the result of f1. And then, since it's an anonymous
function that simply returns an expression, I'd write it as:

def func4(f1,f2,f3,f4):
    return lambda x: f1(f2(f3(f4(x))))

Of course, that's still restricted to precisely four args. Extending
this concept to a variable number of arguments is, uhh, left as an
exercise to the reader. Which will probably end up going back to
reduce(). :)

ChrisA

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


#53259

Fromfp2161@gmail.com
Date2013-08-29 14:27 -0700
Message-ID<6e80de10-56c8-4be9-ac88-bc072c409a76@googlegroups.com>
In reply to#53258
On Thursday, August 29, 2013 11:05:38 PM UTC+2, Chris Angelico wrote:
> On Fri, Aug 30, 2013 at 6:50 AM,  <fp2161@gmail.com> wrote:
> 
> > My way is so obvious that it may not be that interesting...
> 
> >
> 
> > def func4(f1,f2,f3,f4):
> 
> >     def anon(x):
> 
> >         f1(f2(f3(f4(x))))
> 
> >     return anon
> 
> 
> 
> Or have it return the result of f1. And then, since it's an anonymous
> 
> function that simply returns an expression, I'd write it as:
> 
> 
> 
> def func4(f1,f2,f3,f4):
> 
>     return lambda x: f1(f2(f3(f4(x))))
> 
> 
> 
> Of course, that's still restricted to precisely four args. Extending
> 
> this concept to a variable number of arguments is, uhh, left as an
> 
> exercise to the reader. Which will probably end up going back to
> 
> reduce(). :)
> 
> 
> 
> ChrisA

Chris, call me a snob, but I resent using lambdas (aren't they usually considered odd/bad practice in python?)

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


#53269

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-08-30 02:18 +0000
Message-ID<52200111$0$6599$c3e8da3$5496439d@news.astraweb.com>
In reply to#53259
On Thu, 29 Aug 2013 14:27:23 -0700, fp2161 wrote:

> Chris, call me a snob, but I resent using lambdas (aren't they usually
> considered odd/bad practice in python?)

Only among people who dislike functional programming idioms. Like GvR.

It is true that lambda functions are slightly restricted compared to 
"normal" functions: they are limited to a single expression, and they all 
share the same name '<lambda>', which if you have a lot of them can make 
debugging annoying. So *overuse* of lambdas is considered bad form. But 
for callbacks and such, they're fine.

It is frowned upon to *directly* bind a lambda to a name, as in this:

plusOne = lambda x: x+1

instead of:

def plusOne(x): return x+1


which is fair enough for production code, but at the interactive 
interpreter (and throwaway code) I'll continue to feel free to assign 
anonymous functions to names just as I assign anonymous ints and 
anonymous lists to names :-)

I say "directly" because this of course is allowed:

funcs = [lambda x: x+1, lambda x: x*2, lambda x: x**3]
for func in func:
    ...


and *much* better than having to predefine plusOne, timesTwo, powerThree 
functions.



-- 
Steven

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


#53272

FromChris Angelico <rosuav@gmail.com>
Date2013-08-30 07:35 +1000
Message-ID<mailman.378.1377833511.19984.python-list@python.org>
In reply to#53259
On Fri, Aug 30, 2013 at 7:27 AM,  <fp2161@gmail.com> wrote:
> Chris, call me a snob, but I resent using lambdas (aren't they usually considered odd/bad practice in python?)

They're not bad practice; all they are is a function without a name,
that's restricted to returning a single expression. So they're
perfectly suited to this task, and ill-suited to some others.

Like everything, lambda's a tool that can be used or misused.

ChrisA

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


Page 1 of 2  [1] 2  Next page →

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


csiph-web