函数庄天红什么是函数?•函数是一种程序构件,是构成大程序的小功能部件(子程序)–function一词本身就有功能的含义–我们已经熟悉的函数:•自己编的函数,如常用的main()•Python内建函数,如abs()•Python库函数,如math.sqrt()•对象的方法,如win.close()和p.draw()•与数学函数的异同–同:函数名,参变量,函数值,定义与使用–异:算法过程定义;参数传递;副作用2函数的定义和使用•先定义(define)•再通过函数名调用(call)•调用时传递参数•调用执行的是函数体(语句序列)•调用产生返回值•函数定义可置于程序中任何地方,但必须在调用之前3deffunc(x):y=x*xreturnya=func(2)为什么需要函数?•编程更容易把握–大程序分解成小功能部件•代码重用,避免重复相同/相似代码–提高开发效率–更易维护•程序更可读,更易理解•代码简洁美观4编程实例:生日歌•减少相同代码的重复defmain():print“Happybirthdaytoyou!”print“Happybirthdaytoyou!”print“Happybirthday,dearFred.”print“Happybirthdaytoyou!”defhappy():print“Happybirthdaytoyou!”defmain():happy()happy()print“Happybirthday,dearFred.”happy()重复代码的缺点:(1)费时费力(2)代码一致性维护编程实例:生日歌(续)•相似代码的重复defhappy():print“Happybirthdaytoyou!”defsingFred():happy()happy()print“Happybirthday,dearFred.”happy()defsingLucy():happy()happy()print“Happybirthday,dearLucy.”happy()编程实例:生日歌(续)•用参量(parameter)增强函数的通用性defmain():singFred()singLucy()defhappy():printHappybirthdaytoyou!defsing(person):happy()happy()printHappybirthday,dear,person+.happy()defmain():sing(Fred)sing(Lucy)sing(Elmer)8实例分析:futval3.py•在统计未来收益程序中,有类似重复的代码:#Drawbarforinitialprincipalbar=Rectangle(Point(0,0),Point(1,principal))bar.setFill(green)bar.setWidth(2)bar.draw(win)bar=Rectangle(Point(year,0),Point(year+1,principal))bar.setFill(green)bar.setWidth(2)bar.draw(win)实例分析:futval3.py•futval2.py两处画柱子的代码是类似的–循环外的初始柱子–循环内的每年的柱子•解决方法defdrawBar(window,year,height):bar=Rectangle(Point(year,0),Point(year+1,height))bar.setFill(“green”)bar.setWidth(2)bar.draw(window)初始:drawBar(win,0,2000)#假如本金2000每年:drawBar(win,year,height)–完整程序futval3.py9函数参数的用途•函数参数一般用来使函数具有通用性•但还有别的用途–考虑函数defdrawBar(window,year,height)–可变的数据如year和height,使得本函数能画各年度不同高度的柱子–Q:window并不变,为何作为参数?–A:这与作用域有关!•drawBar函数中的window参数是主函数中函数调用语句win参数传递过来的,它指输出Bar在win内•#DrawbarforinitialprincipaldrawBar(win,0,principal)变量的作用域•变量具有作用域(scope):即可以引用该变量的程序区域.–不同作用域中的变量,即使同名,也是不同的变量!–作用域可以是局部,也可以是全局•本函数定义的变量是局部的:即作用域是该函数内部.–函数的参量可视为局部变量,只不过是在调用时才赋值.x,y=0,0deff(x):y=1printx,yf(10)printx,y•运行结果:10100变量的作用域(续)•不是本函数定义的变量,则引用本函数外部定义的变量.x=0deff(y):z=1printx,y,zf(10)•若需使用非本函数的变量,可通过参量传递.x=0deff(p,y):z=1printp,y,zf(x,10)–前例中的作图窗口win通过参量window传递给drawBar()f()xy,zx全局变量•若需引用并且修改函数外部定义的变量,可声明全局变量.x=1deff():printx#未定义变量视为全局变量x=2#赋值引入局部变量,则前行出错!(此行注释)f()defh():globalxprintxx=2#此赋值是针对全局变量的printxh()运行结果:112f()xh()xx函数调用过程•函数定义def函数名(形参列表):函数体•函数调用函数名(实参列表)–进程转子–函数形参被赋值为实参•按位置对应,或按名(形参=实参),即位置和个数均一一对应•实参可以是字面值,也可以是已赋值的变量–执行函数体–控制返回调用者(调用点的下一条语句)函数调用过程图解带返回值的函数•函数与调用者之间的沟通:–通过参量从调用者输入值–通过返回值向调用者输出值•定义def函数名(形参):……return表达式列表–return计算各表达式,将结果返回调用者,退出函数–没有return的函数其实也返回一个值:None•调用x,y,...=函数名(实参)•也可以定义无参函数–非常简单的函数–无需带入参数值和返回值18函数与参数例子—futval3.py•Futval3例题中的drawBar函数调用语句中的实参:drawBar(win,0,principal)•函数定义中的首行:defdrawBar(window,year,height):•参数传递好似执行了几条赋值语句:window=winyear=0height=principal•所以,实参给出的值不同,函数调用多次返回的结果值就不同19函数返回值的例子•square(3)9•print(square(4))16•x=5y=square(x)print(y)25•print(square(x)+square(3))3420函数的返回值•某些函数需要返回多于一个值•返回语句中有多于一个变量:defsumDiff(x,y):sum=x+ydiff=x–yreturnsum,diff•当调用这个函数时,使用同时赋值语句:num1,num2=eval(input(Entertwonumbers(num1,num2)))s,d=sumDiff(num1,num2)print(Thesumis,s,andthedifferenceis,d)编程实例:triangle2.py•修改triangle.py程序,计算三角形的周长.•定义了两个带返回值的函数:defsq(x):returnx*xdefdist(p1,p2):d=math.sqrt(sq(p2.getX()p1.getX())+sq(p2.getY()p1.getY()))returnd……p=dist(p1,p2)+dist(p2,p3)+dist(p3,p1)22有关银行账户的例题•银行账户利率的统计:•addInterest子函数defaddInterest(balance,rate):newBalance=balance*(1+rate)balance=newBalance•测试主函数deftest():amount=1000rate=0.05addInterest(amount,rate)print(amount)•为什么账户金额没增加?23有关银行账户的例题24有关银行账户的例题25有关银行账户的例题defaddInterest(balance,rate):newBalance=balance*(1+rate)returnnewBalancedeftest():amount=1000rate=0.05amount=addInterest(amount,rate)print(amount)test()运行结果:105026许多银行账户统计利率-改进•如果若干银行账户统计:•修改第一个账户的余额:balances[0]=balances[0]*(1+rate)•#addinterest3.py#Illustratesmodificationofamutableparameter(alist).defaddInterest(balances,rate):foriinrange(len(balances)):balances[i]=balances[i]*(1+rate)deftest():amounts=[1000,2200,800,360]rate=0.05addInterest(amounts,0.05)print(amounts)test()结果:[1050.0,2310.0,840.0,378.0]27许多银行账户统计利率-改进360]28许多银行账户统计利率-改进list作为参数传递的概念,实质是共用同一组内存空间的概念360]函数与程序结构•函数不只是为了减少重复代码.•函数还使程序更加模块化(modular).–即使增加了代码量!•编程实例:futval4.py–将主程序中并未重复出现的语句序列改写成了一个函数,原地方改成一个函数调用.–代码量不减反增,但程序可读性大大增强!30函数与程序结构#futval_graph4.py#Plotsaninvestment10yearsintothefuture.#Illustratesuseofafunctionstoeliminatecodeduplication#andimproveprogramreadability.fromgraphicsimport*defcreateLabeledWindow():window=GraphWin(InvestmentGrowthChart,320,240)window.setBackground(white)window.setCoords(-1.75,-200,11.5,10400)Text(Point(-1,0),'0.0K').draw(window)Text(Point(-1,2500),'2.5K').draw(window)Text(Point(-1,5000),'5.0K').draw(window)Text(Point(-1,7500),'7.5k').draw(window)Text(Point(-1,10000),'10.0K').draw(window)returnwindow31函数与程序结构defdrawBar(window,year,height):bar=Rectangle(Point(year,0),Point(year+1,height))bar.setFill(green)bar.setWidth(2)bar.draw(window)defmain():printThisprogramplotsthegrowthofa10yearinve