函数是一等对象的学习总结
文章目录
函数是一等对象(first-class object)
在Python中,万物皆可为对象,函数也不例外。
在Python中,函数为一等对象(first-class object),那么什么才是一等对象呢?
编程语言理论家把“一等对象”定义为满足下述条件的程序实体:
- 在运行时创建
- 能赋值给变量或数据结构中的元素
- 能作为参数传给函数
- 能作为函数的返回结果
1、把函数当作对象
Talk is cheap. Show me the code.
下面分别举例说明这四个特点
-
在运行时创建
test() def test(): print('hello')
Traceback (most recent call last):
File “E:/pyproject/fluent_python/test1.py”, line 1, in
test()
NameError: name ‘test’ is not defined对于上述这段代码,我们可以看到程序会报错。
这是因为Python是从上到下一行一行执行语句的。当我们在执行到第一行时,由于还没有执行到函数
test
定义这一部分。因此会报test没有定义
这种错误。这一现象说明函数满足“在运行时创建”这一特点
-
能赋值给变量或数据结构中的元素
⚠️注:对于定义的一个函数例如
func
,不加括号指的是函数的本身,加括号表示对函数的调用(原因后续会解释)。def func1(): print('hello') def func2(): print('world') # 赋值给变量 a = func1 #建立了a对函数func1的一个引用 a() a_list = [1, 2] # 赋值给列表中的元素 a_list[1] = func2 print(a_list)
hello
[1, <function func2 at 0x0000026F5C2A60D8>] -
能作为参数传给函数
def inner(): print('hello') def outer(func): func() # 将函数inner作为参数赋值给outer outer(inner)
hello
-
能作为函数的返回结果
def inner(): print('hello') def outer(func): return func print(outer(inner))
<function inner at 0x000001EA859461F8>
2、高阶函数
接受函数作为参数,或者把函数当做结果返回的函数是高阶函数(higher-order function)
例如,想要根据单词的长度排序,只需将len
函数传入到sorted
函数的key
参数中.
fruits = ['cherry', 'apple', 'strawberry', 'banana']
sorted_fruits = sorted(fruits, key=len)
print(sorted_fruits)
[‘apple’, ‘cherry’, ‘banana’, ‘strawberry’]
高阶函数map,filter和reduce的现代替代品
reduce
在Python3中已移除。map,filter
可以使用列表推导或者生成器表达式代替,而且可读性更强。
def factorial(n):
return 1 if n < 2 else n * factorial(n - 1)
print(list(map(factorial, range(6))))
print([factorial(n) for n in range(6)])
print(list(map(factorial, filter(lambda x: x % 2, range(6)))))
print([factorial(n) for n in range(6) if n % 2])
[1, 1, 2, 6, 24, 120]
[1, 1, 2, 6, 24, 120]
[1, 6, 120]
[1, 6, 120]
3、匿名函数
lambda关键词在Python表达式内创建匿名表函数。然而,Python 简单的句法限制了lambda 函数的定义体只能使用纯表达式。换句话说,lambda 函数的定义体中不能赋值,也不能使用while 和try 等Python 语句。
fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
sorted_fruits = sorted(fruits, key=lambda word: word[::-1])
print(sorted_fruits)
[‘banana’, ‘apple’, ‘fig’, ‘raspberry’, ‘strawberry’, ‘cherry’]
lambda 句法只是语法糖:与def 语句一样,lambda 表达式会创建函数对象。
4、可调用对象
除了用户定义的函数,调用运算符(即()),还可以应用到其他对象上。
想判断对象能否调用,可以使用内置的callable
函数。
Python 数据模型文档列出了7 种可调用对象
名称 | 说明 |
---|---|
用户定义的函数 | 使用def或lambda表达式创建 |
内置函数 | 如len 或time.strftime |
内置方法 | 如dict.get |
方法 | 在类的定义体中定义的函数 |
类 | 调用类时会运行类的__new__方法创建一个实例,然后运行__\init__方法,初始化实例,最后把实例返回给调用方。 |
类的实例 | 如果类定义了__call__,那么他的实例可以作为函数调用 |
生成器函数 | 使用yield关键词的函数或方法。调用生成器函数返回的是生成器对象 |
判断对象是否可调用callable
print([callable(obj) for obj in [abs, str, 13, list]])
函数和方法的区别
-
函数指的是用户自己定义的函数或者内置的函数
是可以以对象作为参数传入函数的
# 将字符串对象作为参数传入函数中 list('hello')
-
方法指的是用户定义的类或者内置的类中定义的方法
a_dict = {'a': 1, 'b': 2} # a_dict为一个dict类的实例 print(type(a_dict)) # output:<class 'dict'> # 方法的调用形式:实例.方法 print(a_dict.get('a'))
两者最大的使用区别就是
函数要作用在某个对象身上,形式为:function(obj)
方法需要使用到点(即.)操作,形式为:instance.method()
7、仅限关键词指定
下面函数展示了一个人能力和财富之间关系
def cal_money(name, *other, working_competence=0, **other_competence):
money = working_competence*1000000
print(f'{name} can earn ${money} in the end of the year')
例如,公司来了个小红,但是这个小红一天天不务正业,整天跟朋友一起玩,没事睡觉看电视。
今天主管说,经过精密的设计,公司开发了一块软件,通过这个软件发放年终奖
于是她想通过这个软件计算一下自己能拿多少年终奖。
他将她认识的朋友和消耗的时间都输入进去了
cal_money('xiaohong','xiaoming','xiaogang',watch_tv=100, sleep=200)
结果出来的结果让她十分伤心
xiaohong can earn $0 in the end of the year
为了测试这个功能是不是有问题,她特意找来了工作能力很强的小凤。小凤试了一下
cal_money('xiaofeng',working_competence=5)
xiaofeng can earn $5000000 in the end of the year
小红恍然大悟,原始在指定的方向努力才会有收获
这个故事告诉我们:working_competence
只能通过关键字参数指定才能对其赋值,它一定不会捕获未命名的定位参数,如你认识的人xiaoming
,也不会捕获关键字名不对应的值,如干与工作提升无关的事watch_tv
等
-
定义函数时若想指定仅限关键字参数,要把它们放到前面有* 的参数后面。
如将
working_competence
放到*other
的后面。 -
如果不想支持数量不定的定位参数,但是想支持仅限关键字参数,在签名中放一个*
例如
def new(name, *, working_competence): money = working_competence * 1000000 print(f'{name} can earn ${money} in the end of the year')
在这个函数中,要求你只能填两个值(例如:绩效考核时,我并不想知道你认识多少人),而且我不管你第一个值输入什么,你第二个值必须体现出你的工作能力
working_competence=4
new('a',working_competence=4)
a can earn $4000000 in the end of the year
参考文献
参考内容
[1] Fluent Python by Luciano Ramalho (O’Reilly).Copyright 2015 Luciano Ramalho, 978-1-491-94600-8.
上一篇: Python练习题——温度单位转换问题
下一篇: Python练习题2:温度转换 II
推荐阅读