less 函数_10分钟学会Python函数式编程(第一部)

10分钟学会Python函数式编程

来源:https://medium.com/hackernoon/learn-functional-python-in-10-minutes-to-2d1651dece6f

翻译:老齐

在本文中,你将了解什么是函数式编程范式,以及如何在Python中实现函数式编程。你还将学习列表解析和其他形式的解析。


第一部

函数式编程范式

在命令式编程中,你通过给计算机一系列任务来解决问题。在执行任务时,它可以改变状态。例如,假设最初将A设置为5,随后你能更改A的值。变量的意义在于它的值是可变化的。

在函数式编程中,你不告诉计算机做什么,而是告诉它是什么。比如:一个数的最大公约数是多少,从1到n的乘积是多少,等等。

因此,变量的值不能改变。一旦设置了一个变量,它就永远保持这种状态(注意,在纯函数式编程语言中,它们不被称为变量)。所以,函数在函数式编程中没有副作用。所谓副作用是指函数改变了它外部的一些东西。让我们看一个典型的Python代码示例:

a = 3def some_func():    global a    a = 5some_func()print(a)

此代码的输出为5。在函数式编程中,改变变量的值是一个很大的禁忌,让函数影响作用域之外的东西也是一个很大的禁忌,函数唯一能做的就是计算并返回结果。

现在你可能会想:“没有变量,没有副作用,为何这么好呢?”问得好!你绝对是一个好奇宝宝。

用相同的参数调用两次函数,肯定会返回相同的结果。学过数学中的函数,都这么认为。这就是引用透明性。因为函数没有副作用,所以如果你正在构建一个用于计算的程序,你可以加快程序的速度。如果程序知道func(2) =3,我们可以将其存储在表格中。这可以防止程序在我们已经知道答案的情况下重复运行同一个函数。

通常,在函数式编程中,我们不使用循环,而是使用递归。递归是一个数学概念,意味着“自成一体”。递归函数反复将自身作为子函数来调用。下面是Python中递归函数的一个很好的例子:

def factorial_recursive(n):    # Base case: 1! = 1    if n == 1:        return 1    # Recursive case: n! = n * (n-1)!    else:        return n * factorial_recursive(n-1)

一些编程语言也很懒。这意味着他们直到最后一秒才开始计算或执行任何任务。如果你编写一些代码来执行2 + 2,那么只在你实际需要使用结果时,你的函数程序将才会计算这个值。我们很快就会探讨Python中的惰性。

2b60d43541b89986c61d417c13094f7e.png

Map

为了理解map,先了解可迭代对象。可迭代对象就是能够重复得到项的东西,比如列表或数组。Python有许多不同类型的可迭代对象。甚至可以通过“魔术方法”来创建你自己的可迭代对象,它就像调用API那样简单,让你创建一个可迭代对象:

class Counter:    def __init__(self, low, high):        # set class attributes inside the magic method __init__        # for "inistalise"        self.current = low        self.high = high    def __iter__(self):        # first magic method to make this object iterable        return self        def __next__(self):        # second magic method        if self.current > self.high:            raise StopIteration        else:            self.current += 1            return self.current - 1

第一个魔术方法:“__iter__” (在 iter两侧使用双下划线),返回实例对象自己。这种方法通常在循环开始时使用。

我们到终端界面并检验一下:

for c in Counter(3, 8):    print(c)

打印结果将会是:

345678

在Python中,迭代器是一个对象,它只有一个方法:__iter__。这意味着你可以访问对象中的位置,但不能遍历对象。有些对象将有方法__next__ ,而不是 __iter__ ,例如sets(本文稍后将讨论)。在本文中,我们假设我们所接触到的所有东西都是一个可迭代对象。

现在我们知道什么是可迭代对象了,让我们回到map函数。map函数允许我们把一个函数用于可迭代对象中的每一个项。通常我们希望把一个函数用于列表中的每一个项,但要知道:对于大多数可迭代对象来说,这是可能的。map接受2个输入:函数对象和可迭代对象。

map(function, iterable)

假设我们有这样的一个数字列表:

[1, 2, 3, 4, 5]

计算每个数字的平方,我们可以编写如下代码:

x = [1, 2, 3, 4, 5]def square(num):    return num*numprint(list(map(square, x)))

Python函数是编程中的函数是惰性加载的。如果不用list(),将返回迭代器对象,而不是列表本身。我们需要明确地告诉Python“把它变成一个列表”,以便使用它。

或许你对这种惰性计算感到唐突,如果你更多地用函数思维而不是命令思维,就会习惯的。

像上面那样,写一个square(num)这样的普通函数,是可以的,但不是最好的。我们必须定义一个完整的函数,才能在map中使用。更好的选择是直接使用lambda函数。

0344a1adc707f286a26a5920ec87afa3.png

Lambda表达式

lambda表达式是一个单行函数。例如:求平方。

square = lambda x: x * x

现在我们来运行这个函数:

>>> square(3)9

我听到你说:“参数在哪里? 这是什么鬼东西? 它看起来一点也不像函数。”

嗯,这有点令人困惑,但可以解释。我们给变量square赋值。看这部分:

lambda x:

告诉Python这是一个lambda函数,输入的参数名为x。冒号后面的任何内容都是对输入的操作,它会自动返回结果。

要将求平方的程序简化为一行,我们可以执行以下操作:

x = [1, 2, 3, 4, 5]print(list(map(lambda num: num * num, x)))

所以在lambda表达式中,所有的参数都在左边,你想用它们所做的事情都在右边。有点乱,没人能否认这一点。事实上,编写只有其他函数式程序员才能阅读的代码是一种乐趣。另外,使用函数并将其转换为一行代码也是非常酷的。

8b160b2a6fcb809d2578b4c3b141fc3d.png

Reduce

Reduce是一个函数,它可以将一个可迭代对象中各个元素“捏合”到一起。例如,对于列表中的数字,把它们执行某运算,得到一个数字。Reduce是这样的:

reduce(function, list)

我们可以(而且经常会)使用lambda表达式作为函数。

计算列表中每个数字的乘积,你可以编程:

product = 1x = [1, 2, 3, 4]for num in x:    product = product * num

但是使用reduce,你可以这样写:

from functools import reduceproduct = reduce((lambda x, y: x * y),[1, 2, 3, 4])

得到同样的乘积。代码较短,并且运用了函数式编程的知识,因此更简洁。

Filter

filter函数接受一个可迭代对象,并且过滤掉其中所有你不想要的东西。

通常filter接受一个函数和一个列表。它将函数应用于列表中的每个项。如果该函数返回True,则不执行任何操作。如果返回False,则从列表中删除该项。

语法如下:

filter(function, list)

来看一个小例子。如果不使用filter,我们可以这样写:

x = range(-5, 5)new_list = []for num in x:    if num < 0:        new_list.append(num)

使用filter,代码就变成了:

x = range(-5, 5)all_less_than_zero = list(filter(lambda num: num < 0, x))

以上是本文的第一部分,请继续阅读第二部分,包括以下内容:

  • 高阶函数
  • 偏函数应用
  • 函数式编程不是典型的Python
  • 列表解析
  • 其他解析

《Python大学实用教程》和《跟老齐学Python:轻松入门》是与本文内容配套的书籍,供读者参考。


欢迎关注“老齐教室”微信公众号 

阅读更多有深度的实用技术文章

0692f14f210e0696e89918ab1176e337.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值