(一)创建函数:

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']

貌似都不常用。