1函数概述1)数学定义y=f(x),y是x的函数,x是自变量2)Python函数:由若干条语句组成的语句块,一个函数名,以及一个参数列表,是组织代码完成某个功能的最小单位2功能:结构化成为对代码最基本的封装,一般按照功能来组织一段代码;封装的目的是重用和减少冗余代码;代码更加简洁美观,可读易懂;3内置函数Python提供了很多内置函数,可以直接使用。下表列出了一些功能。id()返回变量idhast()返回对象的哈希值type()返回对象类型input()获取用户输入信息print()打印输出信息len(s)返回集合类型isinstance的元素个数(obj,class_or_tuple)判断对象obj是否属于某个类型,返回bool类型hex()oct()bool()list()tuple()dict()set()complex()bytes()bytearray()类型转换enumerate(seq,start=0)返回索引号和序列的二元组elementsexamplestr_1="helloworld"print(id(str_1))print(hash(str_1))print(type(str_1))4函数定义:def函数名(参数列表):函数体(代码块)[return返回值]函数名必须是合法的标识符,约定和名字一样清晰,尽量使用英文缩写,语句块必须是indented,agreement4如果在python函数中不写带空格的return语句,默认会返回一个None值。函数定义的参数列表变成了形式参数,它只是一个符号表达式,称为形式参数调用:函数定义只是声明一个函数,它不会被执行,调用方式是函数名加括号,括号内写参数。调用时写的参数为实参,即实参示例defadd(x:int,y:int)->int:"""一个函数,执行两个数相加"""returnx+y#callsum=add(10,16)print(sum)5调用函数的参数时,传入的参数个数必须与定义的个数相匹配(可变参数除外)。位置参数:例子:deffun(x,y,z):max_num=max(x,y,z)print(max_num)#位置参数,调用时按照定义的顺序传入实参。fun(10,20,30)关键字参数:例子:deffun(x,y,z):result=z-x-yprint(result)#传参方法fun(x=10,y=20,z=30)#可以改变参数传递的顺序fun(y=20,x=10,z=30)#关键字参数应该在位置参数之前传递,位置参数对应位置。fun(10,z=30,y=20)参数默认值:定义时,一个值遵循形参示例:示例:deffun(x=1,y=2,z=3):result=z-x-yprint(result)variableparameter:一个形参可以匹配parameterpositionparameter的任意一个variableparameter:defadd(*nums):sum=0print(type(nums))forxinnums:sum+=xadd*beforeprint(sum)的形参表示该参数为可变参数,可以接收多个实参,将多个实参收集成一个元组,通常使用*argsvariable关键字参数:defshowconfig(**kwargs):fork,vinkwargs.items():print('{}={}'.format(k,v))#形参使用**符号,表示可以接收多个关键字参数#收集到的实参namesandvalues形成字典#混合使用可变参数:defshowconfig(username,password,**kwargs):passdefshowconfig(username,*args,**kwargs):pass参数汇总:gen参数列表的顺序是普通参数、默认参数、可变位置参数、仅关键字参数、可变关键字参数。参数解构示例:defadd(x,y):returnx+yadd(4,5)#直接调用t=(4,5)add(*t)add(*range(1,3))#Iterableobjects也可以用来传递参数#前提是参数个数相同6Scope:一个标识符可见的范围,一般来说就是变量的作用域。全局作用域:在整个运行环境可见局部作用域:局部变量的使用范围不能超出其所在的局部作用域例:x=5deffoo():y=x+1x+=1#错误,赋值是Definition,相当于直接使用print(x)globalvariableifxisnotdefinedglobalx=5deffoo():globalxx+=1print(x)foo()closure自由变量:没有定义的变量在本地范围内。例如,在内存函数之外的外部函数范围内定义的变量。闭包:是出现在嵌套函数中的一个概念,意思是内层函数引用外层函数的自由变量,形成一个闭包。defcounter():c=[0]definc():c[0]+=1#这里不会报错,因为是c[0]而不是c,就是对c中的元素重新赋值returnc[0]returninc#return是函数引用,不是函数调用foo=counter()print(foo(),foo())#print1and2c=100print(foo())#print3上面是在python2中实现闭包的方式,Python3中也可以使用关键字nonlocaldefcounter():c=1definnter():nonlocalcc+=1returncreturninnterfoo=counter()print(foo(),foo())c=100print(foo())nonlocal关键字:将变量标记为定义在上层的局部作用域,而不是全局作用域。默认值的范围deffoo(l=[]):l.append(1)print(l)foo()#print[1]foo()#print[1,1]#原因是函数是同样是对象,python把函数对象的默认值放在属性中,而这个属性伴随着函数对象的整个生命周期。参见foo.__defaults__deffoo(l=[],u='abc',z=123):l.append(1)print(l)print(foo(),id(foo))print(foo.__defaults__)print(foo(),id(foo))print(foo.__defaults__)#函数两次打印相同的id,说明函数的地址没有变,也就是函数的对象没有变。调用它,它的属性__defaults__使用一个元组来保存所有的默认值。#其中l的默认值为引用类型,引用类型的元素发生变化,而不是元组的变化。在非引用类型中deffoo(l=1,u='abc',z=123):u='xyz'z=789print(l,u,z)print(foo.__defaults__)#print(1,'abc','123')print(foo(),id(foo))print(foo.__defaults__)#print(1,'abc','123')变量类型默认值,如果使用这个默认值,你可以修改这个默认值。有时这个功能好,有时这个功能不好,会带来一些麻烦如何根据需要修改?看这两个方法deffoo(x=[],u='abc',z=123):x=x[:]x.append(1)print(x)foo()print(foo.__defaults__)foo()print(foo.__defaults__)foo([10])print(foo.__defaults__)foo([10,5])print(foo.__defaults__)deffoo(x=None,u='abc',z=123):如果x是None:x=[]x.append(1)print(x)foo()print(foo.__defaults__)foo()lst=[10]foo(lst)print(lst)#lst发生变化print(foo.__defaults__)foo([10,5])print(foo.__defaults__)一般函数中不要使用print语句,最后使用return第一种方法:使用shadowcopy创建一个新对象,永远不要改变传入的参数。第二种方法:通过判断值,可以灵活选择创建或修改传入对象。这种方法灵活,适用范围广。在很多函数的定义中,可以看到使用None这个不可变值作为默认参数,这是一种常见的用法。7函数的销毁全局函数1)重新定义同名函数2)del语句3)程序末尾的局部函数1)重新定义同名函数2)del语句3)上级作用域销毁8变量名分析原理LEGB1)Local:局部函数Domain,局部作用域的局部命名空间,在函数被调用时创建,调用结束时消亡,全局作用域,一个模块的命名空间,在模块导入时创建,以及destroyedwhentheinterpreterexits9递归函数Recursion递归:直接或间接调用自身的函数就是递归。递归需要有边界,递归正向段,递归返回段。递归必须有边界条件。返回间接递归是通过另一个函数调用函数本身。但是形成递归调用是非常危险的,但往往在代码复杂的情况下还是可能会出现这种调用。应使用代码规范来避免此类递归调用。注意:慎用递归递归必须有一个退出条件,递归调用必须执行到这个退出条件。递归调用的深度不宜太深。查看递归限制层数:importsysprint(sys.getrecursionlimit())递归性能:循环稍微复杂一点,但只要不是无限循环,可以迭代多次,直到计算出结果.递归函数代码简单易懂,但只能获取和使用最外层的函数,内部递归结果都是中间结果。此外,给定n,必须执行2n次递归。深度越深,效率越低。递归示例:求n的阶乘deffun(n):ifn==1:return1returnn*fun(n-1)print(fun(3))10匿名函数:Python使用lambda表达式构造匿名函数格式:lambad参数列表:表达式lambdax:x*2(lambdax:x*2)(4)#callfoo=lambdax,y:(x+y)**2foo(2,1)usage:advancedWhen给一个函数传递参数,使用lambda表达式往往可以简化代码这个函数得到一个生成器对象生成器函数:1)一个在函数体中包含yield语句的函数,返回一个生成器对象2)一个生成器对象,它是一个可迭代的object,也是一个迭代器3)一个生成器对象,延迟计算,Lazyevaluation4)普通函数调用fn(),函数会立即执行,但是生成器函数可以使用next函数多次执行生成器函数.生成器函数等同于生成器对象,但是生成器函数可以更复杂一些。示例defgen():print("line1")yield1print("line2")yield2print("line3")return3next(gen())#line1next(gen())#line1g=gen()print(next(g))#line1print(next(g))#1ine2print(next(g))#line3StopIterationprint(next(g,'End'))#生成器在最后,返回默认值“结束”
