day19-高阶函数、匿名函数

map 函数

map 是一个在 Python 里非常有用的高阶函数。它接受一个函数和一个序列(迭代器)作为输入,然后对序列(迭代器)的每一个值应用这个函数,返回一个序列(迭代器),其包含应用函数后的结果。

语法
map(function, iterable, ...)
参数iterable可以是一个或多个序列

例子
1、计算平方数

def square(x):
    return x ** 2
lst = map(square, [1,2,3,4,5])
print(list(lst))
#[1, 4, 9, 16, 25]

使用 lambda 匿名函数

lst2 = map(lambda x:x**2, [1,2,3,4,5])
print(list(lst2))
#[1, 4, 9, 16, 25]

2、提供了两个列表,对相同位置的列表数据进行相加

lst3 = map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
print(list(lst3))
#[3, 7, 11, 15, 19]

3、假设用户输入的英文名字不规范,没有按照首字母大写,后续字母小写的规则,请利用map()函数,把一个list(包含若干不规范的英文名字)变成一个包含规范英文名字的list:

输入:['adam', 'LISA', 'barT']
输出:['Adam', 'Lisa', 'Bart']

name_list = ['adam', 'LISA', 'barT']

def format_name(s):
    return s.lower().capitalize()
print(list(map(format_name, name_list)))

或使用匿名函数

print(list(map(lambda x:x.capitalize(), name_list)))

filter函数

filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。

例如,要从一个list [1, 4, 6, 7, 9, 12, 17]中删除偶数,保留奇数,首先,要编写一个判断奇数的函数,然后,利用filter()过滤掉偶数:

def is_odd(x):
    return x % 2 == 1

filter(is_odd, [1, 4, 6, 7, 9, 12, 17])
结果:[1, 7, 9, 17]

利用filter(),可以完成很多有用的功能,例如,删除 None 或者空字符串:

def is_not_empyt(s):
    return s and len(s.split()) > 0
newlist = filter(is_not_empyt, ['1', 'str', '', ' '])
print(list(newlist))

['1', 'str']

关于filter()方法, python3和python2有一点不同
Python2.x 中返回的是过滤后的列表, 而 Python3 中返回到是一个 filter 类。
filter 类实现了 __iter__ 和 __next__ 方法, 可以看成是一个迭代器, 有惰性运算的特性, 相对 Python2.x 提升了性能, 可以节约内存。

a = filter(lambda x: x % 2 == 0, range(10))
print(a)

输出
<filter object at 0x0000022EC66BB128>

所以在python3中输出需要用print(list(a))

例子
请利用filter()过滤出1~100中平方根是整数的数,即结果应该是:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

filter()接收的函数必须判断出一个数的平方根是否是整数,而math.sqrt()返回结果是浮点数,所以没办法用isinstance判断数据类型是整数

方法一:
    import math
    def is_sqr(x):
        r = int(math.sqrt(x))
        return r*r==x
    print filter(is_sqr, range(1, 101))

方法二:
import math
def my_sqrt(x):
    return math.sqrt(x) % 1 == 0
lst = filter(my_sqrt, range(1,101))
print(list(lst))

reduce函数

reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。
在python2中可直接使用reduce()函数
在Python3里,reduce()函数已经被从全局名字空间里移除了,它现在被放置在functools模块里,用的话要先引入from functools import reduce

语法
reduce(function, iterable[, initializer])

参数
function -- 函数
iterable -- 可迭代对象
initializer -- 可选,初始参数

例如,编写一个f函数,接收x和y,返回x和y的和:
def f(x, y):
    return x + y

调用 reduce(f, [1, 3, 5, 7, 9])时,reduce函数将做如下计算:
先计算头两个元素:f(1, 3),结果为4;
再把结果和第3个元素计算:f(4, 5),结果为9;
再把结果和第4个元素计算:f(9, 7),结果为16;
再把结果和第5个元素计算:f(16, 9),结果为25;
由于没有更多的元素了,计算结束,返回结果25。

上述计算实际上是对 list 的所有元素求和。虽然Python内置了求和函数sum(),但是,利用reduce()求和也很简单。

reduce()还可以接收第3个可选参数,作为计算的初始值。如果把初始值设为100,计算:
reduce(f, [1, 3, 5, 7, 9], 100)
结果将变为125,因为第一轮先计算初始值和第一个元素:f(100, 1),结果为101。

例子
Python内置了求和函数sum(),但没有求积的函数,请利用recude()来求积:
输入:[2, 4, 5, 7, 12]
输出:2*4*5*7*12的结果

lst1 = [2, 4, 5, 7, 12]

from functools import reduce
def prod(x, y):
    return x*y
