一、匿名函数
-
匿名函数,即没有名字的函数,在高阶函数传参时,使用 lambda 表达式,往往能简化代码
-
格式:lambda 参数列表 : 表达式lambda x : x **2foo = lambda x,y : (x+y)**2 foo(2,1) –> 9
-
使用 lambda 关键字来定义匿名函数参数列表不需要小括号冒号是用来分割参数列表和表达式的不需要使用 return,表达式的值,就是匿名函数返回值lambda 表达式(匿名函数)只能写在一行上,被称为单行函数
-
>>> (lambda x,y=3:x+y)(5,y=44) –> 49>>> (lambda x,*,y=30:x+y)(5,y=9) –> 14>>> print((lambda *args: [x+2 for x in args])(*range(5))) –> [2, 3, 4, 5, 6]>>> [x for x in (lambda *args:map(lambda x:x+1,args))(*range(5))] –> [1, 2, 3, 4, 5]>>> [x for x in (lambda *args:map(lambda x:(x+1,args),args))(*range(5))]–> [(1, (0, 1, 2, 3, 4)), (2, (0, 1, 2, 3, 4)), (3, (0, 1, 2, 3, 4)), (4, (0, 1, 2, 3, 4)), (5, (0, 1, 2, 3, 4))]
二、递归
-
函数直接或者间接调用自身就是递归递归需要有边界条件、递归前进段、递归返回段递归一定要有边界条件当边界条件不满足的时候,递归前进当边界条件满足的时候,递归返回
-
递归调用的深度不宜过深Python 对递归调用的深度做了限制,以保护解释器超过递归深度限制,抛出 RecursionError: maxinum recursic depth exceeded 超出最大深度查看递归深度import sysdef fool(b,b1=3):fool(b)print(sys.getrecursionlimit())sys.setrecursionlimit(2000) 把递归深度改为 2000
-
递归的性能循环稍微复杂一些,但是只要不是死循环,可以多次迭代直至算出结果递归还有深度限制,如果递归复杂,函数反复压栈,栈内存很快就溢出了
-
递归总结递归是一种很自然的表达,符合逻辑思维递归相对运行效率低,每一次调用函数都要开辟栈帧递归有深度限制,如果递归层次太深,函数反复压栈,栈内存很快就溢出了如果是有限次数的递归,可以使用递归调用,或者使用循环代替,循环代码稍微复杂一些,但是只要不是死循环,可以多次迭代直至算出结果绝大多数递归,都可以使用循环实现即使递归代码很简洁,但是能不用则不用递归
三、返回值和作用域
-
Python 函数使用 return 语句返回 “返回值”所有函数都使用返回值,如果没有 return 语句,隐式调用 return Nonereturn 语句并不一定是函数的语句块的最后一条语句一个函数可以存在多个 return 语句,但是只有一条可以被执行,如果没有一条 return 语句被执行到,隐式调用 return None如果有必要,可以显示调用 return None,可以简写为 return如果函数执行了 return 语句,函数就会返回,当前被执行的 return 语句之后的其它语句就不会被执行了作用:结束函数调用、返回值
-
函数不能同时返回多个值return 1,3,5 看似返回多个值,隐式的被 Python 封装成了一个元祖,然后顺便可以用解构提取更方便
-
函数有可见范围,这就是 作用域 的概念内部函数不能在外部直接使用,会抛出 NameError 异常,因为它不可见
-
一个标识符的可见范围,这就是标识符的作用域,一般常说的是变量的作用域
-
全局作用域在整个程序运行环境中都可见局部作用域在函数、类等内部可见局部变量使用范围不能超过其所在的局部作用域
-
因为函数的语句块中没有类似于 x = 的语句,所以 y = x + 1 中的 x 会从上一级找,从而不报错x = 5def fn():y = x + 1print(x)fn()因为函数会先扫描语句块,且函数的语句块中有 x = 的语句,所以会先调用本地的变量,但是本地并没有赋值,所以就会报错,记住一句话:赋值即定义x = 5def fn():y = x + 1x += 1print(x)fn()
-
使用 global 关键字的变量,将 fn 内的 x 声明为使用外部的全局作用域中定义的 x,且全局作用域中必须有 x 的定义x = 5def fn():global xx += 1print(x)fn()
-
global 总结x += 1 这种是特殊形式产生的错误原因是:先引用后赋值,而 Python 动态语言是赋值才算定义,才能被引用,解决办法是在这条语句前增加 x = 0 之类的赋值语句,或者使用 global 告诉内部作用域,去全局作用域查找变量定义内部作用域使用 x = 5 之类的赋值语句会重新定义局部作用域使用的变量 x,但是,一旦这个作用域中使用 global 声明 x 为全局的,那么 x = 5 相当于在为全局作用域的变量 x 赋值
-
global 使用原则外部作用域变量会在内部作用域可见,但也不要在这个内部的局部作用域中直接使用,因为函数的目的就是为了封装,尽量与外界隔离如果函数需要使用外部全局变量,请使用函数的形参传参解决一句话:不用 global,学习它就是为了深入理解变量作用域
-
使用了 nonlocal 关键字,将变量标记为不在本地作用域中定义,而在上级的某一级局部作用域中定义,但不能是全局作用域中定义,这样就形成闭包def counter():cc = 0def inc():nonlocal cccc += 1return ccreturn incfoo = counter()foo()
-
默认值的作用域def foo(xyz=[]):xyz.append(1)print(xyz)foo() –> [1]foo() –> [1,1]因为函数也是对象,Python 把函数的默认值放在了属性中,这个属性就伴随这个函数对象的整个生命周期函数地址并没有变,就是说函数这个对象的属性没有变,调用它,它的属性 __defaults__ 中所使用元祖保存默认值为了避免出现这种情况:使用影子拷贝创建一个新的对象def foo(xyz=[]):xyz = xyz[:]xyz.append(1)print(xyz)foo() –>[1]print(foo.__defaults__) –>([],)foo() –>[1]print(foo.__defaults__) –>([],)foo([10]) –>[10,1]print(foo.__defaults__) –>([],)通过值得判断就可以灵活的选择创建或者修改传入对象def foo(xyz=None,u=’abc’,z=123):if xyz is None:xyz = []xyz.append(1)print(xyz)foo() –>[1]print(foo.__defaults__) –>(None,’abc’,123)foo() –>[1]print(foo.__defaults__) –>(None,’abc’,123)foo([10]) –>[10,1]print(foo.__defaults__) –>(None,’abc’,123)
-
属性 __defaults__ 中使用元祖保存所有位置参数默认值属性 __kwdefaults__ 中使用字典保存所有 keyword-only 参数的默认值def foo(w,u=’abc’,*,z=123,zz=[456]):u = ‘xyz’z = 789zz.append(1)print(w,u,z,zz)print(foo.__defaults__)foo(‘magedu’)print(foo.__kwdefaults__)
-
一个变量的查找顺序是 LEGB:Local(本地作用域)–> Enclosing(嵌套构成的闭包)–>Global(全局作用域) –>Build-in(内置模块的命名空间)
-
全局函数销毁重新定义同名函数del 语句删除函数对象程序结束时局部函数销毁重新在上级作用域定义同名函数del 语句删除函数对象上级作用域销毁时
本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/95946