一、函数基础简单来说,函数就是程序中可以运行一次或多次的Python语句的组合。Python中的函数在其他语言中也称为过程或子例程,因此这些包装语句由函数名调用。有了函数,我们就可以大大减少复制粘贴代码的次数(相信很多人一开始都有这种体会)。我们可以提取相同的代码来制作一个函数,只需要在需要的地方调用它。那么,这就提高了代码的复用率,整体代码看起来更简洁,不那么臃肿。函数是Python中最基本的程序结构,用来最大限度地复用我们的代码;同时,函数可以将复杂的系统划分为可管理的部分,简化编程和代码重用。接下来,让我们看看函数是什么以及它应该如何定义。有两种定义函数的方法,即def和lambda关键字。函数定义首先总结一下为什么要使用函数?最大化代码重用,最小化冗余代码;过程分解(拆卸)。将一个复杂的任务分解成多个较小的任务。函数定义的语法为:deffunc_name(arg1,arg2,arg3,...,argN):语句返回值根据上面的定义,可以简单描述为:Python中的一个函数有0个或多个参数并且有几行语句并有一个返回值(返回值是可选的)一个语句块(注意缩进)。然后我们定义一个比较简单的函数,没有参数,进入ipython交互环境:In[1]:defhello():...:print('Leavemealone,theworld')...:Call(execute)thisfunction:`In[2]:hello()Leavemealone,theworld`我们发现hello()函数没有return语句。在Python中,如果没有显式执行return语句,那么函数的返回值默认为None。我们说过定义函数有两种形式,另一种形式是使用lambda定义的。使用lambda定义的函数是匿名函数,后面会解释,这里暂时不展示。2.函数参数在定义函数时,我们确定了参数的名称和位置,函数的接口定义就完成了。对于函数的调用者来说,知道如何传递正确的参数以及函数将返回什么值就足够了。函数内部的复杂逻辑被封装了,调用者不需要知道。Python的函数定义很简单,但是很灵活。除了通常定义的强制参数外,还可以使用默认参数、可变参数和关键字参数,这样函数定义的接口不仅可以处理复杂的参数,还可以简化调用者的代码。默认参数默认参数使API简洁而不失灵活性。当一个参数有默认值时,调用时如果不传这个参数,就会使用默认值。definc(init,step=1):returninit+step调用此函数会报语法错误)。允许有多个默认参数,但默认参数需要放在参数列表的末尾。defappend(x,lst=[]):returnlst.append(x)这个函数有问题。(函数中的形参是全局变量?lst在append函数中叫做lst,但是在全局范围内,我们不知道lst叫什么名字。)修改后的函数为:defappend(x,lst=None):iflstisNone:lst=[]lst.append(x)returnlst一般来说,当默认参数可变时,需要特别注意作用域的问题,我们需要上面的技巧(不可变的数据类型按值传递,可变数据类型按引用传递。)。当前可变对象有list、dict、set、bytearray。默认参数很好用,但是如果使用不当,也会掉坑里。默认参数坑最大,演示如下:先定义一个函数,传入一个list,加一个END然后returndefadd_end(L=[]):L.append('END')returnL当我们正常调用它时,结果似乎不错:add_end([1,2,3])[1,2,3,'END']add_end(['x','y','z'])['x','y','z','END']当我们使用默认参数调用时,结果就在开头:add_end()['END']但是,当我们再次调用add_end()时,结果是错误的:add_end()['END','END']add_end()['END','END','END']原因解释如下:Python函数定义时,其值计算默认参数L,即[],因为默认参数L也是一个变量,指向对象[],每次调用函数,如果改变了L的内容,默认的内容下次调用函数时参数会改变,函数定义起来时不再是[]。因此,在定义默认参数时要记住一件事:默认参数必须指向不可变对象!修改上面的例子,我们可以使用None作为不变对象:defadd_end(L=None):ifLisNone:L=[]L.append('END')returnL为什么要设计str,None这样的呢不可变对象?因为不可变对象一旦创建,对象内部的数据就无法修改,减少了修改数据带来的错误。另外,由于对象没有变化,在多任务环境下读取对象时不需要加锁,同时读取也没有问题。我们在写程序的时候,如果可以设计一个不变对象,那就尽量把它设计成一个不变对象。位置参数我们先写一个计算x^2的函数:defpower(x):returnx*x对于power(x)函数,参数x是一个位置参数。我们在调用power函数的时候,必须传入唯一的参数x:power(5)25power(15)225那么,如果我们要计算x^3呢?你可以再定义一个power3函数,但是如果你想计算x^4,x^5,x^n呢?我们不可能定义无限多的函数。我们可以把power(x)修改为power(x,n)来计算x^n,照你说的写就可以了:defpower(x,n):s=1whilen>0:n=n-1s=s*xreturn的关键字参数可变参数允许我们传入0个或任意数量的参数,这些可变参数在函数被调用时会自动组装成一个元组。关键字参数允许你传入0或者任何包含参数名的参数,这些关键字参数会在函数内部自动组装成一个dict。例子如下:defperson(name,age,**kwargs):print('name:',name,'age:',age,'other:',kwargs)除了必须的参数name和age,函数person也接受关键字参数kwargs。调用该函数时,只需传入必填参数:person('LavenLiu',25)name:LavenLiuage:25other:{}1.2.也可以传入任意数量的关键字参数:person('LavenLiu',25)name:LavenLiuage:25other:{}person('Taoqi',25,city='Hebei')name:Taoqiage:25other:{'city':'河北'}person('James',31,gender='M',job='NBAplayer')name:Jamesage:31other:{'gender':'M','job':'NBA球员'}1.2.3.4.5.6.7.8。关键字参数有什么用?它可以扩展函数的功能。比如在person函数中,我们保证能收到name和age这两个参数,但是如果调用方愿意提供更多的参数,我们也可以收到。假设您正在执行用户注册功能。除了用户名和年龄是必填项外,其他都是可选的。使用关键字参数定义该函数即可满足注册要求。与可变参数类似,也可以先组装一个dict,然后将dict转为关键字参数:kwargs={'city':'Hebei','job':'Test'}person('Taoqi',25,**kwargs)name:Taoqiage:25other:{'city':'Hebei','job':'Test'}位置参数和关键字参数位置参数和关键字参数是函数调用时的概念。在将默认参数与关键字参数组合时很有用。关键字参数必须写在位置参数之后,否则会抛出语法错误。defminus(x,y):returnx-yminus(3,5)#位置参数,位置参数传递minus(5,3)#位置参数,位置传递参数minus(x=5,y=3)#关键字参数,关键字参数minus(y=3,x=5)#关键字参数、关键字参数和关键字参数可以共存,但是关键字参数必须写在position参数之后。可变位置参数可变位置参数用*定义,在函数体中,可变位置参数是一个元组。可变位置参数。In[1]:deffn(*args):...:print(args)...:In[2]:fn((1,2,3,4))((1,2,3,4),)In[3]:tup01=(1,2,3,4)In[4]:fn(tup01)((1,2,3,4),)In[5]:fn(*tup01)(1,2,3,4)在python函数中,也可以定义可变参数。可变参数是指传入的参数个数是可变的。In[6]:defcacl(*numbers):...:sum=0...:forninnumbers:...:sum=sum+n*n...:returnsum...:In[7]:nums=[1,2,3]In[8]:cacl(nums)#这里如果不在nums前面加,是不是有问题?Out[8]:14Variablekeywordparameters变量关键字参数使用**定义,在函数体中,变量关键字参数是一个字典。variable关键字参数的key均为字符串,符合标识符定义规范。deffn(**kwargs):print(kwargs)dict01={'name':'LavenLiu','age':29}fn(**dict01)fn(dict01)fn(name='LavenLiu',age=29){'name':'LavenLiu','age':29}{'name':'LavenLiu','age':29}可变位置参数只能作为带可变关键字的位置参数调用argumentscanonlybecalledaskeywordarguments变量位置参数必须先于变量关键字参数In[18]:deffn(args,*kwargs):...:print(args)...:print(kwargs)...:在[19]:fn(1,2,3,a=1,b=2)(1,2,3){'a':1,'b':2}在[20]:deffn(*args,x,y):...:print(args)....:print(x,y)...:In[21]:fn(1,2,3,4)TypeErrorTraceback(最近的calllast)