print(reduce(prod, lst1))

sorted函数

sorted()也是一个高阶函数,可以接收可迭代对象、比较函数和比较的元素和排序规则

语法:
sorted(iterable[, cmp[, key[, reverse]]])

参数说明:
iterable -- 可迭代对象。
cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
Python 3.X 的版本中已经没有cmp函数,使用key即可

python2中它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。

因此,如果我们要实现倒序排序,只需要编写一个reversed_cmp函数:

def reversed_cmp(x, y):
    if x > y:
        return -1
    if x < y:
        return 1
    return 0

这样,调用 sorted() 并传入 reversed_cmp 就可以实现倒序排序:

print(sorted([36, 5, 12, 9, 21], cmp = reversed_cmp))
[36, 21, 12, 9, 5]

sorted()函数可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

list = [1,3,5,-10,12,-15]
result = sorted(list,key=abs)
print(result)
[1, 3, 5, -10, 12, -15]

reverse=True反向排序

print(sorted([36, 5, 12, 9, 21], reverse=True))
[36, 21, 12, 9, 5]

sorted()也可以对字符串进行排序,字符串默认按照ASCII大小来比较:

print(sorted(['bob', 'about', 'Zoo', 'Credit']))
['Credit', 'Zoo', 'about', 'bob']

'Zoo'排在'about'之前是因为'Z'的ASCII码比'a'小。

对字符串排序时,有时候忽略大小写排序更符合习惯。利用sorted()高阶函数,实现忽略大小写排序的算法。

a = ['bob', 'about', 'Zoo', 'Credit']
print (sorted(a, key=lambda x:x.upper()))
['about', 'bob', 'Credit', 'Zoo']

a = ['bob', 'about', 'Zoo', 'Credit']
print (sorted(a, key=str.lower))
['about', 'bob', 'Credit', 'Zoo']

要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True:

print(sorteda, key=str.lower, reverse=True))
['Zoo', 'Credit', 'bob', 'about']

python2中可以利用cmp函数

L=[('b',2),('a',1),('c',3),('d',4)]
print sorted(L, cmp=lambda x,y:cmp(x[1],y[1]))   
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]

利用key

print(sorted(L, key=lambda x:x[1]))             
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]

按年龄排序

students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
print(sorted(students, key=lambda s: s[2]))            
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

按降序

print(sorted(students, key=lambda s: s[2], reverse=True))       
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

匿名函数

python使用lambda来创建匿名函数。lambda只是一个表达式,函数体比def简单很多。
lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑。
lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

语法
lambda [arg1 [,arg2,.....argn]]:expression
lambda a:b,其中a表示参数,b表示返回值。

以下代码能运行吗?
    l = [1,2,3,4,5]  
    for i in range(0,len(l)):  
        print i  
        if l[i] % 2 == 0:  
            del l[i]  
    print l  

结果:
[python] view plain copy
    Traceback (most recent call last):  
      File "D:\1.py", line 3, in <module>  
        if l[i] % 2 == 0:  
    IndexError: list index out of range  

因为随着del()语句的执行,list的元素越来越少,但是for已经定了[0,5):
i = 0,l[i] = 1不是偶数跳过
i = 1,l[i] = 2是偶数,l = [1,3,4,5]
i = 2,l[i] = 4是偶数,l=[1,3,5]
i = 3,l[i] 越界了,list index out of range。

以下代码能运行吗?
[python] view plain copy
    ll = [1,2,3,4,5]  
    for i in ll:  
        if i % 2 == 0:  
            ll.remove(i)     
    print ll  

结果:[1, 3, 5]  

这段代码就没上述的问题。list有多少就取多少。

用filter()和lambda实现上面的功能:

print(list(filter(lambda x:x%2==0,range(10))))
[0, 2, 4, 6, 8]

filter(function,list),把list中的元素一个个丢到function中,Return True的元素组成一个new list。

ll = [1,2,3,4,5]  
def func(x):  
    return x % 2 != 0  
print filter(func,ll)

总结:
1、循环list的时候,最好用for i in list:,减少因为del()犯下不易察觉的失误。
2、在python2 中直接打印map,filter函数会直接输出结果。但在python3中做了些修改,输出前需要使用list()进行显示转换。
3、lambda可以处理的最复杂的情况就是三元运算了,不能再复杂了,比如for循环之类的就不能实现了。

filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的list。

print(list(filter(fun,ll)))
print(list(filter(lambda i:i%2!=0,ll)))

关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:

>>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)    
25

也可以传入多个参数
计算n的y次方

calc = lambda n,y:n**y
print(calc(2,10))

猜你喜欢

转载自www.cnblogs.com/dxnui119/p/9956824.html