函数
*是python为了代码最大程度的重复利用和最小代码冗余而提供的基本程序结构
*是一种设计工具,它能够让程序将复杂的系统分解为可管理的部件
*用于将相关功能打包并
*在python中可以创建这4种函数:
(1)全局函数:定义在模块中 | 尽量避免修改全局变量
(2)局部函数:嵌套与于其它函数中
(3)lambda:表达式
(4)方法:与特定数据类型关联的函数,并且只能与数据类型关联一起使用
*python中提供了很多内置函数
创建函数
*语法:
def functinName(parameters):
suit
一些相关的概念
(1)def 是一个可执行语句
因此可以出现在任何能够使用语句的地方,甚至还可以嵌套其它语句,例如:if或while中
(2)def 创建了一个对象并将其赋值给一个变量名(即:函数名)
(3)return 用于返回结果对象,其为可选;无 return 语句的函数自动返回 None 的对象
返回多值时,彼此之间用逗号分隔,且组合为元组形式返回一个对象
(4)def 语句运行之后,可以在程序中通过函数后附加括号进行调用
函数作用域
*Python 创建、改变或查找变脸名都是在名称空间中进行
*在代码中变量名赋值的位置决定了其能被访问到的范围
*函数定义了本地的作用域,而模块定义了全局的定义域
(1)每个模块都是一个全局作用域,因此,全局作用域的范围仅限于单个程序文件
(2)每次对函数的调用都会创建一个新的本地作用域,赋值的变量除非声明为全局变量,否则均为本地变量
(3)所有的变量名都可以归纳为本地、全局内置的(由__builtin__模版提供)
变量名解析:LEGB法则
变量名引用分3个作用域进行:首先是本地,之后是函数内,接着是全局,最后是内置(作用域越小,优先级越高)
*函数嵌套时,在内部定义之后,也需要在内部调用
*python的闭包
嵌套函数,如果return嵌套函数时,嵌套函数调用的值将会被嵌套函数记住
*注意,列表是可变对象(支持原处修改)
In [1]: l1 = [1,2,3]
In [2]: def f1(x):
...: x.pop()
...: print x
...:
In [3]: f1(l1)
[1, 2]
In [4]: print l1
[1, 2]
*故:不要在函数内部修改可变对象
In [5]: l1 = [1,2,3]
In [6]: def f2(x):
...: x.pop()
...: print x
...:
*传递l1的副本
In [8]: f2(l1[:]) #传参数的时候注意,可避免修改原变量
[1, 2]
In [9]: print l1
[1, 2, 3]
In [10]: l2 = l1[:]
In [11]: l2
Out[11]: [1, 2, 3]
参数匹配模型
*默认情况下,参数通过其位置进行传递,从左至右,这意味着,必须准确地传递和函数头部一样多的参数
*但是也可以通过关键字参数,默认参数或者参数容器等改变这种机制
位置:从左到右
关键字参数:使用'name=value'的语法通过参数名进行匹配
*以上两种方式混用时,先写所有的位置参数,再写关键字参数
默认参数:定义函数时使用'name=value'的语法直接给变量一个值,从而传入的值可以少于参数个数
*写在最前面
可变参数:定义函数时使用 * 开头的参数,可用于收集任意多基于位置或关键字的参数
可变参数解包:调用函数时,使用 * 开头的参数,可用于将参数的集合打散,从而传递任意多基于位置或关键字的参数
*一个*返回元组(收集位置参数),**返回字典(收集关键字参数)
In [20]: def f6(**x):
print x
....:
In [21]: f6(x=2,y=4,z=16)
{'y': 4, 'x': 2, 'z': 16}
In [22]: def f7(x,*y):
....: print x,y
....:
In [23]: f7(2,4,9)
2 (4, 9)
In [24]: def f9(*x,**y):
....: print x
....: print y
....:
In [25]: f9(2,8,9,x=4,y=16)
(2, 8, 9)
{'y': 16, 'x': 4}
变量的分解赋值
In [1]: l1 = ['Mon','Tues','Sun']
In [2]: x,y,z = l1
In [3]: print x,y,z
Mon Tues Sun
*分解参数
In [4]: def f6(x,y,z):
...: print x,y,z
...:
In [5]: f6(l1)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-c839fb903571> in <module>()
----> 1 f6(l1)
TypeError: f6() takes exactly 3 arguments (1 given)
In [6]: f6(*l1)
Mon Tues Sun
In [7]: l2 = ['a','b','c','d']
In [8]: f6(*l2) #参数个数必须要匹配
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-8-dad866aecd84> in <module>()
----> 1 f6(*l2)
TypeError: f6() takes exactly 3 arguments (4 given)
In [9]: l3 = ['a','b']
In [10]: f6(*l3)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-db25026f9264> in <module>()
----> 1 f6(*l3)
TypeError: f6() takes exactly 3 arguments (2 given)
In [11]: f6(2,*l3) #参数个数必须匹配
2 a b
*多变量参数共同使用,混用时,一定要按照顺序
In [17]: d = {'name':'xmj','age':18}
In [18]: def f8(x,*y,**z):
print x
print y
print z
....:
In [19]: f8(6,*l2,**d)
6
('a', 'b', 'c', 'd')
{'age': 18, 'name': 'xmj'}
匿名函数
lambda:表达式
def:语句
*lambda运算符
语法:
lambda args: expression
args:以逗号分隔的参数列表
expession:用args中的各参数表达式 #一定不能是语句
lambda语句定义的代码必须是合法的表达式,不能出现多条件语句(可使用if的三元表达式)和 其它非表达式语句,如 for 和 while 等
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
In [22]: lambda x,y : print x+y #不能是语句,只能是表达式
File "<ipython-input-22-c24e49f64991>", line 1
lambda x,y : print x+y
^
SyntaxError: invalid syntax
In [23]: lambda x,y :x+y #表达式,相当于def定义时,把结果return回去
Out[23]: <function __main__.<lambda>>
*调用
In [24]: f2 = lambda x,y :x+y
In [25]: f2(3,7)
Out[25]: 10
lambda的首要用途是指定短小的回调函数
lmbda将返回一个函数而不是将函数赋值给某个变量名
注意:
lambda是一个表达式而非语句
lambda是一个单表达式,而不死一个代码块
def语句创建的函数将赋值给变量名,而lambda表达式则直接返回函数
lambda也支持使用默认参数
In [26]: l3 = [(lambda x:x*2),(lambda y : y*3)]
In [27]: for i in l3: # i 的取值是列表里面的表达式
....: print i(4) # i(4)表示调用 lambda
....:
8
12
函数式编程
(1)也称作广泛编程,是一种编程范型
(2)它将电脑运算视为教学上的函数计算,并且避免状态和可变数据
(3)函数式编程语言最重要的基础是lambda演算,而且lambda演算的函数可以接受函数当作输入和输出
python支持有限的函数式编程功能
*filter 过滤器
filter()为已知序列的每个元素调用给定的布尔值
调用中,返回值为非零的元素将被添加至一个列表中
In [30]: l1 = [1,2,3,42,67,16]
In [32]: def f1(x):
....: if x>20:
....: return True
....: else:
....: return False
....:
In [34]: filter(f1,l1) #注意调用时的方法
Out[34]: [42, 67]
练习:
返回 /etc/passwd中包含了/bin/bash字串的所有用户名为一个列表
*map 映射器
map()将函数调用映射到每个序列的对应元素上并返回一个含有所有返回值的列表
In [36]: l1 = [0,1,2,3,4,5,6]
In [37]: l2 = ['s','m','w','t','f','s']
In [38]: map(None,l1,l2) #None代表无需做运算,并且由于元素不够,因此没有相对应的时,会出现None
Out[38]: [(0, 's'), (1, 'm'), (2, 'w'), (3, 't'), (4, 'f'), (5, 's'), (6, None)]
In [40]: l2 = ['s','m','w','t','f','s','T']
In [41]: def f3(x):
....: return x*2
....:
In [42]: map(f3,l1)
Out[42]: [0, 2, 4, 6, 8, 10, 12]
In [43]: map(f3,l2)
Out[43]: ['ss', 'mm', 'ww', 'tt', 'ff', 'ss', 'TT']
In [44]: def f4(x,y): #定义参数时必须赋和调用时的情况
....: return x*2,y*2
....:
In [45]: map(f4,l1,l2)
Out[45]: [(0, 'ss'), (2, 'mm'), (4, 'ww'), (6, 'tt'), (8, 'ff'), (10, 'ss'), (12, 'TT')]
*reduce
In [46]: def f5(x,y):
....: return x+y
....:
In [47]: print l1
[0, 1, 2, 3, 4, 5, 6]
In [48]: reduce(f5,l1)
Out[48]: 21
In [49]: reduce(f5,l1,10)
Out[49]: 31
In [50]: reduce(f5,l2)
Out[50]: 'smwtfsT'
In [51]: print l2
['s', 'm', 'w', 't', 'f', 's', 'T']
*函数的嵌套:在内部调用|在内部当返回值返回
*Python的闭包
In [55]: def f1(x): #f1的主要目的是为f2提供运行环境
....: def f2(y):
....: return y**x
....: return f2
....:
In [56]: f1(4)
Out[56]: <function __main__.f2>
In [60]: f3 = f1(4)
In [61]: type(f3)
Out[61]: function
In [62]: f3(2) #闭合特性
Out[62]: 16
In [63]: f3(3)
Out[63]: 81
In [77]: def startpost(m,n):
....: def newpost(x,y):
....: print "The old position(%d,%d),and the new position is (%d,%d)" %(m,n,m+x,n+y)
....: return newpost
....:
In [78]:
In [78]: action = startpost(1,2)
In [79]: type(action)
Out[79]: function
In [80]: action(10,10)
The old position(1,2),and the new position is (11,12)
In [81]: action(1,3)
The old position(1,2),and the new position is (2,5)
yield 可以生成一个生成器对象
生成器自身都是可迭代的
In [88]: def genum(x):
....: y = 0
....: while y <= x:
....: yield y
....: y += 1
....:
In [89]: g1 = genum(10)
In [90]: type(g1)
Out[90]: generator #生成器对象
In [91]: g1.next()
Out[91]: 0
In [92]: g1.next()
Out[92]: 1
In [93]: g1.next()
Out[93]: 2
*函数中自定义yeild,会返回一个生成器对象
In [95]: def num(n):
....: i = 1
....: while i <= n:
....: yield i**2
....: i += 1
....:
In [96]: g1 = num(20)
In [97]:
In [97]: type(num)
Out[97]: function
In [98]: for i in g1:
....: print i
....:
1
4
9
16
25
36
49
64
81
100
121
144
169
196
225
256
289
324
361
400
装饰器
(1)本身是一个函数,目的是为了装饰其它函数
(2)增强被装饰函数的功能
装饰器--一般接受一个函数对象作为参数以对其增强
In [100]: def deco(func):
.....: def wrapper():
.....: print "Please say something!"
.....: func()
.....: print "No zuo no die..."
.....: return wrapper
.....:
In [101]: @deco
.....: def show():
.....: return "I am from Mars."
.....:
In [102]: show()
Please say something!
No zuo no die...
In [103]: @deco
def show():
print "I am from Mars."
.....:
In [104]: show()
Please say something!
I am from Mars.
No zuo no die...
In [106]: def deco(func):
.....: def wapper(x):
.....: print "Please say something...>"
.....: func(x)
.....: print "No zuo no die..."
.....: return wapper
.....:
In [107]: @deco
.....: def show(x):
.....: print x
.....:
In [108]: show("hello ,Mars")
Please say something...>
hello ,Mars
No zuo no die...
递归函数
*递归:在运行过程中,一层一层调用自己,直到不符合条件时退出
递归需要边界条件,递归前段和递归返回段
*一个函数内部包含了对自己的调用
*阶乘的求法
In [110]: def fact(n):
.....: if n <= 1:
.....: return 1
.....: else:
.....: return n*fact(n-1)
.....:
In [111]: fact(3)
Out[111]: 6
In [112]: fact(5)
Out[112]: 120
协程:
函数的设计规范
(1)耦合性:
*尽可能的通过参数接受输入,以及通过return产生输出以保证函数的独立性;
*尽量减少使用全局变量进行函间的通信;
*不要在函数中直接修改可变类型参数;
*避免直接改变定义在另外一个模块中的变量;
(2)聚合性
*每个函数都应该有一个单一的,统一的目标;
*每个函数的功能都应该相对简单;