Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #53149 > unrolled thread
| Started by | AdamKal <adamkalinski@gmail.com> |
|---|---|
| First post | 2013-08-28 05:52 -0700 |
| Last post | 2013-08-29 23:06 -0700 |
| Articles | 20 on this page of 27 — 12 participants |
Back to article view | Back to comp.lang.python
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 →
| From | AdamKal <adamkalinski@gmail.com> |
|---|---|
| Date | 2013-08-28 05:52 -0700 |
| Subject | Is 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]
| From | Jussi Piitulainen <jpiitula@ling.helsinki.fi> |
|---|---|
| Date | 2013-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]
| From | fp2161@gmail.com |
|---|---|
| Date | 2013-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]
| From | Tim Chase <python.list@tim.thechases.com> |
|---|---|
| Date | 2013-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]
| From | Jussi Piitulainen <jpiitula@ling.helsinki.fi> |
|---|---|
| Date | 2013-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]
| From | AdamKal <adamkalinski@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Tim Chase <python.list@tim.thechases.com> |
|---|---|
| Date | 2013-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]
| From | AdamKal <adamkalinski@gmail.com> |
|---|---|
| Date | 2013-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]
| From | ishish <ishish@domhain.de> |
|---|---|
| Date | 2013-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]
| From | Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de> |
|---|---|
| Date | 2013-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]
| From | Josh English <Joshua.R.English@gmail.com> |
|---|---|
| Date | 2013-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]
| From | fp2161@gmail.com |
|---|---|
| Date | 2013-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]
| From | alex23 <wuwei23@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Fabrice Pombet <fp2161@gmail.com> |
|---|---|
| Date | 2013-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]
| From | fp2161@gmail.com |
|---|---|
| Date | 2013-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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]
| From | fp2161@gmail.com |
|---|---|
| Date | 2013-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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