The most pythonic form to display a series of statements?
This is what annoyed me for a while. I learned Haskell before I learned Python, so I always thought of many computations as comparing to a list. It expresses nicely in list comprehension (I give the pythonic version here):
result = [ f(x) for x in list ]
In many cases, however, we want to execute more than one statement in x, for example:
result = [ f(g(h(x))) for x in list ]
It quickly becomes awkward and difficult to read.
My normal solution is to expand this back into a for loop:
result = []
for x in list:
x0 = h(x)
x1 = g(x0)
x2 = f(x1)
result.append(x2)
One thing that bothers me is that I don't need to initialize an empty result "result". It's trivial, but it makes me unhappy. I was wondering if there are alternative equivalent forms. One way might be using a local function (is this what they call in Python?)
def operation(x):
x0 = h(x)
x1 = g(x0)
x2 = f(x1)
return x2
result = [ operation(x) for x in list ]
Are there any particular advantages / disadvantages for either of the two forms above? Or maybe a more elegant way?
source to share
You can easily compose functions in Python.
Here's how to create a new function that is a collection of existing functions.
>>> def comp( a, b ):
def compose( args ):
return a( b( args ) )
return compose
>>> def times2(x): return x*2
>>> def plus1(x): return x+1
>>> comp( times2, plus1 )(32)
66
Here is a more complete recipe for the composition of a function . This should make it less awkward.
source to share
Follow the style that best suits your tastes.
I wouldn't worry about performance; only if you really see some kind of problem can you try switching to a different style.
Here are some other possible suggestions besides your suggestions:
result = [f(
g(
h(x)
)
)
for x in list]
Use progressive lists:
result = [h(x) for x in list]
result = [g(x) for x in result]
result = [f(x) for x in result]
Again, this is just a matter of style and taste. Pick the one that you like the most and stick with it :-)
source to share
If you do this often, and with several different statements, you could write something like
def seriesoffncs(fncs,x):
for f in fncs[::-1]:
x=f(x)
return x
where fncs is a list of functions. so consecutive sequences ((f, g, h), x) will return F (G (H (x))). This way, if you later in your code need to practice h (q (g (f (x))), you just execute the selector sequences ((h, q, g, f), x) instead of creating a new function operations for each combination of functions.
source to share
If your question is only about the last result, your last answer is the best. It is clear to anyone looking at what you are doing.
I often take any code that starts to get complex and translates it into a function. This mainly serves as a comment for this block of code. (any complex code probably needs to be rewritten anyway, and by inserting it into a function I can go back and work on it later)
def operation(x):
x0 = h(x)
x1 = g(x0)
x2 = f(x1)
return x2
result = [ operation(x) for x in list]
source to share
Dagw.myopenid.com option :
def chained_apply(*args):
val = args[-1]
for f in fncs[:-1:-1]:
val=f(val)
return val
Instead of serial ((h, q, g, f), x) you can now call:
result = chained_apply(foo, bar, baz, x)
source to share
As far as I know, there is no built-in / native syntax for composition in Python, but you can write your own function to compose stuff without too much trouble.
def compose(*f):
return f[0] if len(f) == 1 else lambda *args: f[0](compose(*f[1:])(*args))
def f(x):
return 'o ' + str(x)
def g(x):
return 'hai ' + str(x)
def h(x, y):
return 'there ' + str(x) + str(y) + '\n'
action = compose(f, g, h)
print [action("Test ", item) for item in [1, 2, 3]]
Of course, regardless of understanding is not required.
print [compose(f, g, h)("Test ", item) for item in [1, 2, 3]]
This way of composing will work for any number of functions (well, up to the recursion limit) with any number of parameters for the inner function.
source to share
There are times when it's better to fall back on a for-loop, yes, but more often I prefer one of these approaches:
Use appropriate line breaks and indentation so that they can be read:
result = [blah(blah(blah(x)))
for x in list]
Or extract (enough) the logic into another function as you mentioned. But not necessarily local; Python programmers prefer flat nested structure if you can see a sane way to factorize functionality.
I also came to Python from the world of functional programming and shared your prejudices.
source to share