首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >开源图书《Python完全自学教程》7.3.1第一类对象

开源图书《Python完全自学教程》7.3.1第一类对象

作者头像
老齐
发布2022-07-06 16:00:16
发布2022-07-06 16:00:16
3370
举报
文章被收录于专栏:老齐教室老齐教室

7.3 函数是对象

从本书一开始,就在使用“对象”这个术语,并且前面几章一直在学习 Python 内置对象。本章学习的函数,在 Python 中也是对象。也正是由于这个特点,使得 Python 中的函数有很多更优异的表现,减少了编程的苦恼——保持秀发。

图7-3-1 几种编程语言发明者

7.3.1 第一类对象

第一类对象(First-class Object)这个术语是英国的计算机科学家克里斯托弗·斯特雷奇(Christopher Strachey)于20世纪60年代提出来的,意指能够作为参数传给其他函数或者“存入”一个变量的对象(对于 Python 语言就是能够被变量引用的对象)。前面所学习过的数字、字符串等内置类型的对象,都是第一类对象。而对于函数,在 Python 语言中是第一类对象,但在其他语言中,比如 C、C++语言中就不是第一类对象。

1. 函数名称引用函数对象

下面定义一个极简函数:

代码语言:javascript
复制
>>> def foo(): pass  
...

函数 bar() 的函数体中只有 pass ,这是一个 Python 关键词,它也形成一个语句,表示在当前函数体中什么事情也不做。

代码语言:javascript
复制
>>> foo
<function foo at 0x7fe70c6424c0>

foo 是函数名称,从上述返回结果可知,这个名称就引用(代表)了函数对象,<function foo at 0x7fe70c6424c0> 说明函数作为一个对象存在于内存之中,其内存地址是 0x7fe70c6424c0 (以十六进制表示)。如果与一种内置对象对比,比如 x = 3 ,其中的 3 是对象,变量 x 引用了此对象;此处的 foo 的作用与 x 相当,它是函数的名称,引用了函数对象。

2. 函数对象用于赋值语句

代码语言:javascript
复制
>>> y = foo    # (1)
>>> y
<function foo at 0x7fe70c6424c0>

通过注释(1)的赋值语句——注意,不能写成 y = foo() ——变量 y 也引用了 foo 所引用的函数对象。下面是我们熟知的验证方法:

代码语言:javascript
复制
>>> id(foo)
140630322062528
>>> id(y)
140630322062528
>>> hex(id(foo))    # 转化为十六进制
'0x7fe70c6424c0'
>>> hex(id(y))
'0x7fe70c6424c0'

>>> type(foo)
<class 'function'>
>>> type(y)
<class 'function'>

由此我们可以进一步理解“名称引用对象”的提法,不论是变量名称还是定义函数是所用的函数名称,在注释(1)中,它们引用了同样的对象,并且该对象能够被调用(关于对象的“可调用”,参阅第9章9.5.1节)。为了更清晰地理解“对象能够被调用”的效果,写一个能够打印信息的函数。

代码语言:javascript
复制
>>> def bar():
...     print('calling a function')
...
>>> bar()
calling a function

再通过赋值语句,用另外一个变量引用上述定义的函数对象。

代码语言:javascript
复制
>>> z = bar

名称 z 与名称 bar 引用了同一个函数对象,既然前面用 bar() 执行了此函数对象,那么 z() 也应该实现同样的操作效果。

代码语言:javascript
复制
>>> z()
calling a function

果然如此。

在 Python 里有个统一的规定,只要在对象后面写上圆括号 ( ) ——有的时候圆括号中需要提供参数,就表示调用或者执行该对象。

当然,并非所有对象多能被调用,例如:

代码语言:javascript
复制
>>> 3()
<stdin>:1: SyntaxWarning: 'int' object is not callable; perhaps you missed a comma?
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable

在异常信息中就明确告知,整数类型对象不能调用——其原因请参阅第9章9.5.1节。

在本书中,通常用 bar() 这种形式表示函数,除了是跟普通变量名称区别之外,也是为了表示该对象可调用。

3. 函数对象作为参数

函数的实参,可以是任何 Python 对象,那么作为第一类对象的函数,自然也可以作为实参。

代码语言:javascript
复制
>>> def inner_func():
...     print("this is inner function.")
...
>>> def out_func(f):
...     f()
...

函数 inner_func() 很平常,函数 out_func() 则不同以往,特殊之处就是函数内的 f() ,根据7.3.1所学可知,这是表示要执行 f 引用的对象。那么,在调用 out_func() 函数的时候,必须让 f 引用一个能够像这样 f() 执行的对象,否则就会报错,比如:

代码语言:javascript
复制
>>> out_func(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in out_func
TypeError: 'int' object is not callable

哪个函数适合呢?近在眼前:

代码语言:javascript
复制
>>> inner_func()
this is inner function.

于是将此函数对象传给 out_func() ,即 inner_func 引用的函数对象做实参。

代码语言:javascript
复制
>>> out_func(inner_func)    # (2)
this is inner function.

注释(2)中,将 inner_func 作为函数 out_func() 的参数——不要写成 inner_func()

不仅可以用自己定义的函数对象,还可用任何其他对象,只要能够用 f() 样式调用即可。

代码语言:javascript
复制
>>> lst = [1, 2, 3, 4]
>>> out_func(lst.pop)    # (3)
>>> lst
[1, 2, 3]

lst.pop 也是函数对象——严格说是列表的方法,类似函数,也是对象。lst.pop() 能够删除列表最后一个成员,注释(3)就执行了此对象(没有显示返回值,是因为函数中没有将返回值用变量引用和打印),将列表的最后一个成员删除了。

还可以:

代码语言:javascript
复制
>>> out_func(list)

函数 list() 是内置函数,它的名称 list 也同样引用的是该函数对象,list() 则是执行此函数对象,并创建空列表。

上述示例说明,函数对象可以作为函数的参数。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老齐教室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 7.3 函数是对象
    • 7.3.1 第一类对象
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档