为什么要用Python编程?

为什么要用Python编程?,python,functional-programming,Python,Functional Programming,在工作中,我们用一种非常标准的OO方式编写Python。最近,有几个人加入了功能性的行列。他们的代码现在包含了更多的lambda、map和reduces。我知道函数式语言有利于并发性,但在功能上编程Python真的有助于并发性吗?我只是想了解,如果我开始使用更多Python的功能特性,我会得到什么。我每天都在用Python编程,我不得不说,对OO或功能的太多“吹捧”可能会导致缺少优雅的解决方案。我相信这两种范式在解决某些问题时都有各自的优势——我认为这就是你知道使用什么方法的时候。当它为您提供一

在工作中,我们用一种非常标准的OO方式编写Python。最近,有几个人加入了功能性的行列。他们的代码现在包含了更多的lambda、map和reduces。我知道函数式语言有利于并发性,但在功能上编程Python真的有助于并发性吗?我只是想了解,如果我开始使用更多Python的功能特性,我会得到什么。

我每天都在用Python编程,我不得不说,对OO或功能的太多“吹捧”可能会导致缺少优雅的解决方案。我相信这两种范式在解决某些问题时都有各自的优势——我认为这就是你知道使用什么方法的时候。当它为您提供一个干净、可读、高效的解决方案时,请使用功能性方法。OO也是如此


这也是我喜欢Python的原因之一——它是一种多范式,让开发人员可以选择如何解决自己的问题。

标准函数filter()、map()和reduce()用于列表上的各种操作,三个函数都需要两个参数:一个函数和一个列表

我们可以定义一个单独的函数,并将其用作filter()等的参数,如果该函数被多次使用,或者如果该函数太复杂而无法在一行中编写,这可能是一个好主意。但是,如果只需要一次并且非常简单,则使用lambda构造生成(临时)匿名函数并将其传递给filter()更方便

这有助于提高代码的可读性和紧凑性。

使用这些函数也将证明是高效的,因为列表元素上的循环是用C完成的,这比python中的循环快一点


当需要维护状态时,必须使用面向对象的方法,除了抽象、分组等,如果需求非常简单,我会坚持使用函数式而不是面向对象编程。

这个答案完全是重新设计的。它包含了来自其他答案的大量观察结果

如您所见,在Python中使用函数式编程构造有很多强烈的感觉。这里有三组主要的想法

首先,几乎所有人都同意列表和生成器的理解比使用
map
filter
更好、更清晰,但最执着于函数范式最纯粹表达的人除外。如果您针对的Python版本足够新,可以支持列表理解,那么您的同事应该避免使用
map
filter
。如果您的Python版本足够新,可以理解生成器,那么您应该避免使用
itertools.imap
itertools.ifilter

第二,整个社区对
lambda
有很多矛盾心理。除了用于声明函数的
def
语法之外,很多人都对该语法感到恼火,尤其是涉及到具有相当奇怪名称的关键字
lambda
。人们还感到恼火的是,这些小型匿名函数缺少描述任何其他类型函数的良好元数据。这使得调试更加困难。最后,
lambda
声明的小函数通常效率不高,因为它们每次调用时都需要Python函数调用的开销,而Python函数调用通常在内部循环中

最后,大多数人(意思是>50%,但很可能不是90%)认为
reduce
有点奇怪和模糊。我自己承认,每当我想使用它时,我都会使用
打印reduce.\uuuuu doc\uuuuuu
,但这并不经常。虽然当我看到它被使用时,参数的性质(即函数、列表或迭代器、标量)说明了这一点

至于我自己,我属于那些认为功能性风格通常非常有用的人的阵营。但要平衡这一思想,Python本质上并不是一种函数式语言。过度使用函数结构会使程序看起来奇怪地扭曲,让人难以理解

<> P>了解函数样式在何时何地有帮助并提高可读性,请考虑C++中的这个函数:

