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