全部版块 我的主页
论坛 数据科学与人工智能 数据分析与数据科学 数据分析与数据挖掘
891 0
2020-10-14
在10分钟内学习功能Python语法[教程]
功能范式
在命令式范例中,您可以通过向计算机分配一系列任务来执行操作,然后由计算机执行这些任务。在执行它们时,它可以更改状态。
例如,假设您设置了 A = 5,然后再更改 A。从某种意义上说,变量是变量内部的值变化的。
在功能范式中,您不告诉计算机要做什么,而是告诉它要做什么。数的最大公约数是多少,乘积是什么1 to n 是,依此类推。
变量不能改变。设置变量后,它会一直保持这种状态(请注意,在纯函数式语言中,它们不称为变量)。因此,功能在功能范式中没有副作用。副作用是函数在函数外部进行了更改。
让我们看一些典型的Python代码示例:
a = 3
def some_func():
    global a
    a = 5
some_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中的惰性。
地图
为了了解地图,让我们首先看看什么是可迭代的。可迭代是您可以迭代的任何事物。这些是列表或数组,但是Python具有许多不同的可迭代项。您甚至可以创建自己的对象,这些对象可以通过实现魔术方法进行迭代。魔术方法就像一个API,可以帮助您的对象变得更加Pythonic。
您需要实现2种魔术方法以使对象可迭代:
class Counter:  
    def __init__(self
        # 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__或dunder iter(双下划线iter)返回迭代对象,我们经常在循环开始时使用它。接下来是邓德__next__,返回下一个对象。
让我们进入快速终端会话并检查一下:
for c in Counter(3
    print(c)
这将打印:
3
4
5
6
7
8
在Python中,迭代器是仅包含一个 __iter__魔术方法。这意味着我们可以访问对象中的位置,但是不能遍历对象。一些对象将具有魔术方法__next__ 而不是 __iter__魔术方法,例如集合(在本文后面讨论)。在本文中,我们假定触摸的所有对象都是可迭代的对象。
现在我们知道什么是可迭代对象,让我们回到map函数。map函数使我们可以将函数应用于可迭代的每个项目。我们希望对列表中的每个项目都应用一个函数,但要知道大多数迭代器都有可能使用该函数。Map需要2个输入,即要应用的功能和可迭代的对象。
map(function
假设我们有一个数字列表,如下所示: [1
我们想对每个数字取平方,可以编写如下代码:
x = [1
def square(num):
    return num*num
print(list(map(square
功能性Python很懒。如果我们不包括list()该函数将存储可迭代对象的定义,而不是列表本身。我们需要告诉Python “将其转换为列表”以供我们使用。
在Python中突然从非惰性评估过渡到惰性评估是很奇怪的。如果您在功能性思维方式中比在命令式思维方式中思考更多,您将习惯它。
现在写一个普通的函数就像 square(num)但是看起来不对。我们只需要在地图中使用一次就定义一个整体功能?好了,我们可以使用lambda(匿名)函数在map中定义一个函数。
Lambda表达式
Lambda表达式是单行函数。以这个lambda表达式为例,该表达式平方一个给定的数字:
square = lambda x: x * x
现在运行此命令:
>>> square(3)
9
我听到你了 “布兰登,争论在哪里?这到底是什么?看起来不像功能吗?”
好吧,这很混乱,但是可以解释。我们正在给变量赋值square。
这部分:
lambda x:
告诉Python这是一个lambda函数,输入名为x。冒号之后的所有内容都是我们对输入所做的事情,并且返回的结果是什么。
要将平方程序简化为一行,我们可以执行以下操作:
x = [1
print(list(map(lambda num: num * num
在lambda表达式中,所有参数都在左侧,而您要使用它们的内容在右侧。它有点混乱,没有人可以否认。编写只有其他功能程序员才能阅读的代码,这是一种乐趣。另外,将一项功能转换为单行代码也很酷。
减少
Reduce是一种将可迭代变成一件事的功能。通常,我们将对列表进行计算以将其减少到一个数字。
减少看起来像这样:
reduce(function
我们可以(并且经常会)使用lambda表达式作为函数。
列表的乘积是将每个数字相乘。
要对此编程:
product = 1
x = [1
for num in x:
    product = product * num
但是使用reduce可以编写:
from functools import reduce
product = reduce((lambda x
要获得相同的产品。代码更短,并且具有函数式编程知识,因此更加整洁。
过滤
filter函数接受一个可迭代的对象,并过滤掉该可迭代对象中所有不需要的东西。
过滤器具有一个功能和一个列表。它将函数应用于列表中的每个项目,如果该函数返回True,则不执行任何操作。
如果返回False,则将其从列表中删除。
语法如下:
filter(function
让我们看一个小例子,没有过滤器,我们将编写:
x = range(-5
new_list = []
for num in x:
    if num < 0:
        new_list.append(num)
使用过滤器,它将变为:
x = range(-5
all_less_than_zero = list(filter(lambda num: num < 0
高阶函数
高阶函数可以将函数用作参数并返回函数。
一个非常简单的示例如下所示:
def summation(nums):
    return sum(nums)
def action(func
    return func(numbers)
print(action(summation
# Output is 6
或第二个定义的简单示例, return functions,是:
def rtnBrandon():
    return “brandon”
def rtnJohn():
    return “john”
def rtnPerson():
    age = int(input(“What’s your age?”))
    if age == 21:
        return rtnBrandon()
    else:
        return rtnJohn()
您之前知道我怎么说纯函数式编程语言没有变量吗?
好吧,高阶函数使此操作更容易。
如果我们要做的只是通过长函数通道传递数据,则无需在任何地方存储变量。
Python中的所有函数都是一流的对象。
我们将一流对象定义为具有以下一个或多个功能:
在运行时创建
分配给数据结构中的变量或元素
作为参数传递给函数
作为函数的结果返回
因此,Python中的所有函数都是一流的,可以用作高阶函数。
部分申请
部分应用程序(也称为闭包)很奇怪,但是很酷。我们可以在不提供所有所需参数的情况下调用函数。我们来看一个例子。
我们要创建一个函数,该函数接受2个参数(一个底数和一个指数),然后将base返回给指数的幂,如下所示:
def power(base
    return base ** exponent
现在我们想要一个专用的平方函数,使用幂函数计算一个数字的平方:
def square(base):
  return power(base
这行得通,但是如果我们想要多维数据集函数怎么办?还是4的幂的函数?我们可以永远继续写它们吗?好吧,我们可以。
但是程序员很懒。如果我们重复做同样的事情,则表明有一种更快的方法可以加快处理速度,这将使我们不再重复处理。我们可以在这里使用部分应用程序。
让我们看一下使用部分应用程序的平方函数的示例:
from functools import partial
square = partial(power
print(square(2))
# output is 4
那不是很酷!通过告诉Python第二个参数是什么,我们可以仅使用1个参数来调用需要2个参数的函数。
我们还可以使用循环来生成幂函数,该幂函数从三次方一直到1000的幂。
from functools import partial
powers = []
for x in range(2
  powers.append(partial(power
print(powers[0](3))
# output is 9
函数式编程不是Pythonic
您可能已经注意到,但是我们在函数式编程中要做的许多事情都围绕列表进行。除了reduce函数和部分应用程序之外,您看到的所有函数都会生成列表。
Guido(Python的发明者)不喜欢Python中的功能性内容,因为Python已经有了自己的生成列表的方式。
如果我们将“ import this”写入“ Python IDLE”会话中,则会得到:
>>> import this
The Zen of Python
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren’t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain
If the implementation is easy to explain
Namespaces are one honking great idea -- let’s do more of those!
这就是Python的禅宗。这是一首关于Pythonic意味着什么的诗。
我们要在这里涉及的部分是:
> There should be one?—?and preferably only one?—?obvious way to do it.
在Python中,地图和过滤器可以做与列表理解相同的事情(下面讨论)。这打破了Python Zen的一条规则,因此函数编程的这些部分是“ pythonic”。
另一个话题是Lambda。在Python中,lambda函数是常规函数。Lambda是语法糖。
两者是等效的:
foo = lambda a: 2
def foo(a):
  return 2
常规函数可以执行lambda函数可以做的所有事情,但是反之则不行。Lambda函数无法执行常规函数可以执行的所有操作。
关于为什么函数式编程不能很好地适合整个Python生态系统,这是一个简短的争论。
您可能已经注意到我之前提到过列表理解,现在我们将讨论它们。
清单理解
之前,我提到过您可以使用map或filter进行的任何操作,也可以使用列表理解的方法。这是我们将了解它们的部分。列表理解是在Python中生成列表的一种方法。
语法为:
[function for item in iterable]
因此,让我们对列表中的每个数字取平方,例如:
print([x * x for x in [1
好的,所以我们可以看到如何将函数应用于列表中的每个项目。我们如何应用过滤器?
好吧,请看一下前面的代码:
x = range(-5
all_less_than_zero = list(filter(lambda num: num < 0
print(all_less_than_zero)
我们可以这样将其转换为列表理解:
x = range(-5
all_less_than_zero = [num for num in x if num < 0]
列表推导支持if这样的语句。您不再需要将一百万个函数应用于某些对象即可获得所需的东西。实际上,如果我们要尝试某种列表机会,那么使用列表理解将使它看起来更干净,更容易。
如果我们想对列表中0以下的每个数字求平方怎么办?
好吧,使用lambda,map和filter,我们将编写:
x = range(-5
all_less_than_zero = list(map(lambda num: num * num
这是漫长而复杂的。通过列表理解,它是:
x = range(-5
all_less_than_zero = [num * num for num in x if num < 0]
列表理解仅对列表有益。映射和过滤器可在任何可迭代的条件下工作,那么这又是怎么回事?我们可以对遇到的任何可迭代对象使用任何理解。
其他理解
我们可以使用理解来生成任何可迭代的。从Python 2.7开始,我们甚至可以生成一个字典(hashmap)。
# Taken from page 70 chapter 3 of Fluent Python by Luciano Ramalho
DIAL_CODES = [     (86
    (91
    (1
    (62
    (55
    (92
    (880
    (234
    (7
    (81
    ]
>>> country_code = {country: code for code
>>> country_code
{’Brazil’: 55
>>> {code: country.upper() for country
{1: ‘UNITED STATES’
如果是可迭代的,我们可以生成它。让我们看一下集合的最后一个例子。如果您不知道集合是什么,请查看我写的另一篇文章。
TL; DR为:
集是元素的列表,该列表中没有元素重复两次
套装顺序无所谓
# taken from page 87
>>> from unicodedata import name
>>> {chr(i) for i in range(32
{’×’
您可能会注意到,集合具有与字典相同的花括号。Python很聪明。它会根据您是否为字典提供额外的价值而知道您是在编写字典理解还是集合理解。
如果您想了解有关理解的更多信息,请查看此视觉指南。
如果您想了解有关理解和生成器的更多信息,请查阅本文。
结论
函数式编程既美观又纯粹。功能代码可以很干净,但是也可能很凌乱。
一些顽固的Python程序员不喜欢Python的功能范式。
您应该使用想要使用的东西,并使用最好的工具完成工作。

关注 CDA人工智能学院 ,回复“录播”获取更多人工智能精选直播视频!


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

相关推荐
栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群