学习笔记

全民一起玩Python【5】理解函数与函数式编程

1.写函数写数字本质相似,赋变量做参数样样都行

如果只写一个函数名,那么它代表一个变量,因为它与变量一样都指向一个内存地址,如果函数名后面加上括号,代表执行这个函数的代码

因此函数也可以赋值给一个变脸个,变量就相当于成为了一个函数

在调用一个类的一个不存在的方法时,也会报错“该没不存在这属性”

def my_func():
    print('hello')
    return

t=my_func
print(t)

t() #hello

filter函数可以对一个可迭代对象进行筛选,筛选后返回一个迭代器,可以通过list()转换成列表,它由两个参数组成,第一个参数是一个函数,返回True或False,第二个参数是要进行筛选的可迭代对象

#定义一个函数,用于判断数字是否为偶数,返回True或False
def f(n):
    return n%2==0

#定义一个列表
l=[2,3,5,1,9]

#使用filter函数对列表里的元素进行筛选
偶数=filter(f,l)  #返回的是一个迭代器

print(偶数)   #<filter object at 0x00000211491DAA40>

#通过list()方法将迭代器转换成列表
偶数=list(偶数)
print(偶数)   #[2]

sorted()

sorted()可以对一个可迭代对象的元素进行排序,然后返回一个排序结果,

语法是【sorted(可迭代对象,key=函数,reverse=True)】

其中key参数必须只能是一个函数,可以是系统自带的也可以是自己定义的,此外只需要填写函数名,不需要括号

reverse参数设置True表示降序,False表示升序

如果可迭代对象中的元素可以直接进行比较,比如数字、字符串等,如果是数字,进行大小的比较,如果是字符串,不是进行长度的比较,而是比较字符串的第一位、第一位相同再比较第二位,以此类推’

filter()

filter()可以用于过滤可迭代对象中的元素,通过一个返回值是True或False的函数来测试可迭代对象中的所有元素,返回的是一个迭代器,该迭代器生成那些在函数中返回True的元素

filter()的语法是【filter(函数,可迭代对象)】, 其中函数参数必须是返回值是True/False的函数

如果可迭代对象中的元素,在函数参数中的返回结果为True,那么将出现在filter()函数生成的迭代器的结果中

#通过filter()函数对数字列表进行过滤,得到该列表中的所有偶数
数字=[1,2,3,10,5,6]
偶数=filter(lambda x:x%2==0,数字)
print(偶数)   #<filter object at 0x000001D6C145A260>
print(list(偶数)) #[2, 10, 6]

#仅保留列表里长度小于5的字符串
字符串=['12212121','zfc','abc']
def f(s):
    return len(s)<5

a=filter(f,字符串)
print(list(a))  #['zfc', 'abc']

偏函数

偏函数(partial function)是函数时编程中的一个概念,在Python中,偏函数允许你固定一个函数的一部分参数,从而生成一个新的函数

使用此功能需要from functools import partial

相当于基于一个函数生成一个新函数,新函数中的某个参数已经被固定,不需要再填写

语法是【新函数=partial(旧函数,固定参数=)】

Python的functools模块提供了partial函数,可以用于创建偏函数,这样你可以创建一个新的函数,这个函数和原来函数的行为基本一致,但是一部分参数已经预设好了

好处在于,如果经常需要使用某个函数,而该函数的某个参数值时固定的,那么就可以预设参数,使调用个更加简单

from functools import partial

def power(base,exponent):
    return base**exponent
#基于power创建一个新函数,它的base参数被预设为2
square=partial(power,exponent=2)
print(square(10))   #100

#想要将一个字符串转换成二进制的整数,可以使用int函数,并且指定base参数为2
n=int('10010',base=2)
print(n)    #18

basetwo=partial(int,base=2)
n=basetwo('10010')
print(n)    #18

2.单行代码处理全部列表,一个map可抵一套循环

map()函数可以对 一个或多个可迭代对象 的所有元素 进行函数 计算,参数中的函数可以是自己定义的也可以是系统自带的,语法是【map(函数名,可迭代对象,…)】

比如对一个列表内的元素批量乘以二,得到一个新的可迭代对象,就可以先定义一个乘以二的函数,然后再使用map函数

numbers=[6,6,6]
def x2(x):
    return x * 2

result=map(x2,numbers)
print(result)   #<map object at 0x00000243E022AA10>
print(list(result)) #[12, 12, 12]

需要注意的是,map()函数返回的是一个迭代器,只有在需要读取里面的元素时,才开始计算,而这些元素“用完即抛弃”
也就是说,当对map()函数返回的可迭代对象使用一次list()转换成列表后,再次对该可迭代对象使用list()方法,会返回一个空列表,因为在上一次在转换列表时,就对列表里的元素进行过计算并且被释放了

自己写一个跟map()相同功能的函数,大致的思路的是遍历列表内的元素,进行函数计算,然后将计算的结果逐一添加至新列表中

def my_map(f,a):
    b=[]
    for i in a:
        s=f(i)
        b.append(s)
        
       return b

