Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>This answer is completely re-worked. It incorporates a lot of observations from the other answers.</p> <p>As you can see, there is a lot of strong feelings surrounding the use of functional programming constructs in Python. There are three major groups of ideas here.</p> <p>First, almost everybody but the people who are most wedded to the purest expression of the functional paradigm agree that list and generator comprehensions are better and clearer than using <code>map</code> or <code>filter</code>. Your colleagues should be avoiding the use of <code>map</code> and <code>filter</code> if you are targeting a version of Python new enough to support list comprehensions. And you should be avoiding <code>itertools.imap</code> and <code>itertools.ifilter</code> if your version of Python is new enough for generator comprehensions.</p> <p>Secondly, there is a lot of ambivalence in the community as a whole about <code>lambda</code>. A lot of people are really annoyed by a syntax in addition to <code>def</code> for declaring functions, especially one that involves a keyword like <code>lambda</code> that has a rather strange name. And people are also annoyed that these small anonymous functions are missing any of the nice meta-data that describes any other kind of function. It makes debugging harder. Lastly the small functions declared by <code>lambda</code> are often not terribly efficient as they require the overhead of a Python function call each time they are invoked, which is frequently in an inner loop.</p> <p>Lastly, most (meaning > 50%, but most likely not 90%) people think that <code>reduce</code> is a little strange and obscure. I myself admit to having <code>print reduce.__doc__</code> whenever I want to use it, which isn't all that often. Though when I see it used, the nature of the arguments (i.e. function, list or iterator, scalar) speak for themselves.</p> <p>As for myself, I fall in the camp of people who think the functional style is often very useful. But balancing that thought is the fact that Python is not at heart a functional language. And overuse of functional constructs can make programs seem strangely contorted and difficult for people to understand.</p> <p>To understand when and where the functional style is very helpful and improves readability, consider this function in C++:</p> <pre><code>unsigned int factorial(unsigned int x) { int fact = 1; for (int i = 2; i &lt;= n; ++i) { fact *= i; } return fact } </code></pre> <p>This loop seems very simple and easy to understand. And in this case it is. But its seeming simplicity is a trap for the unwary. Consider this alternate means of writing the loop:</p> <pre><code>unsigned int factorial(unsigned int n) { int fact = 1; for (int i = 2; i &lt;= n; i += 2) { fact *= i--; } return fact; } </code></pre> <p>Suddenly, the loop control variable no longer varies in an obvious way. You are reduced to looking through the code and reasoning carefully about what happens with the loop control variable. Now this example is a bit pathological, but there are real-world examples that are not. And the problem is with the fact that the idea is repeated assignment to an existing variable. You can't trust the variable's value is the same throughout the entire body of the loop.</p> <p>This is a long recognized problem, and in Python writing a loop like this is fairly unnatural. You have to use a while loop, and it just looks wrong. Instead, in Python you would write something like this:</p> <pre><code>def factorial(n): fact = 1 for i in xrange(2, n): fact = fact * i; return fact </code></pre> <p>As you can see, the way you talk about the loop control variable in Python is not amenable to fooling with it inside the loop. This eliminates a lot of the problems with 'clever' loops in other imperative languages. Unfortunately, it's an idea that's semi-borrowed from functional languages.</p> <p>Even this lends itself to strange fiddling. For example, this loop:</p> <pre><code>c = 1 for i in xrange(0, min(len(a), len(b))): c = c * (a[i] + b[i]) if i &lt; len(a): a[i + 1] = a[a + 1] + 1 </code></pre> <p>Oops, we again have a loop that is difficult to understand. It superficially resembles a really simple and obvious loop, and you have to read it carefully to realize that one of the variables used in the loop's computation is being messed with in a way that will effect future runs of the loop.</p> <p>Again, a more functional approach to the rescue:</p> <pre><code>from itertools import izip c = 1 for ai, bi in izip(a, b): c = c * (ai + bi) </code></pre> <p>Now by looking at the code we have some strong indication (partly by the fact that the person is using this functional style) that the lists a and b are not modified during the execution of the loop. One less thing to think about.</p> <p>The last thing to be worried about is c being modified in strange ways. Perhaps it is a global variable and is being modified by some roundabout function call. To rescue us from this mental worry, here is a purely function approach:</p> <pre><code>from itertools import izip c = reduce(lambda x, ab: x * (ab[0] + ab[1]), izip(a, b), 1) </code></pre> <p>Very concise, and the structure tells us that x is purely an accumulator. It is a local variable everywhere it appear. The final result is unambiguously assigned to c. Now there is much less to worry about. The structure of the code removes several classes of possible error.</p> <p>That is why people might choose a functional style. It is concise and clear, at least if you understand what <code>reduce</code> and <code>lambda</code> do. There are large classes of problems that could afflict a program written in a more imperative style that you know won't afflict your functional style program.</p> <p>In the case of factorial, there is a very simple and clear way to write this function in Python in a functional style:</p> <pre><code>import operator def factorial(n): return reduce(operator.mul, xrange(2, n+1), 1) </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload