# 第六章 函数与函数编程

## 函数

```   1 def add(x,y):
2     return x+y
```

def foo(x,y,z = 42):

```   1 a = 10
2 def foo(x = a):
3     print x
4 a = 5               # Reassign 'a'.
5 foo()               # Prints '10' (默认值没有改变)
```

```   1 a = [10]
2 def foo(x = a):
3     print x
4 a.append(20)
5 foo()              # Prints '[10, 20]'
```

```   1 def fprintf(file, fmt, *args):
2     file.write(fmt % args)
3
4 # fprintf.args 被赋值为 (42, "hello world", 3.45)
5 fprintf(out,"%d %s %f", 42, "hello world", 3.45)
```

```   1 def printf(fmt, *args):
2         # Call another function and pass along args
3         fprintf(sys.stdout, fmt, *args)
```

```   1 def foo(w,x,y,z):
2     print w,x,y,z
3
4 #以关键字参数形式调用函数
5 foo(x=3, y=22, w='hello', z=[1,2])
```

`foo('hello', 3, z=[1,2], y=22)`

```   1 def spam(**parms):
2     print "You supplied the following args:"
3     for k in parms.keys():
4         print "%s = %s" % (k, parms[k])
5 spam(x=3, a="hello", foobar=(2, 3))
```

```   1 # Accept variable number of positional or keyword arguments
2 def spam(x, *args, **keywords):
3     print x, args, keywords
```

```   1 def callfunc(func, *args, **kwargs):
2     print args
3     print kwargs
4     func(*args, **kwargs)
```

```   1 def foo():
2     print "Hello world"
3
4 foo.secure = 1
5 foo.private = 1
```

`       注意：这仅仅是自定义函数的特权，内建函数或者类的方法是没有这种行为的。 --WeiZhong`

## 参数传递和返回值

```   1 a = [1,2,3,4,5]
2 def foo(x):
3     x[3] = -55    # 修改 x 中的一个元素
4
5 foo(a)            # 传递 a
6 print a           # 显示 [1,2,3,-55,5]
```

return语句用于从函数中返回一个对象。如果没有指定返回对象或者return语句被省略,则会返回一个None对象.如果要返回多个值，可以通过返回一个元组或其它包含对象来完成。

```   1 def factor(a):
2     d = 2
3     while (d <= (a/2)):
4         if ((a/d)*d == a):
5               return ((a/d),d)
6         d = d + 1
7     return (a,1)
```

```   1 x,y = factor(1243)    # 返回的值被赋值给 x 和 y.
2 (x,y) = factor(1243)  # 同样的效果
```

## 作用域规则

```   1 a = 42
2 def foo():
3     a = 13
4 foo()
5 print a
```

```   1 a = 42
2 def foo():
3     global a        # 'a' 在全局名字空间
4     a = 13
5 foo()
6 print a
```

```   1 def bar():
2   x = 10
3   def spam():            # 嵌套函数定义
4        print 'x is ', x  # 在bar()的全局名字空间中寻找x
5   while x > 0:
6        spam()            # 若在Python2.0中运行该代码 程序会报错 : NameError on 'x'
7        x -= 1
```

`        注：Python 2.4中该功能已经是内建功能，不需要做那个 from __future__ import nested_scopes 操作了 --WeiZhong`

```   1 def foo():
2     print i       # 导致UnboundLocalError exception异常
3     i = 0
```

## 递归

Python对递归函数调用的次数作了限制.函数 sys.getrecursionlimit()返回当前允许的最大递归次数,而函数sys.setrecursionlimit()可以改变该函数的返回值.默认的最大递归次数为1000.当一个函数递归次数超过最大递归次数时,就会引发RuntimeError异常.

## apply()函数

apply(func [, args [, kwargs ]]) 函数用于当函数参数已经存在于一个元组或字典中时间接的调用函数. args是一个包含将要提供给函数的按位置传递的参数的元组. 如果省略了args,任何参数都不会被传递. kwargs是一个包含关键字参数的字典.下面的语句效果是一样的:

```   1 foo(3,"x", name='Dave', id=12345)
2 apply(foo, (3,"x"), { 'name': 'Dave', 'id': 12345 })
```

```   1 a = (3,"x")
2 b = { 'name' : 'Dave', 'id': 12345 }
3 foo(*a,**b)     # 与上边的代码相同
```

## lambda操作符

lambda语句用来创建一个匿名函数(没和名字绑定的函数):

lambda args: expression

args是一个用逗号分隔的参数, expressin是一个调用这些参数的表达式,例如:

```   1 a = lambda x,y : x+y
2 print a(2,3)              # 打印出 5
```

lambda定义的代码必须是一个合法的表达式.多重语句和其他非表达式语句(如print, for, while等)不能出现在lambda语句中. lambda表达式也遵循和函数一样的作用域规则.

`        lambda 已经是过时的语句，即将被废除。 --WeiZhong`

## map(), zip(), reduce(), 和filter()

t = map(func, s )函数将序列s中的每个元素传递给func函数做参数, 函数的返回值组成了列表 t. 即t[i] = func(s[i]). 需要注意的是, func函数必须有只有一个参数,例如:

```   1 a = [1, 2, 3, 4, 5, 6]
2 def foo(x):
3     return 3*x
4 b = map(foo,a)   # b = [3, 6, 9, 12, 15, 18]
```

```   1 b = map(lambda x: 3*x, a)   # b = [3, 6, 9, 12, 15, 18]
```

map ()函数也可以用于多个列表,如 t = map(func, s1, s2, ..., sn ). 如果是这种形式,t中的每个元素 t [i ] = func(s1[i ], s2[i ], ..., sn[i ]) .func函数的形参个数必须和列表的个数(n)相同,结果与s1,s2, ... sn中的最长的列表的元素个数相同.在计算过程中,短的列表自动用None扩充为统一长度的列表.

```   1 a = [1,2,3,4]
2 b = [100,101,102,103]
3 c = map(None, a, b)   # c = [(1,100), (2,101), (3,102), (4,103)]
```

```   1 d = [1,2,3,4,5,6,7]
2 e = [10,11,12]
3 f = zip(d,e)   # f = [(1,10), (2,11), (3,12)]
```

reduce(func , s )函数从一个序列收集信息,然后只返回一个值(例如求和,最大值,等).它首先以序列的前两个元素调用函数,再将返回值和第三个参数作为参数调用函数,依次执行下去,返回最终的值. func函数有且只有两个参数.例如:

```   1 def sum(x,y):
2     return x+y
3
4 b = reduce(sum, a)   # b = (((1+2)+3)+4) = 10
```

filter(func ,s)是个序列过虑器，它使用func()函数来过滤s中的元素。使func返回值为false的元素被丢弃，其它的存入filter函数返回的列表中,例如:

```   1 c = filter(lambda x: x < 4, a)   # c = [1, 2, 3]
```

## 列表内涵

```[表达式 for item1 in 序列1
for item2 in 序列2
...
for itemN in 序列N
if 条件表达式]```

```   1 s = []
2 for item1 in sequence1:
3     for item2 in sequence2:
4         ...
5            for itemN in sequenceN:
6                if condition: s.append(expression)
```

Listing 6.1 中的例子可以帮助你理解列表内涵

Listing 6.1 列表内涵

```   1 import math
2 a = [-3,5,2,-10,7,8]
3 b = 'abc'
4 c = [2*s for s in a]          # c = [-6,10,4,-20,14,16]
5 d = [s for s in a if s >= 0]  # d = [5,2,7,8]
6 e = [(x,y) for x in a         # e = [(5,'a'),(5,'b'),(5,'c'),
7            for y in b         #      (2,'a'),(2,'b'),(2,'c'),
8            if x > 0]          #      (7,'a'),(7,'b'),(7,'c'),
9                               #      (8,'a'),(8,'b'),(8,'c')]
10 f = [(1,2), (3,4), (5,6)]
11 g = [math.sqrt(x*x+y*y)       # f = [2.23606, 5.0, 7.81024]
12      for x,y in f]
13 h = reduce(lambda x,y: x+y,   # 平方根的和
14            [math.sqrt(x*x+y*y)
15             for x,y in f])
```

## eval(), exec, execfile(),和compile()

eval(str [,globals [,locals ]])函数将字符串str当成有效Python表达式来求值，并返回计算结果。

```        >>> eval('3+4')
7
>>> exec 'a=100'
>>> a
100
>>> execfile(r'c:\test.py')
hello,world!
>>> ```

```   1 globals = {'x': 7,
2            'y': 10,
3            'birds': ['Parrot', 'Swallow', 'Albatross']
4           }
5 locals = { }
6
7 # 将上边的字典作为全局和局部名称空间
8 a = eval("3*x + 4*y", globals, locals)
9 exec "for b in birds: print b" in globals, locals   # 注意这里的语法
10 execfile("foo.py", globals, locals)
```

`        在Python2.4中俺未发现可以引起异常 --WeiZhong`

`        exec(str) 这种形式也被接受，但是它没有返回值。 --WeiZhong`

compile(str ,filename ,kind )函数将一个字符串编译为字节代码, str是将要被编译的字符串, filename是定义该字符串变量的文件，kind参数指定了代码被编译的类型-- 'single'指单个语句, 'exec'指多个语句, 'eval'指一个表达式. cmpile()函数返回一个代码对象，该对象当然也可以被传递给eval()函数和exec语句来执行,例如:

```   1 str = "for i in range(0,10): print i"
2 c = compile(str,'','exec')      # 编译为字节代码对象
3 exec c                          # 执行
4
5 str2 = "3*x + 4*y"
6 c2 = compile(str2, '', 'eval')  # 编译为表达式
7 result = eval(c2)               # 执行
```

PythonEssentialRef6 (last edited 2009-12-25 07:10:06 by localhost)

• Page.execute = 1.691s
• getACL = 0.100s
• init = 0.012s
• load_multi_cfg = 0.001s
• run = 3.333s
• send_page = 3.222s
• send_page_content = 1.730s
• send_page_content|1 = 0.388s
• send_page|1 = 0.476s
• total = 3.346s