10分钟学会python编程_10分钟学会python函数式编程

在这篇文章里,你将学会什么是函数范式以及如何使用Python进行函数式编程。你也将了解列表推导和其它形式的推导。

函数范式

在命令式范式中,通过为计算机提供一系列指令然后执行它们来完成任务。在执行这些指令时,可以改变某些状态。例如,假设你最初将A设置为5,然后更改A的值。这时在变量内部值的意义上,你改变了A的状态。

在函数式范式中,你不用告诉计算机做什么而是告诉他这个东西是什么。比如数字的最大公约数是什么,从1到n的乘积是什么等等。

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

6479f53a4c4fb93b07df8277aee95a87.png

10分钟学会python函数式编程

这段代码的输出是5。在函数式范式中,改变变量是一个很大的禁忌,并且具有影响其范围之外事物的功能也是一个很大的禁忌。函数唯一能做的就是计算一些东西并将其作为结果返回。

现在你可能会想:“没有变量,没有副作用?为什么这样好?“这个问题问得好,我相信大多数人对此感到疑惑。

如果使用相同的参数调用函数两次,则保证返回相同的结果。如果你已经学习了数学函数,你就会知道这个好处。这称为参照透明度。由于函数没有副作用,如果你正在构建一个计算某些事情的程序,你可以加速程序。如果每次调用func(2)都返回3,我们可以将它存储在表中,这可以防止程序重复运行相同的功能。

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

3aed96f815c7e4ff1f83333444b034d1.png

10分钟学会python函数式编程

有些编程语言也具有惰性。这意味着他们直到最后一秒才计算或做任何事情。如果你编写一些代码来执行2 + 2,函数程序只会在你真正需要使用结果时计算出来。我们很快就会在Python中探索惰性。

Map

为了理解,我们先来看看迭代是什么。通常可以迭代的对象是列表或数组,但Python有许多不同的类型可以迭代。你甚至可以创建自己的对象,这些对象可以通过实现魔术方法进行迭代。魔术方法就像是一个API,可以帮助你的对象变得更加Pythonic。您需要实现2个魔术方法才能使对象成为可迭代的:

2d08e7b6140f8dd92367a684a8f76bfb.png

10分钟学会python函数式编程

第一个魔术方法“iter”(注:这里是双下划线)返回迭代对象,这通常在循环开始时使用。”next“返回下一个对象。

让我们快速进入一个终端调用上面的代码:

0cf6a75141bece623f39080249f87a55.png

10分钟学会python函数式编程

运行将会打印出

7928cb3e5cea07d70e5a933cf1d8aaed.png

10分钟学会python函数式编程

在Python中,迭代器是一个只有iter魔术方法的对象。这意味着您可以访问对象中的位置,但不能遍历该对象。一些对象将具有魔术方法next而不是iter魔术方法,例如集合(在本文后面讨论)。对于本文,我们假设我们接触的所有内容都是可迭代的对象。

现在我们知道什么是可迭代对象了,让我们回到map函数。 map函数允许我们将函数应用于iterable中的每一项。 Map需要2个输入,它们分别是要应用的函数和可迭代对象。

1f28043d86bd731f135a0ef52ea4356e.png

10分钟学会python函数式编程

假设我们有一个数字列表,如下所示:

d0173392f3f8174706dd1a85b0990285.png

10分钟学会python函数式编程

我们想要对每个数字进行平方,我们可以编写如下代码:

1b9a2be444d034496a11b891ccc6eb8e.png

10分钟学会python函数式编程

Python中函数式的函数是具有惰性的。如果我们不使用“list”,该函数将存储iterable的定义,而不是列表本身。我们需要明确告诉Python“把它变成一个列表”供我们使用。

在Python中突然从非惰性求值转向惰性求值有点奇怪。如果你在函数式思维方式中考虑得更多,而不是命令式思维方式,那么你最终会习惯它。

现在写一个像“square(num)”这样的普通函数虽然很好,但却是不对的。我们必须定义一个完整的函数才能在map中使用它?好吧,我们可以使用lambda(匿名)函数在map中定义一个函数。

