在函数(一)中看到,函数内部也有很多对象,现在再补充一个对象:__defaults__,该对象保存了参数的默认值,并以元组形式存在,如果手动修改其内容,函数的关键字参数赋值将被覆盖:
#动态管理函数参数的默认值 #函数参数默认值存于__defaults__,是元组类型对象 def paramsize(bytesize,trans='KB'): if trans=='KB': size=1024 if trans=='MB': size=1024**2 if trans=='GB': size=1024**3 if trans=='TB': size=1024**4 return str(bytesize//size)+trans print(paramsize.__defaults__) #手动修改 paramsize.__defaults__=('TB',) print(paramsize.__defaults__) paramsize(1021302345678900987654321234567)结果为: 关于以上代码,顺便可以插入一个细节,当元组只有一个元素时,必须要在元素后加逗号‘,’例如(6,),这才算一个元组
函数式编程是一种编程规范,因为调用函数本质是函数复用的过程,通过将处理过程结构化(函数化:将复用代码封装成函数)可以减少代码冗余 另外,函数在python中和列表,元组等数据结构地位一样,都是一个对象(这从一个方面反映了函数也可以作为参数传入另一个函数):
a=5 def func(): pass b=[1,2,3] c='python' print(type(a),type(func),type(b),type(c)) #<class 'int'> <class 'function'> <class 'list'> <class 'str'> #看出函数也是一个对象匿名函数指的是没有函数名的函数对象,其作用在于减少代码量,正好体现了Python的简洁优美,匿名函数用于简单函数的表达,用关键字lambda开头,在冒号‘:’前是参数,后面则是返回值,举个例子:
#将匿名函数对象赋值给lambdaf,以便进行调用 lambdaf=lambda x,y:x**2+y**2 #等价于 def func(x,y): return x**2+y**2由上看出,匿名函数确实将一个函数简写到1行,调用lambdaf(2,3)等价于调用func(2,3),此外,其类型type(lambdaf)同样是class ‘function’ 匿名函数的便捷性更多体现在下面要说的高阶函数中,因为高阶函数需要以函数作为参数,匿名函数的简洁正好很适合直接写成参数
高阶函数以函数作为参数,可以简单理解为给作为参数的函数增加了特定的功能,高阶函数很多,有必要掌握python内置高阶函数:map,reduce,filter,因为它们的应用很广泛 1.map函数:在这里,map并不是地图的意思,而是mapping,即映射;它会对可迭代对象按照位置逐一进行操作,在map的说明文档里有:
map(func, *iterables) --> map object根据第四课的学习,我们很容易就看出,iterables是可变位置参数,也就是说map每次按位置操作的对象不限个数,func参数一般就写上lambda函数,func每次接收的数据来自iterables,map所做的就是将iterables的元素逐一取出给func进行操作并保存结果,而最终完整返回的是一个map对象,所以在查看内容时注意类型转换 想象一个场景:对列表中的每个数进行三次方,列表为:li=[1,2,3,4,5,6] 在没接触map时,我会想到用for循环来做,既然有了map,我现在可以一行代码就完成这个任务:
list(map(lambda x:x**3,li))list()是为了将map对象转为列表好观察 以上代码等价于:
def cubelist(x): return x**3 list(map(cubelist,li))前面看到iterables是可变位置参数,所以map可以处理多个可迭代对象,比如对三个列表的每个元素求和得到一个新列表:
lisa,lisb,lisc=[1,2,3],[4,5,6],[7,8,9]#多重赋值 list(map(lambda x,y,z:x+y+z,lisa,lisb,lisc))2.reduce函数:reduce函数用于同一可迭代对象的两两元素之间进行操作,操作结果与下一个元素继续操作,可以看出最终这个序列(就是上面说的可迭代对象)的规模在不断缩小,因此得名reduce,中文意思是减少 在文档中有说明: reduce(function,sequence[,initial])->value 注意两个地方: 第一个,sequence[,initial]就是上面提到的序列,initial在中括号[…]里,代表可选参数,指的是对序列进行操作前,预定好一个初始值,然后在这个值的基础上进行操作(不要错误想成是从序列哪一个索引开始操作); 第二个,reduce每次操作返回的都是一个值,而不是像map一样返回一个map对象; 举个实例,对列表元素逐一求和:
#先导入reduce from functools import reduce li=[1,2,3,4,5] reduce(lambda x,y:x+y,li)结果是15,如果改成reduce(lambda x,y:x+y,li,10),结果将是10+15=25: 3.filter函数:filter函数是对可迭代对象进行过滤,返回一个新对象,因此形象地被大家叫做filter(滤波器): filter(function or None,iterable)->filter object iterable只是一个位置参数,说明filter只能对一个可迭代对象进行过滤; filter会按照function这个规则过滤可迭代对象,该规则必须返回bool值(True,False),True代表保留,False代表过滤,常常会用到三元表达式; 若function为None,相当于没有过滤,但返回的是filter对象; 假设现在遇到一个问题:筛选出列表中小于3的元素
li=[7,5,1,3,2,0,8,9] list(filter(lambda x:True if x<3 else False,li))再来一个非常简单的问题:做一个全通滤波器,即使用filter复制一个列表
li=[7,5,1,3,2,0,8,9] list(filter(None,li))扩展:sorted函数
sorted(iterable, key=None, reverse=False),默认排序是升序排列,sorted在NLP中很常用,key参数接收的是一个函数,比如现在有一组人员信息:
students=[('john','A',15),('jane','B',12),('dave','B',10)]我现在按年龄给他们排序:
sorted(students,key=lambda x:x[2]) #[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]这样看来,可以稍微总结一个规律:高阶函数总是按可迭代对象中的微观元素进行操作的,操作的规则由位置参数func对应的函数决定,不同的高阶函数就像是给func每次的操作增加了特定功能