函数设计概念
函数设计原则:
- 只有在真正必要的情况下使用全局变量
- 每一个函数都应该有一个单一的目标:这个目标可以用一个简单说明句来总结,不应该宽泛或者包含多件事情
- 避免直接改变另一个模块文件中的变量
函数有多种方法获得输入产生输出,一般使用参数作为输入,return语句配合可变参数的改变作为输出。
函数输入:
- 参数
- 全局变量
- 文件/流
函数输出:
- return语句
- 可变参数
- 全局变量
- 文件/流
创建
def fun(args):
return
def语句
def创建了一个函数对象并将其赋值给一个变量。def语句是实时执行的,在模块导入时运行或者在交互模式下输入时运行。
始终记住:函数是一个对象,就像数字、字符串一样。除了函数调用外,还可以dir查看函数对象的属性。
return语句:函数结果作为调用表达式的值,如果没有return语句,函数返回None。
调用:
fun()
在函数名后增加()可以调用函数。参数是通过赋值传递的。
lambda表达式:创建一个函数对象并将其作为结果返回。
lambda argu1, argu2, arguN : expression using argus
lambda表达式中可以使用默认参数。
lambda表达式可以实现的函数完全可以用def实现,但是由于lambda是表达式而非语句,可以用在def不适用的地方,比如作为一个列表的元素。另一方面,lambda表达式的主体是个表达式而非代码块,所以只能编写简单函数。示例:
>>>key = 'got'
>>>{'already':(lambda: 2+2), 'got':(lambda: 2*4)}[key]()
8
使用lambda表达式的几种特殊案例:
- 打印:如果希望在lambda函数中进行打印,应该使用sys.stdout.write()表达式,而不是print语句
- 选择逻辑:if/else三元表达式
lambda x, y : x if x < y else y
- 循环:如果需要在lambda中执行循环,可以使用map函数或者列表解析表达式
import sys
showall = lambda x:map(sys.stdout.write, x)
t = showall(['spam\n', 'eggs\n'])
showall = lambda x: [sys.stdout.write(line) for line in x]
t = showall(['spam\n', 'eggs\n'])
参数
在调用函数时,需要向函数传递参数。参数的传递是以赋值的形式实现的,遵循赋值操作的约束。
python中关于参数需要着重介绍的概念是参数匹配模型。参数会出现在两个地方:函数头部的参数以及调用时传入的参数,分别称为形参和实参。
函数:
- def fun(name):常规参数:通过位置或者变量名进行匹配
- def fun(name=value):默认参数
- def fun(*name):匹配并收集额外不匹配的位置参数到元组name中
- def fun(**name):匹配并收集额外的不匹配关键字参数到字典name中
- def fun(*args, name):调用中参数必须按照关键字传递
函数头部参数必须以此顺序出现:一般参数,默认参数,*name,
**name
调用者:
- fun(value):常规参数:通过位置进行匹配
- fun(name=value):关键字参数:通过变量名进行匹配
- fun(*seq):解包序列成一般参数,按位置传递所有参数
- fun(**dict):解包字典成关键字参数,按关键字传递所有参数
函数调用中,参数必须以此顺序出现:位置参数,关键字参数,*seq,
**dict
参数匹配步骤:
- 通过位置匹配非关键字参数
- 通过变量名匹配关键字参数
- 额外的非关键字参数收集到*name元组中
- 额外的关键字参数收集到**name字典中
- 对于在头部未得到分配的参数使用默认值
当所有的匹配都完成后,通过赋值操作实现传参。
变量的作用域
本地变量:在def内的函数中是可见的,并且仅在函数调用时存在,在函数退出时消失。
global:声明模块级的变量
递归函数
对于线性迭代,一般使用循环结构而不用递归,因为前者简单并且高效;但是对于需要遍历任意形状结构的情况,循环不再适用,这个时候需要使用递归。
其他
生成器函数
yield表达式替代常规函数中的return语句,用于定义生成器函数,调用时返回一个迭代器对象,该对象支持next()方法,可以开始这个函数或者从上次yield值后的地方恢复。
以常规的def语句编写,但是使用yield语句一次返回一个结果。这样仅在需要的时候才产生结果,而不是立即产生所有结果。
def gensquares(N):
for i in range(N):
yiled i ** 2
x = gensquares(4)
next(x)-->0
next(x)-->1
next(x)-->4
next(x)-->9
next(x)-->StopIteration
生成器在内存使用和性能方面都比常规函数更好,尤其在结果列表很大时,这一点尤其有用。
生成器表达式
和列表解析式非常类似,区别在于用()而非[]括起来。生成器表达式返回一个生成器对象,支持迭代协议,可以使用所有的迭代工具。
生成器本身就是迭代器,和文件对象相同。