Lambda表达式

lambda表达式是一个只有一行的函数。举个例子,这个lambda表达式对给定的数字进行平方:

3b9a1a70efe3acd80b20b92f03d4c6bd.png

10分钟学会python函数式编程

让我们运行它:

0e8894105a29a45b5cf5e2f08d908f29.png

10分钟学会python函数式编程

这看起来不像一个函数吗?

嗯,这有点令人困惑,但可以解释。我们将一些东西分配给变量“square”。那这个呢:

06b9062dbf28e4509f010f7b456fd5b0.png

10分钟学会python函数式编程

告诉Python这是一个lambda函数,输入叫做x。冒号之后的任何内容都是您对输入所做的操作,它会自动返回结果。

简化我们的square程序到只有一行代码,我们可以这样做:

81d83f1d288a8c75fba88c0691651583.png

10分钟学会python函数式编程

所以在lambda表达式中,所有参数都在左边,你要用它们做的东西在右边。它有点乱。但事实是,编写只有其他函数式程序员才能阅读的代码会有一定的乐趣。此外,使用一个函数并将其转换为一行代码是非常酷的。

Reduce

Reduce是一个将迭代变成一个东西的函数。通常,你可以在列表上使用reduce函数执行计算以将其减少到一个数字。 Reduce看起来像这样:

3a3b8654fac910f4b28291a10d9b8839.png

10分钟学会python函数式编程

我们经常会使用lambda表达式作为函数。

列表的乘积是每个单独的数字相乘。要做到这一点你将编写如下代码:

a2608cbee8427256ef07f722178b1bd7.png

10分钟学会python函数式编程

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

c0f7cba50527d78e6d120b13f68b5845.png

10分钟学会python函数式编程

获得相同的功能,代码更短,并且在使用函数式编程的情况下更整洁。(注:reduce函数在Python3中已不是内置函数,需要从functools模块中导入)

Filter

filter函数采用可迭代的方式,并过滤掉你在该可迭代中不需要的所有内容。

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

语法如下:

8978d7079d5c680d27e5a7e08d3a6624.png

10分钟学会python函数式编程

让我们看一个小例子,没有filter我们会写:

95480877c86ba880e669f753eb528307.png

10分钟学会python函数式编程

使用filter,可以这样写:

bc988963957d0b46ec88f11eca977a72.png

10分钟学会python函数式编程

高阶函数

高阶函数可以将函数作为参数并返回函数。一个非常简单的例子如下:

d3d6aa8990fc44c9d26a78167d26cd38.png

10分钟学会python函数式编程

第二个返回函数的例子:

b316f4619d5b02d5a0bb1ac6862f488a.png

10分钟学会python函数式编程

开头我说过纯函数式编程语言没有变量。更高阶的函数使这变得更容易。

Python中的所有函数都是一等公民。一等公民被定义为具有以下一个或多个特征:

在运行时创建

在数据结构中分配变量或元素

作为函数的参数传递

作为函数的结果返回

Python中的所有函数都可以用作高阶函数。

Partial application

Partial application(也称为闭包)有点奇怪,但非常酷。您可以在不提供所需的所有参数的情况下调用函数。让我们在一个例子中看到这一点。我们想要创建一个函数,它接受2个参数,一个基数和一个指数,并返回指数幂的基数,如下所示:

05d48738301ffab34ed5788efe93403d.png

10分钟学会python函数式编程

现在我们想要一个专用的平方函数,使用幂函数计算出数字的平方:

60c0fd60048254c3813f441360b22490.png

10分钟学会python函数式编程

这有效,但如果我们想要一个立方体功能呢?或者求四次方的功能呢?我们可以继续写下它们吗?好吧,你可以。但程序员很懒的。如果你一遍又一遍地重复同样的事情,这表明有一种更快的方法来加快速度,这将使你不再重复。我们可以在这里使用闭包。让我们看一个使用闭包的square函数的示例:

5f2de6b477fbcac129a1bf9614ad304a.png

10分钟学会python函数式编程

