五、函数
函数在 Python中举足轻重,封装函数除了增加代码可重用,在Python中,函数的应用具有更大的灵活性,能否善用函数,可能成为判断你是否是一个真正的Python高手的重要标志。
(一)函数,首先是一个对象
首先,Python不仅仅是动态强类型的语言,它也是真正的强对象类型的语言。python中的万物皆为对象,可不是说说而已的,常量是对象,变量是对象,四大数据结构也是对象(还记不记得它们可以互相嵌套使用?),那么,函数呢?是的,函数也是对象。
示例1:创建一个函数,用于计算一个字符串的长度
>>> def func_1(strs):
return len(strs)
>>> func_1("How are you!")
12
作为一个Python对象,它通常具备对象模型的三个必要属性,即id、类型、值。我们来看看上面这个函数的id、类型、值:
>>> id(func_1)
47027880
>>> type(func_1)
<class 'function'>
>>>func_1
<function func_1 at 0x02CD96A8>
作为一个强对象类型,它通常具有如下特征:
而这些特性,Python的函数都具备。
1、函数允许赋值给一个变量
>>> func_2 = func_1
PS:请注意,函数赋值给另外一个变量时,并不会被调用,仅仅是在函数对象上绑定了一个新的名字而已。
>>> func_2("what’s this?")
12
>>>
当然,既然只是在对象上添加了一个引用,事实上,只要你的程序需要,你还可以添加更多的引用,不过是增加了更多的引用,本质上,这些变量最终都指向了同一个函数对象。
>>> func_3 = func_1
>>> if func_3 == func_2 : print(‘ok!’)
ok!
容器型对象很多,比如:列表list、字典dict、集合set等等,它们中可以存放任何对象,包括整数、字符串,同样,函数也可以存放到容器对象中。例如
示例2:函数作为一个独立的元素包含于一个列表中
>>> list1 = [func_1, len]
>>> for x in list1:
print(x("abcde"))
5
5
>>>
代码解析:
(1)列表list1的两个元素:func_1是我们自定义的函数,len 是python的内置函数。
(2)for 循环迭代,函数对象赋值给了 x 变量。
(3)调用 x(“abcde”) ,并显示。
当然,更直接的方法是,通过元素的索引获取函数对象,再调用该函数。
>>> list1[0]("abcde")
5
3、函数允许作为实参传递给另一个函数
示例3:
>>> def func_4(func):
ln = func("函数神奇妙用!")
print ("字符串的长度是 :" + ln)
>>> func_4(func_1)
字符串的长度是 : 7
函数作为另外一个函数的返回值,例如:
>>> def func_5():
return func_1
>>> my_func = func_5()
>>> my_func("my_python")
9
# 可简写为:
>>> func_5()("my_python")
9
这里,func_5实际上属于高阶函数。(什么是高阶函数?建议大家翻翻书吧!)
PS:Python内置函数中,典型的高阶函数如 map 函数。
示例:map 接受一个函数和一个迭代对象作为参数,调用 map 时,依次迭代把迭代对象的元素作为参数调用该函数。
>>> map(func_1, ["abcde","def","gh","lmnopqr"])
>>> lens = map(func_1, ["abc","def","gh","lmnop"])
>>> list(lens)
[5, 3, 2, 7]
map 函数的作用相当于:
>>> [func_1(i) for i in ["abc","def","gh","lmnop"]]
[5, 3, 2, 7]
比较而言,map 的运行效率会更快一些。
列表中包含列表,字典中包含字典,那么,函数中能不能再包含函数呢?答案是肯定的,这种包含了函数的函数,叫嵌套函数。
示例4:去除字符串的前2个字符后再计算它的长度
>>> def func_6(my_str):
def func_7(a):
# 获取去掉第一个字符的切片
return a[2:]
new_str = func_7(my_str) #调用内建函数
# 计算切片后的字符串的长度
return len(new_str)
>>> func_6("i_python")
6
PS:需要注意的是,位于嵌套函数里面的函数,相当于一个局部变量,它的作用域仅限于嵌套函数内部,不能在函数的外部访问。
示例5:创建一个可被调用的类
class get_sum:
def __init__(self, x):
self.x = x
def __call__(self, y):
return self.x + y
>>> my_sum = get_sum(1) #赋初始值
>>> my_sum(5) #调用自定义的类
>>> 6
执行 my_sum (5) 相当于调用 get_sum._call__(self, 4),self 就是实例对象 get_sum,初始值self.x 等于 1,所以,所以调用my_sum (5)的返回值为 1 + 5
PS:确定对象是否为可调用的对象,可以用内置函数callable来判断。
>>> callable(func_1)
True
>>> callable(3)
False
>>> callable(len)
True
别只把函数当函数,
它不仅仅是一个封装的代码块,
它也是一个对象,
它能像所有其他的对象一样,
被包含、被赋值、被传参、被返回,
它还能被嵌套,
还能被模仿。(而且是高仿~!)
当你把函数看得如此的透彻,
还能用得如此的溜(666~)的时候,
你不想做牛人都难!
声明:
本文摘编自博客园杨过的文章,
https://www.cnblogs.com/duex/p/6725694.html
(局部有修改)