3.lambda表达式短小精悍,可匿名可传参灵活自如

lambda是Python中的一个关键字,可以用于创建一个匿名函数(没有函数名),可以接受任意数量的参数(包括0个,表达式可以写自定义命令),但只有一个表达式,冒号:后面的计算结果就是return的结果,语法格式是【lambda 参数:单行表达式】

比如,想要定义一个函数,功能是返回两个参数的和,一般的写法是这样的:

def add(x,y):

return x+y
用lambda的写法是这样的【add=lambda x,y:x+y】

lambda的优点是可以作为一个匿名函数在其他函数中使用,比如sorted、map等,例如,如果你想要对一个字符串列表中的元素,按照字符串长度来进行排序,可以写成:

words=['hello666','world','python','lambda233']
s=sorted(words,key=lambda x:len(x))
print(s)    #['world', 'python', 'hello666', 'lambda233']

lambda虽然定义了一个函数,但却没有函数名,可以把lambda表达式复制给变量,相当于函数名

a=[1,2,3]
from math import sin
my_sin=lambda x:round(sin(x),2)

b=map(my_sin,a)
print(list(b))  #[0.84, 0.91, 0.14]

4.reduce席卷容器,利滚利通吃全局

从Python 3开始,reduce()函数被移动到了functools模块中,因此使用该函数需要先【from functools import reduce】

reduce()的基本语法是【reduce(函数,容器,初始值】

其中,function是一个接收两个参数的函数,reduce()通过该函数来处理序列中的元素;

sequence指的是序列、列表等,reduce()会连续调用指定的函数,遍历式的对该序列中的元素一个一个进行计算,

initial为可选参数,如果提供了该参数,那么它将处理第一个序列元素之前放置在计算开始的位置

如果指定了初始值,那么第一次执行时,交给函数的参数为初始值与容器中的第一个元素,

如果不设置初始值,则第一次执行时,交给函数的参数是容器的第一个和第二个元素

计算过程是,将序列中的前两个元素,根据函数进行计算后,得到的结果作为指定函数的第一个参数,序列中的下一个参数作为函数的第二个参数,再次运算,知道序列中的元素被遍历结束位置

from functools import reduce

def my_add(x,y):
    return x+y

a=reduce(my_add,[1,2,3])
print(a)    #6

一些场景会需要设置初始值,比如计算一个列表中所有数值的平方的和

from functools import reduce

def sq_add(x,y):
    return x + y**2

#1**2+2**2+3**2应该等于14

a=reduce(sq_add,[1,2,3],0)
print(a)    #14

以上代码,结合lambda可以更为精简

from functools import reduce

#1**2+2**2+3**2应该等于14

a=reduce(lambda x,y:x+y**2,[1,2,3],0)
print(a)    #14
from functools import reduce

#抽取一个有多个字符串元素构成的列表中,每个元素的第一个字符,组成一个新的字符串
x=['关羽','张飞','赵云','马超','黄忠']
y=reduce(lambda x,y:x+y[0],x,"")
print(y)    #关张赵马黄

5.递归算法分身有术,搜遍全局路尽方出

递归会调用函数自身(其实是在内存中调用了自己的一个“拷贝”,严格说是指针和“调用栈”,即另一个函数)

def 阶乘(n):
    if n==1:
        s=1
    else:
        s=n*阶乘(n-1)
    return s

if __name__=='__main__':
    a=阶乘(3)
    print(a)

对于“层次型”问题,比如硬盘上一层层的子目录,如果需要探寻每一层的内容,但又不知道一共有多少层,那么使用递归方式最简单

isinstance()函数可以用来判断某个对象是否属于某个类型,比如isinstance(a, int)可以判断变量a是否属于int

#提取层层嵌套的子列表内的所有元素
x =[ 5 , [2,3,[ 'a', 'b'] ],[[5,8],[ 6,[9,10] ]]]
print(x)

def 透视(a):
    for i in a:
        if not isinstance(i,list):
            print(i)
        else:
            透视(i)
    return

透视(x)
#提取层层嵌套的子列表内的所有元素
x =[ 5 , [2,3,[ 'a', 'b'] ],[[5,8],[ 6,[9,10] ]]]


def 透视(a,r):
    for i in a:
        if not isinstance (i,list):
            r.append(i)
        else:
            透视(i,r)
    return r
m=透视(x,[])
print(m)    #[5, 2, 3, 'a', 'b', 5, 8, 6, 9, 10]

此处为语雀视频卡片,点击链接查看:[12.5]–第四十六回 递归算法分身有术,搜遍全局路尽方出.mp4

6.装饰器做改革精通世故,新人进旧人留和谐相处

此处为语雀视频卡片,点击链接查看:[12.6]–第四十七回 装饰器做改革精通世故,新人进旧人留和谐相处.mp4

总结

此处为语雀视频卡片,点击链接查看:[13.1]–提高篇结语:学问不可有遗力,编程功夫今始成.mp4

发表回复