python命令式编程的概念,【Python】十分钟学会函数式编程

点击上方“小白学视觉”,选择加"星标"或“置顶”重磅干货,第一时间送达

2_1614844576358.jpg本文转自:深度学习这点小事

2_1614841943925.jpg

函数式编程到底是什么?本文将详解其概念,同时分享怎样在 Python 中使用函数式编程。主要内容包括列表解析式和其他形式的解析式。函数式模型

在命令式模型中,执行程序的方式是给计算机一系列指令让它执行。执行过程中计算机会改变状态。例如,比如 A 的初始值是 5,后来改变了 A 的值。那么 A 就是个变量,而变量的意思就是包含的值会改变。

而在函数式模式中,你不需要告诉计算机做什么,而是告诉计算机是什么。比如数字的最大公约数是什么,1 到 n 的乘积是什么等等。

因此,变量是不能被改变的。变量一旦被设置,就永远保持同一个值(注意在纯粹的函数式语言中,它们不叫变量)。因此,在函数式模型中,函数没有副作用。副作用就是函数对函数外的世界做出的改变。来看看下面这段Python代码的例子:a = 3

def some_func():

global a

a = 5

some_func()

print(a)

代码的输出是 5。在函数式模型中,改变变量的值是完全不允许的,让函数影响函数外的世界也是不允许的。函数唯一能做的就是做一些计算然后返回一个值。

你可能会想:“没有变量也没有副作用?这有什么好的?”好问题。

如果函数使用同样的参数调用两次,那么我们可以保证它会返回同样的结果。如果你学过数学函数,你肯定知道这样做的好。这叫做引用透明性(referential transparency)。由于函数没有副作用,那么我们可以加速计算某个东西的程序。比如,如果程序知道 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中的这种懒惰。映射

要理解映射(map),首先需要理解什么是可迭代对象。可迭代对象(iterable)指任何可以迭代的东西。通常是列表或数组,但 Python 还有许多其他可迭代对象。甚至可以自定义对象,通过实现特定的魔术方法使其变成可迭代对象。魔术方法就像 API 一样,能让对象更有 Python 风格。要让对象变成可迭代对象,需要实现以下两个魔术方法: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)返回迭代子,通常在循环开始时调用。__next__则返回迭代的下一个对象。

可以打开命令行试一下下面的代码:for c in Counter(3, 8):

print(c)

这段代码将会输出:3

4

5

6

7

8

在 Python 中,迭代器就是只实现了__iter__魔术方法的对象。也就是说,你可以访问对象中都包含的位置,但无法遍历整个对象。一些对象实现了__next__魔术方法,但没有实现__iter__魔术方法,比如集合(本文稍后会讨论)。在本文中,我们假设涉及到的一切对象都是可迭代的对象。

现在我们知道了什么是可迭代的对象,回过头来讨论下映射函数。映射可以对可迭代对象中的每个元素执行指定的函数。通常,我们对列表中的每个元素执行函数,但要知道映射其实可以针对绝大多数可迭代对象使用。map(function, iterable)

假设有一个列表由以下数字组成:[1, 2, 3, 4, 5]

我们希望得到每个数字的平方,那么代码可以写成这样:x = [1, 2, 3, 4, 5]

def square(num):

return num*num

print(list(map(square, x)))

Python中的函数式函数是懒惰的。如果我们不加“list()”,那么函数只会将可迭代对象保存下来,而不会保存结果的列表。我们需要明确地告诉Python“把它转换成列表”才能得到结果。

在Python中一下子从不懒惰的函数求值转换到懒惰的函数似乎有点不适应。但如果你能用函数式的思维而不是过程式的思维,那么最终会适应的。

这个“square(num)”的确不错,但总觉得有点不对劲。难道为了仅使用一次的map就得定义整个函数吗?其实我们可以使用lambda函数(匿名函数)。Lambda 表达式

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表达式,所有参数都放在左边,操作都放在右边。虽然看上去有点乱,但不能否认它的作用。实际上能写出只有懂得函数式编程的人才能看懂的代码还是有点小兴奋的。而且把函数变成一行也非常酷。归纳

归纳(reduce)是个函数,它把一个可迭代对象变成一个东西。通常,我们在列表上进行计算,将列表归纳成一个数字。归纳的代码看起来长这样:reduce(function, list)

上面的函数可以使用lambda表达式。

列表的乘积就是把所有数字乘到一起。可以这样写代码:product = 1

x = [1, 2, 3, 4]

for num in x:

product = product * num

但使用归纳,可以写成这样:from functools import reduce

product = reduce((lambda x, y: x * y),[1, 2, 3, 4])

这样能得到同样的结果。这段代码更短,而且借助函数式编程,这段代码更简洁。过滤

过滤(filter)函数接收一个可迭代对象,然后过滤掉对象中一切不需要的东西。

通常过滤接收一个函数和一个列表。它会针对列表中的每个元素执行函数,如果函数返回True,则什么都不做。如果函数返回False,则从列表中去掉那个元素。

语法如下:filter(function, list)

我们来看一个简单的例子。没有过滤,代码要写成这样:x = range(-5, 5)

new_list = []

for num in x:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值