(一)创建函数:
1、内建的callable函数可以用来判断函数是否可调用:
(Python 2.7.4)
1 >>> import math 2 >>> x = 1 3 >>> y = math.sqrt 4 >>> callable(x) 5 False 6 >>> callable(y) 7 True
【注意】函数callable在Python 3.0中不再可用,需要使用表达式hasattr(func._call_)代替。有关hasattr更多信息,参见第7章。
2、使用def(或“函数定义”)语句创建函数:
如:返回斐波那契数列的函数:
1 >>> def fibs(num): 2 result = [0,1] 3 for i in range(num - 2): 4 result.append(result[-2] + result[-1]) 5 return result 6 7 >>> fibs(10) 8 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 9 >>> fibs(5) 10 [0, 1, 1, 2, 3] 11 >>>
3、记录函数:在函数开头写下字符串,它会作为函数的一部分进行存储,这称为文档字符串。
文档字符串可以按输入myfuction._doc_方式访问,但是读者发现在Python 2.7.4只有myfuction.func_doc能行:
1 def myf(): 2 'i want this function return two character showing welcome' 3 return "你好" 4 5 >>> print myf() 6 你好 7 >>> myf._doc_ 8 9 Traceback (most recent call last): 10 File "<pyshell#21>", line 1, in <module> 11 myf._doc_ 12 AttributeError: 'function' object has no attribute '_doc_' 13 >>> myf.func_doc 14 'i want this function return two character showing welcome' 15 >>>
【注意】_doc_是函数属性,详细看第7章。属性名下的双划线表示它是个特殊属性,详细看第9章。
4、内建help函数,在交互式解释器中使用,就可以得到关于函数、包括它的文档字符串的信息:
1 >>> def myf(): 2 'i want this function return two character showing welcome' 3 return "你好" 4 5 >>> help(myf) 6 Help on function myf in module __main__: 7 8 myf() 9 i want this function return two character showing welcome
1 >>> import math 2 >>> help(math.sqrt) 3 Help on built-in function sqrt in module math: 4 5 sqrt(...) 6 sqrt(x) 7 8 Return the square root of x.
(二)参数魔法
1、在函数内为参数赋予新值不会改变外部任何变量的值。
【注意】参数存储在局部作用域(local scope)内。
2、字符串(以及数字和元组)是不可变的,即无法被修改(也就是说,只能用新的值覆盖)。所以它们做参数的时候也就无需多做介绍。
但是如果将可变的数据结构,如列表,作为参数的时候,会发生:参数被改变了。
1 >>> names = ['aaa','bbb'] 2 >>> n = names 3 >>> n[0] = 'new' 4 >>> names 5 ['new', 'bbb']
6 >>> names2 = ['aaa','bbb'] 7 >>> n2 = names2[:] 8 >>> #现在n2和names2包含两个独立(不同)的列表,其值相等: 9 >>> n2 is names2 10 False 11 >>> n2 == names2 12 True 13 >>> #如果现在改变n2,就不会影响到names2了: 14 >>> n2[0] = 'new' 15 >>> n2 16 ['new', 'bbb'] 17 >>> names2 18 ['aaa', 'bbb']
3、初始化数据结构的函数:
1 >>> def init(data): #把初始化代码放到函数中 2 data['first'] = {} 3 data['middle'] = {} 4 data['last'] = {} 5 6 7 >>> #使用: 8 >>> s = {} 9 >>> init(s) 10 >>> s 11 {'middle': {}, 'last': {}, 'first': {}}
【注意】字典的键并没有具体顺序,每次在解释器中打印的顺序可能不同。
4、如果参数不可变,比如数字,想要改变值,只能从函数中返回你要的值了(多的话用元组返回):
1 >>> def addself(x): 2 return x + 1 3 4 >>> y = 1 5 >>> y = addself(y) #赋值为使用addself函数后返回的值 6 >>> y 7 2
【小技巧】如果真想改变参数,那么可以将值放在在列表中:
1 >>> def addself(x): #无需返回值哦 2 x[0] = x[0] + 1 3 4 5 >>> y = [1] #将值放在列表中 6 >>> addself(y) #这样代码看起来比较清新 7 >>> y 8 [2]
5、关键字参数和默认值
目前为止我们使用的参数都叫位置参数。
关键字参数:可以明确每个参数的作用,避免参数多的时候很难记住参数的顺序。
1 >>> def myf(greet,name): 2 print "%s,%s" % (greet,name) 3 4 5 >>> myf('hello','lisa') 6 hello,lisa 7 >>> myf(greet = 'hi',name = 'linda') 8 hi,linda
最厉害的是,可以在函数中给参数提供默认值。如果参数具有默认值,调用的时候,你可以不提供参数、提供一些或提供所有。
1 >>> def wel(greet = 'what',name = 'who'): 2 print '%s,%s' % (greet,name) 3 4 5 >>> wel() 6 what,who 7 >>> wel(name = 'Elizabeth') 8 what,Elizabeth 9 >>> wel('hah') 10 hah,who
位置参数和关键字参数可以联合使用,但要把位置参数放在前面。不然,解释器会不知道它们到底谁是谁(也就是它们应该处的位置)。
【注意】除非完全清楚程序的功能和参数的意义,否则避免混合使用位置参数和关键字参数。
6、收集参数
让用户提供任意数量的参数。
*:参数前的星号将所有值放在同一个元组中,如果有普通参数在前,星号的意思就是“收集其余位置的参数”(除了关键字的参数)。
**:处理关键字参数的“收集”操作。放在字典里,而不是元组。
1 >>> def print_params(x,y,z = 3,*pospar,**keypar): 2 print x,y,z 3 print pospar 4 print keypar 5 6 7 >>> print_params(1,2,3,7,8,9,foo = 1,bar = 2) 8 1 2 3 9 (7, 8, 9) 10 {'foo': 1, 'bar': 2}
7、反转过程
使用*和**可以收集参数,放进元组和字典里,供函数使用。也可以执行相反的操作,将收集好的元组或字典里的参数通过*或**传进函数。
【注意】operator模块中包含此函数的效率更高版本。
使用*:
1 >>> def add(x,y): 2 return x + y 3 4 >>> params = (1,2) 5 >>> add(*params) 6 3
使用**:
1 >>> def hello(name,sex): 2 print name + ' is a '+ sex 3 4 >>> params = {'name':'one','sex':'girl'} 5 >>> hello(**params) 6 one is a girl
星号只在定义函数(允许使用不定数目的参数)或者调用“分隔”字典或序列时才有用:
1 >>> def wit(**k): #在定义中使用星号 2 print k['name'],' is',k['age'],' years old.' 3 4 5 >>> def nwit(k): #在定义中不使用星号 6 print k['name'],' is',k['age'],' years old.' 7 8 9 >>> args = {'name':'one','age':'36'} 10 >>> wit(**args) #在使用中使用星号 11 one is 36 years old. 12 >>> nwit(args) #在使用中不使用星号 13 one is 36 years old. 14 >>> #效果一样
(三)作用域
1、在执行 x = 1 后,名称 x 引用到值 1 。就像字典一样。当然,变量和所对应的值用的是个“不可见”的字典,叫做命名空间或者作用域。内建的vars函数可以返回这个作用域:
1 >>> x = 1 2 >>> scope = vars() 3 >>> scope['x'] 4 1 5 >>> scope['x'] += 1 6 >>> x 7 2
每个函数调用都会创建一个新的作用域。
函数内的变量被称为局部变量(local variable)。
1 >>> def myf(): 2 x = 32 3 4 5 >>> x = 1 6 >>> myf() 7 >>> x 8 1
这里 myf函数改变(重绑定)了变量 x ,但是调用myf的时候创建了新的命名空间,x = 32只在内部作用域(局部命名空间)其作用,没有影响到全局作用域的x。
【屏蔽(Shadowing)的问题】
同名的话,全局变量会被局部变量屏蔽,但是可以使用globals函数获取全局变量值,该函数的近亲是vars,它可以返回全局变量的字典:
1 >>> param = "哈哈" 2 >>> def myf(param): 3 print param + globals()['param'] 4 5 6 >>> myf('paramfrommyf') 7 paramfrommyf哈哈
使用globals函数,重绑定全局变量(使变量引用其他新值):
1 >>> x = 1 2 >>> def change(): 3 global x 4 x = x+1 5 6 7 >>> change() 8 >>> x 9 2
2、嵌套作用域
突出应用是,例如需要用一个函数“创建”另一个。详细见105页,不常用吧。
(四)递归
1、recursion:see recursion.
有用的递归函数包含:
(1)当函数直接返回值时有基本实例(最小可能性问题)。
(2)递归实例,包括一个或者多个问题最小部分的递归调用。
关键就是将问题分解为小部分。
经典应用:阶乘、幂、二分查找。
2、函数到处放
Python对“函数式编程”方面有一些有用的函数:map、filter和reduce函数(Python3.0中这些都被移至functools模块中)。filter函数可以基于一个返回布尔值的函数都会元素进行过滤。
1 >>> map(str,range(10)) 2 ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
1 >>> def func(x): 2 return x.isalnum() 3 4 >>> seq = ['aaa','x35','?!','***','&%$#'] 5 >>> filter(func,seq) 6 ['aaa', 'x35']
还有个叫做lambda表达式的特性,可以创建短小的函数。
1 >>> filter(lambda x:x.isalnum(),seq) 2 ['aaa', 'x35']
貌似都不常用。