是不是很酷!我们可以只使用1个参数来调用需要2个参数的函数。

我们还可以使用一个循环来生成一个幂函数,该函数实现从立方体一直到1000的幂。

4683984cd64af1b3218759d8ee112bea.png

10分钟学会python函数式编程

函数式编程不是pythonic

您可能已经注意到了,我们想要在函数式编程中做的很多事情都围绕着列表。除了reduce函数和闭包之外,您看到的所有函数都会生成列表。 Guido(Python之父)不喜欢Python中的函数式,因为Python已经有了自己生成列表的方法。

如果你在Python的交互环境下写入”import this“,你将会得到:

617ea6f8ff525c46a01e6057d6320d9e.png

10分钟学会python函数式编程

这是Python之禅。这是一首关于Pythonic意味着什么的诗。我们想要涉及的部分是:

There should be one — and preferably only one — obvious way to do it.(应该尽量找到一种,最好是唯一一种明显的解决方案)

在Python中,map和filter可以执行与列表推导(下面讨论)相同的操作。这打破了Python之禅的一个规则,因此函数式编程的这些部分不被视为“pythonic”。

另一个话题是Lambda。在Python中,lambda函数是一个普通函数。 Lambda是语法糖。这两种说法是等价的。

647a05a10e940af7640b0683a5fa607b.png

10分钟学会python函数式编程

普通函数可以执行lambda函数可以执行的所有操作,但它不能以相反的方式工作。 lambda函数不能完成普通函数可以执行的所有操作。

这是一个简短的论证,为什么函数式编程不能很好地适应整个Python生态系统。你可能已经注意到我之前提到了列表推导,我们现在将讨论它们。

列表推导

前面,我提到过你可以用map或filter做的任何事情,你可以用列表推导。列表推导是一种在Python中生成列表的方法。语法是:

2194cb26f711aadaab2fa0f826045f0c.png

10分钟学会python函数式编程

让我们对列表中的每个数字进行平方,例如:

3966feb81a3ac68a5bb951e0680395d3.png

10分钟学会python函数式编程

我们可以看到如何将函数应用于列表中的每一项。我们如何应用filter呢?看看前面的代码:

3ccac62cbb1565ca4559ae7086d9ab47.png

10分钟学会python函数式编程

我们可以将其转换成一个列表推导,像这样:

79bcaf49da2b085494e2a1837e890d09.png

10分钟学会python函数式编程

列表支持if这样的语句。您不再需要将一百万个函数应用于某些东西以获得您想要的东西。事实上,如果你想尝试生成某种列表,那么使用列表推导看起来会更清晰,更容易。如果我们想要将列表中每个0以下的数字平方怎么办?有了lambda,map和filter你会写:

fd8628ad42023cd7e26d093aad823b6f.png

10分钟学会python函数式编程

这似乎很长很复杂。通过列表推导,它只是:

466f5cfb924455e913027fe7b60de187.png

10分钟学会python函数式编程

列表推导仅适用于列表。map,filter适合任何可迭代的对象,那么这有什么用呢?你可以对你遇到的任何可迭代对象使用任何推导。

其他推导

你可以为任何可迭代对象创建一个推导。

可以使用推导生成任何可迭代的对象。从Python 2.7开始,您甚至可以生成字典(hashmap)。

如果它是可迭代的,则可以生成它。让我们看一下最后一组的例子。

f435b004b0c74e3ed223de9fd2a3d0c9.png

10分钟学会python函数式编程

set是一个元素列表,在该列表中没有元素重复两次。

set中的元素没有顺序。

1e8c3e7b503e1e6cbabb338769fbd400.png

10分钟学会python函数式编程

您可能会注意到set(集合)与dict(字典)具有相同的花括号。 Python非常聪明。根据你是否为dict提供值,它会知道你是在写dict推导还是set推导。

总结

函数式编程美观而纯粹。函数式代码可以很干净,但也可能很乱。一些Python程序员不喜欢Python中的函数式编程。但我认为,你应该在解决问题时,使用最佳工具。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值