四、匿名及递归函数
1、函数设计
- 耦合性
- 对于输入是用参数并且对于输出使用return语句;
- 只有真正必要的情况下使用全局变量;
- 不要改变可改变类型的参数,除非调用者希望这样;
- 每个函数都应有一个单一的、统一的目标;
- 每个函数应相对较小;
- 避免直接改变在另一个模块文件中的变量。
总之,使函数和其他编程组件中的外部依赖性最小化。函数的自包含性越好,则越容易被理解、复用和修改。
函数执行环境:
2、递归函数
(1)直接或间接地调用自身以进行循环的函数。
- 定义简单,逻辑清晰;缺点:过深调用会导致栈溢出
(2)通常包含两部分:
- 基线条件(针对最小的问题):满足这种条件时函数将直接返回一个值。
- 递归条件:包含一个或多个调用,这个调用旨在解决问题的一部分。
(3)递归定律:
- 必须有基本结束条件;
- 必须改变自己的状态并向基本结束条件演进;
- 必须递归调用自身
(4)需要防止栈溢出
- 在计算机中,函数调用是通过栈(stack)实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小有限,所以,递归调用的次数过多会导致栈溢出。
- 解决方法:通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
- 尾递归:是指在函数返回时,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,是递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环
Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题
3、函数对象:属性和注解
- 与函数的参数和结果相关的任意的用户定义的数据。
- 是可选的,出现时只附加到函数对象的__annotations__属性以供其他用户使用。
- 有注解时,Python将它们收集到字典中并且将它们附加给函数对象自身。
- 编写了注解仍可对参数使用默认值。
注解只在def语句中有效,在lambda表达式中无效。
4、匿名函数(lambda)
- lambda表达式
- 创建了 一个可以调用的函数;
- 返回函数而不是将这个函数赋值给一个变量名;
- 是表达式,而不是一个语句;
- 主体时一个单个的表达式,而不是一个代码块。
- 通常用来编写跳转表,即行为的列表或字典,能够按照需要执行相应的动作。
在lambda中打印时使用sys.stdout.write(str(x)+'\n')。
嵌套lambda和作用域,嵌套的lambda能够获取到在上层函数作用域中的变量名x的值
5、函数式编程工具
(1)map
(2)filter
(3)reduce
接受一个迭代器来处理,自身不是迭代器,返回一个单个的结果。