丰富的线上&线下活动,深入探索云世界
做任务,得社区积分和周边
最真实的开发者用云体验
让每位学生受益于普惠算力
让创作激发创新
资深技术专家手把手带教
遇见技术追梦人
技术交流,直击现场
海量开发者使用工具、手册,免费下载
极速、全面、稳定、安全的开源镜像
开发手册、白皮书、案例集等实战精华
为开发者定制的Chrome浏览器插件
#-*-coding:utf-8-*-#@File:引出生成器.py#@author:Flymeawei#@email:Flymeawei@163.com#@Time:2022/8/2021:00#列表生成式lst=[iforiinrange(10)]print(lst)print(type(lst))#[0,1,2,3,4,5,6,7,8,9]#
当然,这种不断调next()实在是太繁琐了,虽然是点一次出现一次,但正确的法是使for循环,因为成器也是可迭代对象。
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。比如,著名的斐波拉契数列Fibonacci,除第一个和第二个数外,任意一个数都可由前两个数相加得到:1,1,2,3,5,8,13,21,34,...
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
代码如下
也就是说,上面的函数离generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield(b)就可以了。
yield一般用于创建生成器:工作后返回变量值给生成器。
成器不仅记住了它数据状态;成器还记住了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。
生成器的特点:
可以直接作用于for循环的数据类型有以下几种:
a=(1,)#元组b=[1,2]#列表c={}#空字典d=()#元组s=set()s1={None}#集合print(type(c))#空集合
instance()函数
defisinstance(x,A_tuple):#realsignatureunknown;restoredfrom__doc__"""Returnwhetheranobjectisaninstanceofaclassorofasubclassthereof.(返回一个对象是类的实例还是类的子类。)Atuple,asin``isinstance(x,(A,B,...))``,maybegivenasthetargettocheckagainst.Thisisequivalentto``isinstance(x,A)orisinstance(x,B)or...``etc.(一个元组,如''isinstance(x,(A,B,…))'',可以被指定为目标核对。这相当于''isinstance(x,A)或isinstance(x,B)or...``etc.)"""pass代码实现:
可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的那我们还可以通过isinstance()来判断是否是Iterator对象
注意:Iterator和Iterable,一个是迭代器,一个是可迭代对象
iter()函数.py
可以作用于next()函数的对象都是itreator迭代器类型,他们表示一个惰性计算序列;
集合数据类型list,dict,str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
匿名函数lambda:顾名思义,没有名字的函数,可以将其赋值给一个变量。
语法:lambda[list]:表达式
参数介绍:
"""[list]:表示参数列表,注意:参数与表达式之间需要冒号来区分表达式:表达式方法非常多,表达形式也非常多返回值:为表达式的结果value"""代码实现
而函数式编程——FunctionalProgramming,虽然也可以归结到面向过程的程序设计,但其思想更接近抽象的计算。
我们首先要搞明白计算机(Computer)和计算(Compute)的概念。在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。
对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Python语言。
函数式编程就是一种抽象程度很高的编程范式。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
Python对函数式编程提供了部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
例如Python内置求绝对值函数abs()
>>>abs(-5)5>>>f=abs>>>f
importbuiltinsbuiltins.abs=102.引出高阶函数上面的例子,函数可以传参数,而函数名可以做变量,那我们函数里面的参数也可以为函数名。代码中的total为高阶函数
#-*-coding:utf-8-*-#@File:引出高阶函数.py#@author:Flymeawei#@email:Flymeawei@163.com#@Time:2022/8/2110:00deffun(i):returni*2deftotal(x,y,fun):returnfun(x)+fun(y)add_sum=total(1,2,fun)print(add_sum)#6下面代码test称为高阶函数
map()函数,把一个可迭代对象中的每一个元素换成一个新的对象,最终返回一个迭代器。
Python内置map()函数:
classmap(object):"""map(func,*iterables)-->mapobjectMakeaniteratorthatcomputesthefunctionusingargumentsfromeachoftheiterables.Stopswhentheshortestiterableisexhausted."""def__getattribute__(self,*args,**kwargs):#realsignatureunknown"""Returngetattr(self,name)."""passdef__init__(self,func,*iterables):#realsignatureunknown;restoredfrom__doc__passdef__iter__(self,*args,**kwargs):#realsignatureunknown"""Implementiter(self)."""pass@staticmethod#knowncaseof__new__def__new__(*args,**kwargs):#realsignatureunknown"""Createandreturnanewobject.Seehelp(type)foraccuratesignature."""passdef__next__(self,*args,**kwargs):#realsignatureunknown"""Implementnext(self)."""passdef__reduce__(self,*args,**kwargs):#realsignatureunknown"""Returnstateinformationforpickling."""passmap()函数的返回值:
map(func,*iterables)-->mapobject参数详解:
"""func:代表传入参数为函数,这里的函数指定指向函数的函数名*iterables:代表参数指定的可迭代的返回值:返回处理好的数据map()函数:是将传入的func函数作用于可迭代的数据里的面每个元素,并将处理好的新的结果返回"""代码实现
reduce()函数,把一个可迭代对象中的每个元素做聚合处理,最终返回一个聚合之后的值.
functools函数reduce()
defreduce(function,sequence,initial=_initial_missing):"""reduce(function,sequence[,initial])->valueApplyafunctionoftwoargumentscumulativelytotheitemsofasequence,fromlefttoright,soastoreducethesequencetoasinglevalue.Forexample,reduce(lambdax,y:x+y,[1,2,3,4,5])calculates((((1+2)+3)+4)+5).Ifinitialispresent,itisplacedbeforetheitemsofthesequenceinthecalculation,andservesasadefaultwhenthesequenceisempty."""it=iter(sequence)ifinitialis_initial_missing:try:value=next(it)exceptStopIteration:raiseTypeError("reduce()ofemptysequencewithnoinitialvalue")fromNoneelse:value=initialforelementinit:value=function(value,element)returnvaluetry:from_functoolsimportreduceexceptImportError:passreduce函数的参数与返回值:
注意使用reduce函数时需要先导入,reduce函数是在functools模块里面
fromfunctoolsimportreducereduce(function,sequence[,initial])->value#参数详解"""function:一个有两个参数的函数sequence:是一个序列,是一些数据的集合,或者是一组数据,可迭代对象initial:可选,初始参数返回值:返回函数计算的结果reduce()函数,使用function函数(有两个参数)先对集合中的sequence第1、2个元素进行操作,如果存在initial参数,则将会以sequence中的第一个元素和initial作为参数,用作调用,得到的结果再与sequence中的下一个数据用function函数运算,最后得到一个结果。"""代码实现:
filter()函数把一个可迭代对象中的元素做过滤操作,如果func返回值为True则留下,否则过滤掉。
Python内置函数filter()
classfilter(object):"""filter(functionorNone,iterable)-->filterobjectReturnaniteratoryieldingthoseitemsofiterableforwhichfunction(item)istrue.IffunctionisNone,returntheitemsthataretrue."""def__getattribute__(self,*args,**kwargs):#realsignatureunknown"""Returngetattr(self,name)."""passdef__init__(self,function_or_None,iterable):#realsignatureunknown;restoredfrom__doc__passdef__iter__(self,*args,**kwargs):#realsignatureunknown"""Implementiter(self)."""pass@staticmethod#knowncaseof__new__def__new__(*args,**kwargs):#realsignatureunknown"""Createandreturnanewobject.Seehelp(type)foraccuratesignature."""passdef__next__(self,*args,**kwargs):#realsignatureunknown"""Implementnext(self)."""passdef__reduce__(self,*args,**kwargs):#realsignatureunknown"""Returnstateinformationforpickling."""pass参数列表:
filter(function,iterable)"""function:判断函数。iterable:序列,(可迭代对象)。返回值:返回列表filter函数,序列(可迭代对象)的每个元素作为参数传递给函数进行判断,然后返回True或False,最后将返回True的元素放到新列表中"""filter函数实现过滤奇数:
#-*-coding:utf-8-*-#@File:filter函数.py#@author:Flymeawei#@email:Flymeawei@163.com#@Time:2022/8/2113:06defnot_odd(num):returnnum%2==0#过滤奇数new_lst=filter(not_odd,[1,2,3,4,5,6,7,8,9,10])print(list(new_lst))这里定义了一个函数not_odd,不是奇数的函数,这个函数,只有当参数为2的整数倍时返回True。这里filter函数的两个参数第一个是过滤方法,第二个是需要过滤的列表,将列表里面的元素依次带入函数中进行运算,得到的结果如果为True时,将此结果作为新的filter对象保留,等待函数里面的列表执行完成后,返回最终的值,这里的值为列表,也就是过滤掉了False的数据或元素。
filter函数过滤操作
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
看代码:
#-*-coding:utf-8-*-#@File:返回函数的高阶函数.py#@author:Flymeawei#@email:Flymeawei@163.com#@Time:2022/8/2114:48defsum_fun(*args):defadd_fun():s=0foriinargs:s+=ireturnsreturnadd_funf=sum_fun(1,2,3,4,5,6,7,8,9)add=f()print(add)#45当我们调用sum_fun时,返回的并不是求和结果,而是求和函数add_fun,将其赋值给f,当我们在调f函数时才返回求和结果s。
用filter函数来计算素数
用Python高阶函数来实现这个算法:
defodd_num():#奇数生成器函数n=1whileTrue:n+=2yieldndefun_divisible(n):#判断是否为可整除数returnlambdax:x%n>0defprimes():#素数生成器函数yield2it=odd_num()whileTrue:n=next(it)yieldnit=filter(un_divisible(n),it)#过滤出不可以整除的数foriinprimes():#打印小于100的素数ifi<100:print(i)else:break高阶函数实现打印小于100的素数:
什么是闭包:一个函数定义中引入了函数定义以外的变量,并且该函数可以在其定义以外被执行,这个函数以及引用到外部的变量称为闭包。
闭包的三个条件,缺一不可
"""1)必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套2)内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量3)外部函数必须返回内嵌函数——必须返回那个内部函数"""闭包代码实现:
python交互环境idle
>>>defcounter(start=0):count=[start]defincr():count[0]+=1returncount[0]returnincr>>>c1=counter(5)>>>print(c1())6>>>print(c1())7>>>print(c2())51>>>print(c2())52>>>当一个函数在本地作用域找不到变量申明时会向外层函数寻找,这在函数闭包中很常见但是在本地作用域中使用的变量后,还想对此变量进行更改就会报错。看一段代码:
此时,如果我在函数内加一行nonlocalc就可解决这个问题
代码:
闭包实现y=a*x+b
#-*-coding:utf-8-*-#@File:闭包的应用.py#@author:Flymeawei#@email:Flymeawei@163.com#@Time:2022/8/2116:18#y=a*x+bdefcreate_line(a,b):defline(x):returna*x+breturnlineline1=create_line(1,1)#a:1b:1line2=create_line(4,5)#a:4b:5print(line1(5))#6print(line2(5))#25从这段代码中,函数line与变量a,b构成闭包。在创建闭包的时候,我们通过create_line的参数a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式(y=x+1和y=4x+5)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提代码可复性的作。
如果没有闭包,我们需要每次创建函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。
1.闭包优化了变量,原来需要类对象完成的作,闭包也可以完成2.由于闭包引了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存4.闭包的陷阱函数内部函数,引用外部函数参数或值,进行内部函数运算执行,并不是完全返回一个函数,也有可能是一个在外部函数的值,我们还需要知道返回的函数不会立刻执行,而是直到调用了函数才会执行。看代码:
#-*-coding:utf-8-*-#@File:闭包的陷阱.py#@author:Flymeawei#@email:Flymeawei@163.com#@Time:2022/8/2117:09deffun_a():fun_list=[]foriinrange(1,4):deffun_b():returni*ifun_list.append(fun_b)returnfun_listf1,f2,f3=fun_a()print(f1(),f2(),f3())#999这里创建了一个fun_a函数,外部函数的参数fun_list定义了一个列表,在进行遍历,循环函数fun_b,引用外部变量i计算返回结果,加入列表,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了,但是实际结果并不是我们想要的1,4,9,而是9,9,9,这是为什么呢?这是因为,返回的函数引用了变量i,但不是立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,每一个独立的函数引用的对象是相同的变量,但是返回的值时候,3个函数都返回时,此时值已经完整了运算,并存储,当调用函数,产生值不会达成想要的,返回函数不要引用任何循环变量,或者将来会发生变化的变量,但是如果一定需要呢,如何修改这个函数呢?
我们fun_b()把这里的参数i赋值给x就可以解决
#-*-coding:utf-8-*-#@File:闭包的陷阱.py#@author:Flymeawei#@email:Flymeawei@163.com#@Time:2022/8/2117:09deffun_a():fun_list=[]foriinrange(1,4):deffun_b(x=i):returnx**2fun_list.append(fun_b)returnfun_listf1,f2,f3=fun_a()print(f1(),f2(),f3())#149可以再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变,那我们就可以完成下面的代码:#-*-coding:UTF-8-*-#deffun_a():deffun_c(i):deffun_b():returni*ireturnfun_bfun_list=[]foriinrange(1,4):#f(i)立刻被执行,因此i的当前值被传入f()fun_list.append(fun_c(i))returnfun_listf1,f2,f3=fun_a()print(f1(),f2(),f3())#149七、装饰器1.什么是装饰器先看一段代码:
#-*-coding:utf-8-*-#@File:什么是装饰器.py#@author:Flymeawei#@email:Flymeawei@163.com#@Time:2022/8/2119:38deffun():print('洗脸')fun()#调用fun函数#洗脸#想给fun函数增加起床和吃早点这两个功能deftest1(func):deftest2():print('起床')func()print('吃早点')returntest2test1(fun)()#起床#洗脸#吃早点由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。也可以将函数赋值变量,做参传入另一个函数。装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。
装饰器的作用:为已经存在的对象添加额外的功能
看代码代码:
#-*-coding:utf-8-*-#@File:装饰器.py#@author:Flymeawei#@email:Flymeawei@163.com#@Time:2022/8/2119:46deftest1(func):deftest2():print('起床')func()print('吃早点')returntest2@test1#装饰器deffun():print('洗脸')fun()#起床#洗脸#吃早点我们没有直接将fun函数作为参数传入test1中,只是将test1函数以@方式装饰在fun函数上。也就是说,被装饰的函数,函数名作为参数,传入到装饰器函数上,不影响fun函数的功能,再此基础上可以根据业务或者功能增加条件或者信息。
(注意:@在装饰器这里是作为Python语法里面的语法糖写法,用来做修饰。)
print(fun.__name__)#test2这并不是我们想要的!输出应该是fun,这里的函数被test2替代了。它重写了我们函数的名字和注释文档,那怎么阻止变化呢,Python提供functools模块里面的wraps函数解决了问题。代码实现:
为work()函数增加记录日志功能
把日志写入文件
>>>int('123')123但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做进制的转换。>>>int('12345',base=8)5349>>>int('12345',16)74565如果要转换大量的二进制字符串,每次都传入int(x,base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:代码:
#定一个转换义函数defint_bin(num,base=2):returnint(num,base=2)print(int_bin('1001'))#9把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单,继续优化,functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int_bin()函数,可以直接使用下面的代码创建一个新的函数。#-*-coding:utf-8-*-#@File:偏函数partial.py#@author:Flymeawei#@email:Flymeawei@163.com#@Time:2022/8/2122:18fromfunctoolsimportpartialint2=partial(int,base=2)print(int2('1001'))#9理清了functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值实际上固定了int()函数的关键字参数base。
它经常用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。