Python 函数是第一类对象


在很多资料中,经常会看到这样一句话:“Python 中的函数是第一类对象”。这里所说的第一类对象,其实是指函数作为一个对象,与其他对象具有相同的地位。

关于这一点,Guido 曾提过“First-class Everything”,他对 Python 的一个发展目标就是所有的对象都是第一类对象。也就是说,所有对象都可以赋值给变量,放进容器中,作为参数传递,用作返回值等等。

1

函数是对象

Python 中的一切皆对象,对于函数也不例外。

以一个简单的函数为例,来说明这一点:

>>> def greet(msg):
...     print('Hello, {}!'.format(msg))
...
>>>

我们都知道,对象有三大要素 - id、type、value,那么函数有吗?

>>> id(greet)    # 唯一标识
570757645992
>>>
>>> type(greet)  # 对象的类型
<class 'function'>
>>>
>>> greet        # 对象的值
<function greet at 0x00000084E3CE86A8>

很显然,它都有!当然,除了这些通用属性之外,函数还可用于一些高级操作。

2

函数可以赋值给变量

由于函数是对象,所以和任何其他对象(例如:字符串)一样,它也可以赋值给变量:

>>> g = greet
>>> f = greet
>>> g is f
True

但这并不会调用函数,只不过是在函数对象上绑定了新的名称而已。

如果要调用函数,除了直接使用 greet 之外,还可以通过调用这些变量来执行相同的底层函数:

>>> greet('nice to meet you')
Hello, nice to meet you!
>>>
>>> f('nice to meet you')
Hello, nice to meet you!
>>>
>>> g('nice to meet you')
Hello, nice to meet you!

3

函数可以存储在容器中

常见的容器有很多(例如:列表、字典),它们可以存储任何对象,也包括函数。

例如,向列表中添加一些函数:

>>> funcs = [greet, len, str.lower]
>>> funcs
[<function greet at 0x00000084E3CE86A8>, <built-in function len>, <method 'lower' of 'str' objects>]

其中,greet 是我们自定义的函数,len 是内置函数,而 str.lower 是字符串中的方法。

要调用这些函数很容易,可以直接通过索引来访问:

>>> funcs[0]
<function greet at 0x00000084E3CE86A8>
>>>
>>> funcs[0]('nice to meet you')
Hello, nice to meet you!

也可以将其分配给变量,然后通过变量来调用:

>>> f = funcs[0]
>>> f('nice to meet you')
Hello, nice to meet you!

4

函数可以作为参数

在函数式编程中,有一个很重要的概念 - 高阶函数,就是让函数的参数能够接收别的函数。如果使用过 map()、filter() 之类的函数,应该知道这一点。

来看下面这个函数:

>>> def welcome(func, msg):
...     func(msg);
...
>>>

可以通过传递不同的函数和信息来影响问候语,尝试传递 greet 函数:

>>> welcome(greet, 'nice to meet you')
Hello, nice to meet you!

函数的这个特性非常强大,它允许我们抽象并传递程序中的行为。

5

函数可以嵌套

与条件语句和循环语句类似,Python 也允许在一个函数中定义其他函数,这些函数通常被称为嵌套函数(或内部函数)。

来看一个示例:

>>> def welcome(msg):     # 外部函数
...     def greet(text):  # 嵌套函数
...         return 'Hello, {}!'.format(text)
...     return greet(msg)
...
>>>

当每次调用 welcome 时,它都会定义一个新的嵌套函数 greet,然后调用它:

>>> r = welcome('nice to meet you')
>>> print(r)
Hello, nice to meet you!

6

函数可以作为返回值

函数不仅可以嵌套,还可以作为返回值,甚至是捕获并携带外部函数的一些状态。

对上述示例略作修改:

>>> def welcome(msg):
...     def greet():
...         return 'Hello, {}!'.format(msg)
...     return greet  # 注意这里没有圆括号
...
>>>

如果仔细观察嵌套函数 greet,你会发现它不再有任何参数了,但仍可以访问外部函数中定义的参数 msg:

>>> f = welcome('nice to meet you')
>>> f
<function welcome.<locals>.greet at 0x00000084E3CE8620>
>>>
>>> f()
'Hello, nice to meet you!'

看起来,greet 似乎记住了参数的值。这样的函数称为词法闭包(或简称:闭包),即使程序流不在该范围内,闭包也会记住其所包含的词法范围中的值。

7

对象可以表现得像函数

虽然对象不是函数,但是也可以被调用。在某些情况下,可以将它们当作函数来处理。

如果对象是可调用的,意味着可以对它使用圆括号 () 并传递参数:

>>> class Greeter:
...     def __init__(self, name):
...         self.name = name
...     def __call__(self, msg):
...         return 'Hello, {}, {}!'.format(self.name, msg)
...
>>>

在内部,将对象实例作为函数来“调用”会尝试执行 __call__ 方法:

>>> g = Greeter('Pony')
>>> g('nice to meet you')
'Hello, Pony, nice to meet you!'

并非所有的对象都可以调用,可以用内置函数 callable 来判断:

>>> callable(Greeter)
True
>>>
>>> callable(True)
False

·END·
 

高效程序员

谈天 · 说地 · 侃代码 · 开车

长按识别二维码,解锁更多精彩内容

零基础掌握 Python 入门到实战

11-08
【为什么学PythonPython 是当今非常热门的语言之一,2020年的 TIOBE 编程语言排行榜中 ,Python名列第一,并且其流行度依然处在上升势头。 在2015年的时候,在网上还经常看到学Python还是学R的讨论,那时候老齐就选择了Python,并且开始着手出版《跟老齐学Python》。时至今日,已经无需争论。Python给我们带来的,不仅仅是项目上的收益,我们更可以从它“开放、简洁”哲学观念中得到技术发展路线的启示。 借此机会,老齐联合CSDN推出了本课程,希望能影响更多的人走进Python,踏入编程的大门。 【课程设计】 本课程共包含三大模块: 一、基础知识篇 内置对象和基本的运算、语句,是Python语言的基础。本课程在讲解这部分知识的时候,不是简单地将各种知识做简单的堆砌,而是在兼顾内容的全面性的同时,更重视向学习者讲授掌握有关知识的方法,比如引导学习者如何排查错误、如何查看和理解文档等。   二、面向对象篇 “面向对象(OOP)”是目前企业开发主流的开发方式,本课程从一开始就渗透这种思想,并且在“函数”和“”的学习中强化面向对象开发方式的学习——这是本课程与一般课程的重要区别,一般的课程只在“”这里才提到“对象”,会导致学习者茫然失措,并生畏惧,乃至于放弃学习。本课程则是从开始以“润物细无声”的方式,渗透对象概念,等学习到本部分的时候,OOP对学习者而言有一种“水到渠成”的感觉。   三、工具实战篇 在项目实战中,除了前述的知识之外,还会用到很多其他工具,至于那些工具如何安装?怎么自己做工具?有那些典型工具?都是这部分的内容。具体来说,就是要在这部分介绍Python标准库的应用以及第三方包的安装,还有如何开发和发布自己的工具包。此外,很多学习Python的同学,未来要么从事数据科学、要么从事Web开发,不论哪个方向,都离不开对数据库的操作,本部分还会从实战的角度,介绍如何用Python语言操作常用数据库。
©️2020 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值