付费下载
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
有助于保持一致性,因为你只需改变单个的拷贝而无须去寻找再修改大量代码的拷贝。后将着重介绍python函数的其他特性.declaration/definitiondeffoo():print'bar'functionobject/referencefoofunctioncall/invocationvs没有返回值的函数。从后面内容你会看到,pythonNone11.1.2.返回值与函数类函数会向调用者返回一个值,而实际编大偏函数更接近过程,不显示地返回任何东西。把c“void"python>>>def...printo>>>res=o>>>>>><typedefreturn -defreturn'abc',[42,'python'],让人真的以为可以返回多个对象。如果我们要恰当地给这个元组加上括号,bar()的定义看起来会defreturn('abc',[4-2j,'python'],从返回值的角度来考虑,可以通过很多方式来元组。接下来的3种保存返回值的方式是等的>>>aTuple=>>>x,y,z=>>>(a,b,c)=>>>('abc',[(4-2j),'python'],>>>x,y,('abc',[(4-2j),'python'],>>>(a,b,('abc',[(4-2j),'python'],x,y,za,b,c用单一变量对其进行。(参见6.18.3)NonepythonNone.那么调用者们起来并以一个元组返回。是的,尽管我们声称python比诸如c那样只允许一个返回值的语言灵活的多,但是老实说,python11.1pythonpython态地确定类型而且函数能返回不同类型的值,所以没有进行直接的类型关联。因为重载并不是语言特性,程序员需要使用type()这个内建函数作为,来处理有着不同参数类型的函数的多重以模拟类C语言的函数重载(以参数不同选择函数的多个原型)。调用函函数操作同大多数语言相同,我们用一对圆括号调用函数。实际上,有些人认为(())是一个双字符操作符。正如你可能的,任何输入的参数都必须放置在括号中。作为函数的一部分,括号也关键字参举个简单的例子,比一个函数foo(),伪代码如下deffoo_suite#presumablydoessomeprocessingwith标准调用foo():foo(42)foo('bar')defnet_conn(host,net_conn('kappa',host参数得到字符串'kappa',port参数得到整数8080.当然也可以不按照函数中的参数顺序net_conn(port=8080,当参数允许"缺失“的时候,也可以使用关键字参数.这取决于函数的默认参数,在下一默认参默认参数就是了默认值的参数。因为给参数赋予了默认值,所以,在函数调用时,不向该参数传入值也是允许的。在11.5.2章对默认参数进行更全面的介绍。参数参数)或字典(关键字参数)作为参数组传递给函数 在本章中讨论这两种形式。基func(*tuple_grp_nonkw_args,tuple_grp_nonkw_args是以元组形式体现的非关键字参数组,dict_grp_kw_args是装有关键字参数的字典。正如我们已经提到的,在这章对这两者进行全面介绍,现在你只需知道,存在这样的特性允许你把变量放在元组和/或者字典里,并在没有显式地对参数进行逐个的情况下,func(positional_args,*tuple_grp_nonkw_args,apply()内建函数。(PriortoPython1.6,suchargument例表发送给合的适算术函数.(我们也会在原来版本中哪些地方会用到apply())参数,因为这些是二元运算符/运算。接着选择任意的数字作为算子。因为我们没打算在这个程序的基础版本中支持负数,所以两个数字的列表按从大到小的顺序排序,然后用这个参数列表11.131#!/usr/bin/env23fromoperatorimportadd,6ops={'+':add,'-':7MAXTRIES=8defop=choice('+-nums=[randint(1,10)foriinans=pr='%d%s%d='%(nums[0],op,oops=whileifint(raw_input(pr))==printifoops==print'answer\n%s%d'%(pr,print'incorrect...tryoops+=except(KeyboardInterrupt,EOFError,print'invalidinput...tryagain'defwhileopt=raw_input('Again?ifoptandopt[0]==except(KeyboardInterrupt, =='mainLines1–Lines在这个应用程序中我们用的全局变量有:一个包含了运算符和与其相关联的函数的集合(字典),一个决定在给出正解之前,用户有多少次机会尝试给出答案的整型变量。函数字典的键值是运算符的符号,程序通过查字典找到合适的算术函数。Linesdoprob()函数是应用程序的引擎。该函数随机选择一个操作并生成两个操作数,同时为了第十行用了random.choice()函数。它用于获取一个序 我们案例中运算符号的字符串-以仅仅用两次randint()来获得我们的操作数,比如,nums[randint(1,10),randint(1,10)是为了让你能看看列表解析的又一个例子,我们没有这样做,而且使用列表解析更易于扩展和升级, 位。如果你使用的是更早一点的python版本,你要么:增加一个反序的比较函数来获得倒转的排序,如:lambdax,y:cmp(y,x),认为它是一个单行的函数。这样写apply(ops[op],nums),而不是ops[op](*nums)输入或者允许尝试的次数(3)被耗尽才终止运行。这允许程序接受不合法Lines程序的主是main(),如果直接运行,程序将自顶向下的运行。如果被作为模块导入,导入者要么调用doprob()函数来开始执行,要么调用main()来进入程序控制。main()简单地调用doprob()使用户与的主要功能进行交互,并负责提示用户退出或者尝试下一个问题。$7-2=5correctAgain?7*6=42correctAgain?7*3=incorrect...try7*3=incorrect...try7*3=sorry...theanswer7*3=7*3=21correctAgain?7-5=2correctAgain?[y]创建函11.3.1.defdef"functionation_string"标题行由def关键字,函数的名字,以及参数的集合(如果有的话)组成。def子句的剩余部分包def'returnsasalutorystringcustomizedwiththeinput'returno"+str(who)11.3.2.与定义比11.3.3前向def>>>inTraceback(innermostlast):File"<stdin>",line1,in?File"<stdin>",line3,infooNameError:defprint'indef>>>foo()infoo()indefdefprint'in>>>infoo()in11.3.4.函数属pyhonfoobarx个模块中使用了相同的变量名字,这也是安全的,因为句点属性标识对于两个模块意味了不同名空间,比如说,在这段代码中没有名字:importfoo,bar在本章的稍后部分以及第12python的模块中进行讨论)def'foo()--properlycreateddocbar.doc='Oops,forgotthedocstrabove'bar.version=0.1上面的foo()中,我们以常规地方式创建了我们的文档字串,比如,在函数后第一个没有help()显示会比用doc属性更漂亮,但是你可以选择你喜欢的方式)>>>Helponfunctionfooin mainfoo()--properlycreateddoc>>>print>>>printfoo.foo()--properlycreateddoc>>>printbar.Oops,forgotthedocstr注意我们是如何在函数外定义一个文档字串。然而我们仍然可以就像平常一样,在运行时刻它。然而你不能在函数的中属性。换句话说,在函数中没有'self‘这样的东西dict['version']内部/内嵌函defdefprint'bar()print'foo()called'foo()calledbar()NameError:name'bar'isnot内部函数一个有趣的方面在于整个函数体都在外部函数的作用域(即是你可以一个对象的讲述。如果内部函数的定义包含了在外部函数里定义的对象的(这个对象甚至可以是在外部函11.3.6*函数(与方法)装仅是当一个函数或者方法的时候,才会应用的额外调用。def:类方法在2.2python中的时候,实现方法很笨拙:defstaticFoo()::staticFoo=:(要澄清的是对于那个版本,这不是最终的语法)在这个类的中,我们定义了叫staticFoo()的方法。现在因为打算让它成为静态方法,我们省去它的self参数,而你会在12章中看到,self参数在标准的类方法中是必需的。接着用staticmethod()内建函数来将这个函数“转化“为静态方法,但是在defstaticFoo()staticFoostaticmethod(sta-ticFoo)显得有classdefstaticFoo()::deffunc(arg1,arg2,...):deffunc(arg1,arg2,...):passfunc=deco2(deco1(func))(g·f)(x)g(f(x))pythondef: 有参数和无参数的装deffoo(): foo= deffoo():pass.. 函数对象,而该函数对象正是以foo作为其参数的装饰器。简单的说来:foo deffunc():Thisisequivalentto:func=的,该中装饰器不带任何参数。例子11.8就是含有无参装饰器的中间。那么什么是装饰11.2修饰符举例子通过显示函数执行的时间"装饰"了一个(没有用的)1611.21#!/usr/bin/env23fromtimeimportctime,4defdefprint'[%s]%s()called'%ctime(),returnreturndef19foriin2021[SunMar1922:50:282006]foo()[SunMar1922:50:332006]foo()[SunMar1922:50:342006]foo()5-10tsfunc()函数是一个显示何时调用函数的时戳的装饰器。它定义了一个内部的函数wrappedFunc(),该函数增加了时戳以及调用了目标函数。装饰器的返回值是一个Lines我们用空函数体(什么都不做)来定义了foo()函数并用tsfunc()来装饰。为证明我们的设想,立5(4+11pythonlangugaereference,python2.4What’sNewinPython2.4”的文档PEP318中来阅读关于装饰器的内容。传递函当学门如C的语言时,函数指针的概念是一个高级话题,但是对于函数就像其他对象的python来说就不是那么回事了.函数是可以被的(或者以其他变量作为其别名,也作为参见14章)在以上的描述中,我们注意到可以用其他的变量来做作为函数的别名对象的赋值给这个变量。如果对象是函数的话,这个对象所有的别名都是可调用的。>>>def...print'in>>>bar=infoo()方式来调用bar()。确定你明白"foo"(函数对象的)和"foo()"(函数对象的调用)的区别。>>>o()foobar()中。bar(fooargfunc来作为其别名就如同面的例子中我们把foo赋给bar一样。现在我们来研究下一个更加实际的例子,numconv.py,代码在例子11.3中给出一个将函数作为参数传递,并在函数体内调用这些函数,更加实际的例子。这个用传入的转换函数简单将一个序列的数转化为相同的类型。特别地,test()函数传入一个内建函数int(),long(),或者float()来执行转换。1#!/usr/bin/envpython3defconvert(func,4'conv.sequenceofnumberstosame5return[func(eachNum)foreachNuminseq]7myseq=(123,45.67,- 8printconvert(int,9printconvert(long, printconvert(float,$[123,[123L,,][123.0,形式参位置参外,没有任何默认参数(见下一个部分)的话,传入函数(调用)的参数的精确的数目必须和>>>deffoo(who):#definedforonly1...printo',>>>foo()#0arguments...BADTraceback(innermostlast):File"<stdin>",line1,in?TypeError:notenougharguments;expected1,got>>>foo('World!')#1argument...WORKSo>>>foo('Mr.','World!')#2arguments...BADTraceback(innermostlast):File"<stdin>",line1,in?TypeError:toomanyarguments;expected1,gotTypeError。看看,python无论何时调用函数,都必须提供函数的所有位置参数。可以不按位将关键字参数传入函数,给出关键字来匹配其在参数列表中的合适的位置是被准予的(可以回顾11.2.2)11.5.2.默认参数的标题行中给出。c++也支持默认参数,和python有同样的语法:参数名等号默认值。这个deffunc(posargs,defarg1=dval1,"functionation_string"为什么用默认参APIapi>>>defreturn+(cost*>>>taxMe(100)>>>taxMe(100,在上面个例子中,)函数以一个项目的成本输入参数,计算出附加了销售税的。成本是一个必需的参数,但税率是一个默认参数(在我们的例子中为8.25%。或许你是一个零售商,生意上的大部分客户来自相同的州或者国家。不同地方税率的顾客期望看见他们与当地销售税率相对应的价格总量。为了覆盖默认的税率,你所要做的就是提供一个参数值,比如在上面taxMe(100,0.05)5%税率,你提供了一个参数作为税率参数,所以覆盖或者0.0825>>>deftaxMe2(rate=0.0825,...returncost*(1.0+SyntaxError:non-defaultargumentfollowsdefault让我们再看下关键字参数,用我们的defnet_conn(host,net_conn('kappa',net_conn(port=8080,然而,如果默认参数引入这个等式,情况就会不同,虽然上面的调用仍然有效。让我们修改下net_conn()的以使端口参数有默认值80,再增加另外的名为stype(服务器的类型)默认defnet_conn(host,port=80,net_conn('phaze',8000, #nodefargsnet_conn('kappa')#bothdefargsnet_conn('chino',stype='icmp')#useportdefnet_conn(stype='udp',host='solo')#useportdefnet_conn('deli',8080)#usestypedefnet_conn(port=81,host='chino')#usestypedefnet_conn()的调用中。关键字参数已经被证明能给不按顺序的位置参数提供参数,结合默认参数,它们同样也能被用于跳过缺失参数,上面例子就是极好的。默认函数对象参数我们现在将给出另外一个证明默认参数会让人受益的例子。grabWeb.py,在例子11.4中给出,是一个主要目的是从互联网上抓取一个Web页面并暂时到一个本地文件中用于分析的简单web(通过测量可性或者速度。process()例子抓取网页这段了一个web页面(默认为本地的www服务器)并显示了html文件的第一个以及最后download()函数的双默认参数允许用不同的urls或者指定不同的处理函数来进行1#!/usr/bin/env23fromurllibimporturlretrievedefforeachLineinifnotreturndeffirstLast(f=open(lines=printprintdefdownload(url=retval=exceptretval=ifretval:#dosome =='main$<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML3.2可变长度的参在函数中不是显式命名的,因为参数的数目在运行时之前是未知的(甚至在运行的期间,每次函数中命名的。由于函数调用提供了关键字以及非关键字两种参数类型,python用两种方法来11.2.4*和**符号来指定元组和字典的元素作为非关键字以及关键字参数的方法。在这个部分中,再次使用相同的符号,但是这次在函数的非关键字可变长参数(元组当函数被调用的时候,所有的形参(必须的和默认的)都将值赋给了在函数中相对应的局悉(va_list,va_arg,以及省略号[])。Pythondeffunction_name([formal_args,] deftupleVarArgs(arg1,arg2='defaultB','displayregularargsandnon-keywordvariableprint'formalarg1:',arg1print'formalarg2:',arg1foreachXtrArgintheRest:print'anotherarg:',eachXtrArg>>>tupleVarArgs('abc')formalarg1:abcformalarg2:defaultB>>>tupleVarArgs(23,formalarg1:formalarg2:>>>tupleVarArgs('abc',123,'xyz',456.789)formalarg1:abcformalarg2:123anotherarg:xyzanotherarg:456.789关键字变量参数deffunction_name([formal_args,][*vargst,] ation_string为了区分关键字参数和非关键字非正式参数,使用了双星号(**。**是被重载了的以便不与幂运算发生。关键字变量参数应该为函数定义的最后一个参数,带**。我们现在展示一个如何defdictVarArgs(arg1,arg2='defaultB','display2regularargsandkeywordvariableprint'formalarg1:',arg1print'formalarg2:',foreachXtrArginprint'Xtraarg%s:%s'%\(eachXtrArg,str(theRest[eachXtrArg]))>>>dictVarArgs(1220,740.0,c='grail')formalarg1:1220formalarg2:740.0Xtraargc:grail>>>dictVarArgs(arg2='tales',c=123,d='poe',arg1='mystery')formalarg1:mysteryformalarg2:talesXtraargc:123Xtraargd:poe>>>dictVarArgs('one',d=10,e='zoo',men=('freud','gaudi'))formalarg1:oneformalarg2:Xtraargmen:('freud','gaudi')Xtraargd:10Xtraarge:defnewfoo(arg1,arg2,*nkw,displayregularargsandallvariableprint'arg1is:',arg1print'arg2is:',arg2foreachNKWinnkw:print'additionalnon-keywordarg:',eachNKWforeachKWinprint"additionalkeywordarg'%s':%s"%\(eachKW,kw[eachKW])>>>newfoo('wolf',3,'projects',freud=90,arg1is:wolfarg2is:additionalnon-keywordarg:projectsadditionalkeywordarg'freud':90additionalkeywordarg'gamble':11.6.3调用带有可变长参数对象11.2.4*和**来指定参数集合。接下来带着对函数接受变长参数的些许偏见,我们会向你展示那种语法的例子,我们现在将用面部分定义的,我们的newfoo(),来测试新的调用语法。我们第一个newfoo()的调用将会使用旧风格的方式来分别列出所有的参数,甚至跟在所有形式参数之后的变>>>newfoo(10,20,30,40,foo=50,arg1is:arg2is:additionalnon-keywordarg:30additionalnon-keywordarg:40additionalkeywordarg'foo':50additionalkeywordarg'bar':>>>newfoo(2,4,*(6,8),**{'foo':10,'bar':arg1is:arg2is:additionalnon-keywordarg:6additionalnon-keywordarg:8additionalkeywordarg'foo':10additionalkeywordarg'bar':>>>aTuple=(6,7,>>>aDict={'z':argPAGEargPAGE2is:additionalnon-keywordarg:3additionalnon-keywordarg:6additionalnon-keywordarg:7additionalnon-keywordarg:8additionalkeywordarg'z':9additionalkeywordarg'x':4additionalkeywordarg'y':5函数式编全测试或通过,或需要给对潜在改善进行多次迭代计时的函数来工作。你所要做的就是创建一个设置测试环境的诊断函数,然后对有疑问的地方,调用函数。因为系统应该是灵活的,所以想testee,timeit()testit(),可能会对如今的软件开发者我们现在将展示这样的一个testit(函数的例子的源代(见例子11.5)留下该模块给函数提供了一个执试的环境。testit()函数使用了一个函数和一些参数,然后在异常处理的下,用给定的参数调用了那个函数。如果函数成功的完成,会返回True和函数的返回值给调用者。任何都会导致False和异常的原因一同被返回。(Exception是所有运行时刻异常的根类:复习第10章以获得更详细的资料Example11.5TestingFunctions1#!/usr/bin/envpython3deftestit(func,*nkwargs,**kwargs):56retval=func(*nkwargs,7result=(True,8exceptException,9result=(False, returndeffuncs=(int,long,vals=(1234,12.34,'1234',foreachFuncinprint'-'*foreachValinretval=ifprint'%s(%s)='%(eachF,`eachVal`),print'%s(%s)=FAILED:'%(eachF,`eachVal`),retval[1] =='main这样的功能性,在测试中有两个失败的案例。这里是运行的输出:$int(1234)=1234=12int('1234')=int('12.34')=FAILED:invalidliteralforint():long(1234)=1234Llong(12.34)=12Llong('1234')=1234Llong('12.34')=FAILED:invalidliteralforlong():float(1234)=float(12.34)=float('1234')=float('12.34')=函数式编的以4种内建函数和lambda表达式的形式出现11.7.1.函数与lambda“语句”代表了一个表达式,这个表达式的定义体必须和放在同一行。我们现在来演示下函数的语法:lambda[arg1[,arg2,...argN]]:笔记:lambda表达式返回可调用的函用合适的表达式调用一个lambda生成一个可以像其他函数一样使用的函数对象。它们可被传入给其他函数,用额外的别名化,作为容器对象以及作为可调用的对象被调用(如果需要的话,可以带参数结果。它们和那些返回等价表达式计算值相同的函数是不能区分的。defreturn如果那样的话,我们重写下我们的true()函数以使其看其来像如下的东西:deftrue():returnlambda命名的true()函数的用法相当的明显,但lambda就不是这样。我们仅仅是这样用,或者我们需要在某些地方用它进行赋值吗?一个lambda函数自己就是无目地服务,正如在这里看到的:>>>lambda<function<lambda>atlambda(对象来,计数又回到零,然后被回收掉。为了保留住这个对象,它保存到一个变量中,以后>>>true=lambda>>>true()下个部分中,展示如何去使用带函数式编程构建的lambda表达式。defadd(x,y):returnx+y?lambdax,y:x+defusuallyAdd2(x,y=2):returnx+y?lambdax,y=2:x+ydefshowAllAsTuple(*z):returnz?lambda*z:z>>>a=lambdax,y=2:x+>>>b=lambda*z:>>>b(23,(23,关于lambda最后补充一点:虽然看起来lambdda是一个函数的单行版本,但是它不等同于c++的内联语句,这种语句的目的是由于性能的原因,在调用时绕过函数的栈分配。lambda内建函数apply()、filter()、map()、在这个部分中,看看apply(),filter(),map(),以及reduce()内建函数并给出一些如python象,lambda表达式提供了迅速创造这些函数的机制。11.2内建函 描apply(func[,nkw][,kw]) 用可选的参数来调用func,nkw为非关键字参数 filter(func,seq)b 使func返回值为ture的元素的序列。一个含有每个序列中元素集合的n个元组的列表。reduce(func,seq[,init])seq(果初始值init给定,第一个比较会是init和第一个序列元素而不正如前面提到的,函数调用的语法,现在允许变量参数的元组以及关键字可变参数的字典,在这里提及这个函数既是为了介绍下历史,也是出于具有applay()函数的代码的目的。filter()。想像下,去一个果园,走的时候带着一包你filter()函数的主要前提。给定一个对象的序列和一个“过滤”函数,每个序列元素都filter(true)值元素添加到一个列表中。返回的对象是一个从原deffilter(bool_func,filtered_seq=[]ifreturnfiltered_seqFigure Howthefilter()built-infunction在图11-1中,我们观察到我们原始队列在顶端,一个大小为n的队列,元素从eq[0],你的函数确实返回一个真或假。如果bool_func()给每个序列的元返回一个真,那个元素将会入到返回的序列中。当迭代整个序列已经完成,filter()返回一个新创建的序列。我们下面展示在fromfromrandomimportdefreturnn%allNums=foreachNuminallNums.append(randint(1,99))printfilter(odd,allNums)代码包括两个函数:odd()(真)(假)Booleanmainmain()的目的是来产生10个在1到100filter()$pythonoddnogen.py[9,33,55,65]$pythonoddnogen.py[39,77,39,71,$pythonoddnogen.py[23,39,9,1,63,$pythonoddnogen.py[41,85,93,53,第一次重foreachNuminrange(9):allNums.append(randint(1,99))printfilter(lambdan:n%2,RefactoringPassallNums=foreachNuminallNums.append(randint(1,99))print[nforninallNumsifn%2]RefactoringPass(为了简单,我们用一个较短的名字将randint()倒入到我们的代码中)fromrandomimportrandintasprint[nfornin[ri(1,99)foriinrange(9)]if在最简单的形式中,map()带一个函数和队列,将函数作用在序列的每个元素上,然后创建map(都加了2.pythonmap()如何运作的,11-2中阐释的如defmap(func,seq):mapped_seq=[]foreachIteminseq:returnmapped_seqFigure Howthemap()built-infunction>>>map((lambdax:x+2),[0,1,2,3,4,[2,3,4,5,6,>>>map(lambdax:x**2,range(6))[0,1,4,9,16,25]>>>[x+2forxinrange(6)][2,3,4,5,6,7][0,1,4,9,16,25]map()map()map()会并行地迭代每个序列。在第一次调用时,map()会将每个序列的第一个元素到一个元组中,将func函数作用到map()map()mapped_seqmap(这里有些使用带多个序列的map()的例子>>>map(lambdax,y:x+y,[1,3,5],[2,4,6])[3,7,11]>>>map(lambdax,y:(x+y,x-y),[1,3,5],[(3,-1),(7,-1),(11,->>>map(None,[1,3,5],[(1,2),(3,4),(5,想在一个新的内建函数,zip,被加进来之前的python2.0是很普遍的。而zip是这样做的:>>>zip([1,3,5],[(1,2),(3,4),(5,reduce(,reducereduce(func,[1,2, =func(func(1,2),这就是可选初始化器出现的地方(initifinitisNone:#initializer?res=lseq.pop(0)#nores=init#foriteminlseq:#reducereturnres #returnresult4图表(见图11-4。reduce()的“oworld”是其一个简单加法函数的应用或在这章前面看到的与之等价的lamdadefmySum(x,y):returnlambdax,y:>>>defmySum(x,y):return>>>allNums=range(5)#[0,1,2,3,>>>total=11-4reduce()>>>foreachNumin total=mySum(total,>>>print'thetotalis:',totalthetotalis:>>>print'thetotalis:',reduce((lambdax,y:x+y),range(5))thetotalis:10((((0+1)+2)+3)+4) 用list的头两个元素(0,1,调用mySum()来得到1,然后用现在的结果和下一个元素2来再次调用mySum(),再从这次调用中获得结果,与下面的元素3配对然后调用mySum(),最终拿整个前4mySum()10,10即为最终的返回值。偏函数应currying的概念将函数式编程的概念和默认参数以及可变参数结合在一起。一个带n个参数,curried的函数第一个参数为固定参数并返回另一个带n-1个参数函数对象分别类似于LISP的(PFA,PFApython2.5functools模块能很好的给用户调用。简add()mul(),operator模块。这两个函数仅仅是我们熟悉的+和*操作符的函数式接口,举例来说,add(x,y)与x+y一样。在我们的程序中,我们经常想要给和数字加一或者乘以100add(1,foo),add(1,bar),mul(100,foo),mul(100,bar)般的调用,拥有已存在的并使函数调用简化的函数不是一件很美妙的事吗?举例来说,add1(foo),add1(bar),mul100,但是却不用去实现函数add1()和mul100()?哦,现在用PFAs你就可以这样做。你可以通过使用functional模块中的partial()函数来创建PFA:>>>fromoperatorimportadd,>>>fromfunctoolsimport>>>add1=partial(add, #add1(x)==add(1,>>>mul100=partial(mul,100)#mul100(x)==mul(100,>>>mul100(10)>>>mul100(500)的参数,要么作为curried参数,要么作为那些 >>>baseTwo=partial(int,>>>baseTwo. ='Convertbase2stringtoan>>>baseTwo('10010')11.3.4部分base警basebaseTwoBADpartial(int,2),这可能会让参数以错误的顺序传入int(),因为固定参数的总是放在运行时刻参数的左边,比如baseTwoBAD(x)int(2,x)2,base'10010'>>>baseTwoBAD=partial(int,>>>Traceback(mostrecentcalllast):File"<stdin>",line1,inTypeError:anintegeris形参之后,所以baseTwo(x)==int(x,base=2).简单GUI类的例子PFAsPFAs活动,等等。如果想要固定其中的一些参数,如让所有的文本为蓝底白字,你可以准确地以PFAs的方式,自定义为相似对象的伪模板。11.6GUI1#!/usr/bin/env23fromfunctoolsimport4import5root=MyButton=partial(Tkinter.Button,fg='white',b1=MyButton(text='Buttonb2=MyButton(text='Buttonqb=MyButton(text='QUIT',qb.pack(fill=Tkinter.X,b1=Tkinter.Button(root,fg='white',bg='blue',text='Button1')b2=Tkinter.Button(root,fg='white',bg='blue',text='Button2')qb=Tkinter.Button(root,fg='white',text='QUIT',bg='red',Reference“What’s变量作用标识符的作用域是定义为其在程序里的可应用范围,或者即是我们所说的变量可见性。换句话说,就好像在问你自己,你可以在程序里的哪些部分去一个制定的标识符。变量可以是局全局变量与局部定义在函数内的变量有局部作用域,在一个模块中别的变量有全局作用域。在编译器理论里有名的“龙“书中,Aho,Sethi,ULLman以这种方法进行了总结。全局变量的一个特征是除非被删除掉,否则它们的存活到运行结束,且对于所有的函数,他们的值都是可以被的,然而局部变量,就像它们存放的栈,暂时地存在,仅仅只依赖于定义它们的函数现阶段是否处于活动。当一个函数调用出现时,其局部变量就进入它们的作用域。deffoo():local_str=returnglobal_str+笔记:搜索标识符(aka变量,名字,等等当搜索一个标识符的时候,python先从局部作用域开始搜索。如果在局部作用域内没有找到那个名字,那么就一定会在全局域找到这个变量否则就会被抛出NameError在12正空现说子空间仅仅是将名字映射到对象名领域,现在使用的变量名字虚拟集合。作用域的概念和用于找到变量的名字空间搜索顺序相关。当一个函数执行的时候,所有在局部命名空间的名字都在局部作用域内。那就是当查找一个变量的时候,第一个被搜索的名字空间。如果没有在那找到变量的话,那么就可能找到同名的全局变量。这些变量 (搜索)仅仅通过创建一个局部变量来“隐藏“或者覆盖一个全局变量是有可能的。回想一下,局字空间是首先被搜索的,存在于其局部作用域。如果找到一个名字,搜索就不会继续去寻找一个全局域的变量,所以在全局或者内建的名字空间内,可以覆盖任何匹配的名字。同样,当使用全局变量同名的局部变量的时候要。如果在赋予局部变量值之前,你在函数中(为了这个全局变量)使用了这样的名字,你将会得到一个异常(NAMEERROR或者Unbound-LocalErrorpython版本。defprint"\ncallingfoo()..."bar=200print"infoo(),baris",barbar=100print"in main,baris",barfoo()print"\nin main,baris100callingfoo()...infoo(),baris main,baris(still)须使用global语句。global的语法如下:globalvar1[,var2[,...>>>is_this_global=>>>def...global...this_is_local=...is_this_global=...printthis_is_local+>>>printis_this_global11.8.3.作用域的数python从句法上支持多个函数嵌套级别,就如在python2.1中的,匹配静态嵌套的作用域。然而,在2.1至前的版本中,最多为两个作用域:一个函数的局部作用域和全局作用域。虽然存在多个函数的,但你不能超过两个作用域。defm=defn=printm+n7>>>Traceback(innermostFile"<stdin>",line1,in?File"<stdin>",line7,infooFile"<stdin>",line5,inbarNameError:m在函数bar()内foo()的局部变量m是的因为m是为foo()的局部变量。从bar()的列表中。注意'printm'bar()的函数调用却失败了。幸运的是,由于python闭数也会到相同的问题。如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量两种。Closures从句法上看很简单(和内部函数一样简单)但是仍然很有。为什么你会想要用closues?defcounter(start_at=0):count=[start_at]defcount[0]+=1returncount[0]returnincrcounter()做的唯一一件事就是接受一个初始化的的值来开始计数,并将该值赋给列表count唯一一个成员。然后定义一个incr()的内部函数。通过在变量count,我们创建了一个闭包因为它现在携带了整个counter()作用域。incr()增加了正在运行的count然后返回它。然后最后的魔法就是counter()返回一个incr,一个(可调用的)函数对象。如我们交互地运行这个函数,我 >>>count=>>>count2=掉这个类的call()特别方法来使他的实例可调用。这里我们能够使用一对函数来做这事。追踪闭包词法的下面两个部分包含了给高级读者的材料……如果你愿意的话,你可以跳过去。讨论如何func_closure','<cellat0x5ee30:intobjectat<int'w' <int'x'id=0x200377c<int'y' <int'z' 11.7#!/usr/bin/env2output='<int%rid=%#0xw=x=y=z=16def7x=y=z=29def10y=z=12def13z=14printoutput%('w',id(w),15printoutput%('x',id(x),16printoutput%('y',id(y),17printoutput%('z',id(z),z)19clo=20if21print"f3closurevars:",[str(c)forcin2223print"nof3closure2426clo=27if28print"f2closurevars:",[str(c)forcin2930print"nof2closure3133clo=34if35print"f1closurevars:",[str(c)forcin3637print"nof1closure38Lines这 Lines6–9,局部变量遮蔽或者隐藏了对他们同名的全局变量的。如果f2()使用了任何的定义在f1()作用Lines9–10,f1()f2()做相同的事,定义了局部变量yz,以及对一个内部如果对于f3()有任何的自由变量,他们会在这里显示出来。,你会注意到对自由变量的是在单元对象里,或者简单的说,单元。这些东西是什么呢?单元是在作用域结束后使自由变量的存活的一种基础方法。Lines这个部分描绘了f3()的定义,创建一个局部的变量z。接着显示w,x,y,z,这4个变量从最内f3f2(),或者f1(w的,所以,这是个全局f3(f2x,f1()的闭包变量。相似地,yf2()的闭包变量。最后,z是f3()的局部变量。Lines条件表达式不会求得True。这里的这段代码仅仅是有修饰的目的。*高级闭包和装饰器11.3.6deco.py。接下来就是稍微高级点的例子,来给你演示闭包的真正的。应用程序“logs"函数调用。用户选择是要在函数调1#!/usr/bin/env23fromtimeimporttimedefdeflog(f,*args,printfunction:args:defdefwrapper(*args,log(f,*args,returnf(*args,returndefdefwrapper(*args,now=returnf(*args,log(f,*args,print"timedelta:%s"%(time()-returnreturn{"pre":"post":exceptKeyError,raiseValueError(e),'mustbe"pre"or"post"'defprinto,",38$funcLog.pyo,World!function:<functionoat0x555f0>args:('World!',)kargs:timedelta:Lines5–10,描了logged()的的用户请求。它应该在目标函数被调用前还是之后呢?logged()有3()以及post_logged()。lo示标准输出函数的名字和参数。如果你愿意在“真实的世界中”使用该函数的话,你很有可能会把输出写到一个文件,数据库,或者标准错误(sys.stderr)。logged()在28-32上是函数中非函数的最开始的代码。用户的选择然后返回*()函数中的一个便能用目标函调用并包裹它。Lines数已经执行之后,post_loggeed()会将函数调用写入日志,而pre_logged()则是在执行之前。logged(什么时候。然后返回的函数对象作为目标的函数的参数进行调用,比如,pre_logged(f)post_logged(f).两个*logged()wrapper()的闭包。当合适将其写入日志的时候,它便会Lines这段的主要部分简单地装饰了o()函数并将用修改过的函数对象一起执行它。当你在38行调用o()的时候,它和你在35行创建的函数对象已经不是一回事了。34行的装饰器用特殊的装饰将原始函数对象进行了包裹并返回这个包裹后的o()版本。作用域和那些为函数局部变量的lambda表达式在这个函数体内是可以的;然而,在lambda语句中的表达式有和函数相同的作用域。你也可以认为函数和一个lambda表达式是同胞。x=defy=bar=lambda:x+yprintbar()然而,须在回顾下过去,去看下原来的python版本中让代码运行必需的,一种极其普遍的做法。在2.1之前会得到一个错误如同你在下面看到的一样因为函数和lambda都>>>Traceback(innermostFile"<stdin>",line1,in?File"<stdin>",line4,inFile"<stdin>",line3,inNameError:在上面的例子中,虽然lambda表达式在foo()的局部作用域中创建,但他仅仅只能两个作用域:它自己的局部作用域和全局的作用域(Section11.8.3).解决的方法是加入一个变量作为默认参数,这样我们便能从外面的局部作用域传递一个变量到内部。在我们上面的例子中,我们将lambda的那一行修改成这样:bar=lambday=y:yy(lambda的局部变量python变外部y值的可能性,比如:x=defy=bar=lambday=y:x+yprintbar()y=8printbar()ylambdalambda的定义没有变。那时唯一替代的方案就是在lambda表达式中加入对函数局部变量y进行的局部变量z。x=defy=bar=lambdaz:x+zprintbar(y)y=printx=defy=bar=lambda:x+yprintbar(y)y=print变量作用域和名字空间少。我们要么在只能全局作用域的模块的,要么在一个我们能函数局部作用域和全名字空间。从函数内部,局部作用域包围了局部名字空间,第一个搜寻名字的地方。如果名字存在11.91#!/usr/bin/env2j,k=1,34def56j,k=3,7print"j==%dandk==%d"%(j,8k=9 defj=print==%dandk==%d"%(j,k=print==%dandk==%d"%(j,j=print==%dandk==%d"%(j,*N!?factorial(N)?1*2*3...*factorial(N)==N*(N-=N*(N-1)*(N-:=N*(N-1)*(N-2)...*3*2*factorial(NN*factorial(N-1).换句话说,为了获得factorial(N)的值,需要计算factorial(N-1).而且,为了找到factorial(N-1),需要计算defifn==0orn==1:#0!=1!=returnreturn(n*factorial(n-11.10接口。这很容易明白因为他们仅仅只有一个方法,用于调用获得下个元素的next()然而,除非你实现了一个迭代器的类,迭代器真正的并没有那么“聪明“。难道调用函数还没next()调用一样简单的东西?那就是的另外一个方面甚至更加强力用,可以暂停或者挂起,并从程序离开的地方继续或者重新开始。在有调用者和(被调用的)协同足够强大,但是在Python2.5的时候,得到了显著的提高(见pep342)。这些提升让更加接的时候,现在能返回控制。在调用的能挂起(返回一个结果)之前,调用生成器返回一个结果而不是阻塞等待那个结果返回。让我们更进
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026摩洛哥啤酒花深加工行业目前供需调研竞争格局评估投资回报规划发展
- 2026中国自行车骑行护具产品设计趋势与用户画像分析报告
- 2027届新疆昌吉州共同体化学九上期中调研模拟试题含解析
- 2026中国体育器材制造业市场现状供需分析及投资评估规划分析研究报告
- 2026中国智能家居家电市场竞争分析发展现状评估投资规划研究报告
- 2026中国医疗设备行业市场现状竞争分析及投资方向规划分析研究报告
- 2026浙江金华武义县文化和广电旅游体育局招聘1人笔试题库(网校专用)附答案详解
- 2026中国医疗保健国际交流促进会招聘考前冲刺试卷(真题汇编)附答案详解
- 2026广西北海市海城区市场监督管理局公开招聘协管员2人笔试题库及完整答案详解【考点梳理】
- 2026云南临沧市临翔区人民医院高校毕业生(青年)就业见习人员招募考前冲刺试卷带答案详解(研优卷)
- 2026年重庆省考行测真题及答案
- 小区物业整体服务方案投标文件(技术方案)
- MT/T 146-2025树脂锚杆
- 阿里JAVA编码规范手册
- 尾矿库工程施工总体方案设计
- 2026年一级建造师之一建矿业工程实务考试题库300道及完整答案(易错题)
- 2024年版《手术室护理实践指南》练习题(附答案)
- 电气柜布线培训课件
- 基于美育培养的小学语文古诗词教学现状及对策研究-以五年级为例
- 鞋业安全检查指南讲解
- T CAME 23-2020 区域消毒供应中心物流配送管理
评论
0/150
提交评论