unsigned int factorial(unsigned int x)
{
    int fact = 1;
    for (int i = 2; i <= n; ++i) {
        fact *= i;
    }
    return fact
 }
正如您所看到的,在Python中谈论循环控制变量的方式不适合在循环中愚弄它。这消除了其他命令式语言中“聪明”循环的许多问题。不幸的是,这是一个半借用函数式语言的概念

即使这样,也会产生奇怪的拨弄。例如,此循环:

c = 1
for i in xrange(0, min(len(a), len(b))):
    c = c * (a[i] + b[i])
    if i < len(a):
        a[i + 1] = a[a + 1] + 1
现在,通过查看代码,我们得到了一些强有力的指示(部分是因为此人正在使用这种函数式风格),即列表a和b在循环执行期间没有被修改。少考虑一件事

最不需要担心的是c被以奇怪的方式修改。也许它是一个全局变量,正在被某个循环函数调用修改。为了将我们从这种心理担忧中解救出来,这里有一个纯粹的函数方法:

from itertools import izip
c = reduce(lambda x, ab: x * (ab[0] + ab[1]), izip(a, b), 1)
非常简洁,结构告诉我们x是一个纯粹的累加器。它在任何地方都是局部变量。最终结果明确地分配给c。现在不用担心了。代码的结构消除了几种可能的错误

这就是为什么人们可能会选择功能性风格。它简洁明了,至少如果您了解
reduce
lambda
的作用。有大量的问题可能会影响以更命令式风格编写的程序,而您知道这些问题不会影响您的函数式程序

在factorial的情况下,有一种非常简单明了的方法可以在函数中用Python编写此函数
c = 1
for i in xrange(0, min(len(a), len(b))):
    c = c * (a[i] + b[i])
    if i < len(a):
        a[i + 1] = a[a + 1] + 1
from itertools import izip
c = 1
for ai, bi in izip(a, b):
   c = c * (ai + bi)
from itertools import izip
c = reduce(lambda x, ab: x * (ab[0] + ab[1]), izip(a, b), 1)
import operator
def factorial(n):
    return reduce(operator.mul, xrange(2, n+1), 1)
inc = lambda x: x + 1
def inc(x): return x + 1
$ python -mtimeit -s'L=range(12,52)' 'reduce(lambda x,y: x*y, L, 1)'
100000 loops, best of 3: 18.3 usec per loop
$ python -mtimeit -s'L=range(12,52)' 'p=1' 'for x in L: p*=x'
100000 loops, best of 3: 10.5 usec per loop
$ python -mtimeit -s'import operator; L=range(12,52)' 'reduce(operator.mul, L, 1)'
100000 loops, best of 3: 10.7 usec per loop
thelist.sort(key=lambda s: len(s))
thelist.sort(key=len)
def imperative(seq):
    p = 1
    for x in seq:
        p *= x
    return p
import operator as ops

def functional(seq):
    return my.reduce(ops.mul, 1, seq)
def imperative(seq):
    p = 1
    for x in seq:
        p *= x
    return p

def imperative2(seq):
    p = 0
    for x in seq:
        p += x
    return p
def reduce(op, seq, init):
    rv = init
    for x in seq:
        rv = op(rv, x)
    return rv

def imperative(seq):
    return reduce(*, 1, seq)

def imperative2(seq):
    return reduce(+, 0, seq)
import operator as ops

def functional(seq):
    return my.reduce(ops.mul, 1, seq)

def functional2(seq):
    return my.reduce(ops.add, 0, seq)
import functools as func, operator as ops

functional  = func.partial(my.reduce, ops.mul, 1)
functional2 = func.partial(my.reduce, ops.add, 0)
import functools as func, operator as ops

reducer = func.partial(func.partial, my.reduce)
functional  = reducer(ops.mul, 1)
functional2 = reducer(ops.add, 0)
c := 0
for i := I step 1 until n do
   c := c + a[i] * b[i]
y = [i*2 for i in k if i % 3 == 0]