​


函数:  是对程序逻辑进行结构化或过程化的一种编程方法!

来看一下函数的形式:

>>> def bar():
return ('abc', [2, 's'], 'ss')
>>> x, y, z = bar()
>>> (a, b, c) = bar()
>>> s = bar()
>>> s
('abc', [2, 's'], 'ss')
>>> x
'abc'
>>> a
'abc'
>>> b
[2, 's']
>>>


OK,看一下一个小游戏代码,熟悉一下python的函数调用和上一节的异常处理:

from operator import add, sub
from random import randint, choice
ops = {'+': add, '-': sub}
MAXTRIES = 2
def doprob():
op = choice('+-')#随机选择操作符
nums = [randint(1, 10) for i in range(2)]#或者[randint(1, 10), randint(1, 10)]
nums.sort(reverse = True)#由大到小排序
ans = ops[op](*nums)
pr = '%d %s %d=' % (nums[0], op, nums[1])
oops = 0
while True:
try:
if int(raw_input(pr)) == ans:
print 'correct'
break
if oops == MAXTRIES:
print 'answer\n%s%d'%(pr, ans)
else:
oops += 1
except (KeyboardInterrupt, EOFError, ValueError):
def main():
while True:
doprob()
try:
opt = raw_input('Again? [y]').lower()
if opt and opt[0] == 'n':
break
except (KeyboardInterrupt, EOFError):
break
if __name__ == '__main__':
main()


跟其他语言相同,python中你也可以再不同的函数中使用相通的变量,然后可以在另一个函数中一同调用!



内嵌/内部函数


如:

>>> def foo():
def bar():
print 'bar'
print 'foo'
bar()

>>> foo()
foo
bar
>>> bar()
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
bar()
NameError: name 'bar' is not defined

你调用foo()是正确的,调用bar()就会报错,因为他是在foo函数中定义的。




可变长的函数参数



有时候我们要使用可变长的函数参数,变长的函数在函数声明中不是显示命名的,因为参数的数目在运行时之前是未知的。

函数的调用提供了两种类型:关键字,非关键字两种参数类型,python用两种方法来支持变长的参数。

在C 中我们有varargs!(va_list, va_start,va_end),  在我们的python中也类似!

关键字变量参数带元组的函数语法:

def fun([formal_args,] *vargs_tuple):

星号操作符之后的形参将作为元组传递给参数。



>>> def t(arg1, arg2 = 't', *the):
print 'formal arg1:', arg1
print 'formal arg2:', arg2

>>> def t(arg1, arg2 = 't', *the):
print 'formal arg1:', arg1
print 'formal arg2:', arg2
for eachX in the:
print 'another arg:', eachX

>>> t('s')
formal arg1: s
formal arg2: t
>>> t(23, 44)
formal arg1: 23
formal arg2: 44
>>> t(22, 33, 44, 55, 66, 77, 88)
formal arg1: 22
formal arg2: 33
another arg: 44
another arg: 55
another arg: 66
another arg: 77
another arg: 88




非关键字变量参数字典 参数函数的的定义:


def fun([formal_args,][*vargst,] **vargsd):
...


在这里,**为了不和幂运算发生混淆,重载了! 关键字变量参数应该是函数定义的最后一个参数,带**!


下面看字典的例子:


>>> def t(arg1, arg2 = 't', **the):
print 'formal arg1:', arg1
print 'formal arg2:', arg2
for eachX in the.keys():
print 'Xtra arg %s: %s' % (eachX, str(the[eachX]))

>>> t(12, 23, c='s')
formal arg1: 12
formal arg2: 23
Xtra arg c: s
>>> t('e', 's', men=('as', 'df'))
formal arg1: e
formal arg2: s
Xtra arg men: ('as', 'df')


要注意的是:

关键字字典参数必须出现在非关键字元组之后!


如:

>>> def t(arg1, arg2 = 't', *ts, **the):
print 'formal arg1:', arg1
print 'formal arg2:', arg2
for s in ts:
print 'additional non-keyword arg:', s
for sp in the.keys():
print "additional keyword arg '%s': %s" % (sp, the[sp])

>>> t(33, 4324, 'sdf', f = 324, ss = 333)
formal arg1: 33
formal arg2: 4324
additional non-keyword arg: sdf
additional keyword arg 'ss': 333
additional keyword arg 'f': 324



当然我们还可以这样来调用函数:


>>> t(22, 33, *(3, 4), **{'s':2, 'd':4})
formal arg1: 22
formal arg2: 33
additional non-keyword arg: 3
additional non-keyword arg: 4
additional keyword arg 's': 2
additional keyword arg 'd': 4
>>> a = (3, 4, 5)
>>> b = {'a':1, 'b':2}
>>> t(33, 44, *a, **b)
formal arg1: 33
formal arg2: 44
additional non-keyword arg: 3
additional non-keyword arg: 4
additional non-keyword arg: 5
additional keyword arg 'a': 1
additional keyword arg 'b': 2





函数式编程


匿名函数:






lambda [arg1[, arg2,...argn]]:expression



来看一下实例:



>>> def true():
return True
>>> true()
True
>>> trues = lambda: True
>>> trues()
True



OK!


看一下带参数的函数:


>>> def add(x, y):
return x+y
>>> add(1, 2)
3
>>> adds = lambda x, y: x+y
>>> adds(1, 2)
3



lambda是一个函数的单行版本,但是他不同于C++中的inline函数,这种语句的目的是由于性能的原因,在调用时绕过函数的栈分配!





内建函数:

apple() filter() map() reduce()





1、apple()






python1.6已经摒弃。


2、filter()






过滤器!将好的过滤出来!filter函数将给定的序列的每个元素调用给定的布尔函数,每个返回true的元素添加到列表中!

用图来解释:

OK 。我们来看一下列子:


>>> from random import randint
>>> def s(n):
return n%3
>>> allNums = []
>>> for eachNum in range(10):
allNums.append(randint(1, 99))

>>> print filter(s, allNums)
[28, 46, 52, 8, 26, 61, 67, 53, 62]



还记得刚才看到的lambda吧!我么可以把s函数用lambda代替:   lambda n: n%3


或者是print改写成:


print [n for n in allNums if n%3]



当然,s函数是不能要的!



其实我们用列表解析会更加灵活!我们用r代替randint

>>> from random import randint as r
>>> print [n for n in [r(1, 99) for i in range(10)] if n % 3]

看是不是更加的简单了啊!!!




3、map()






map与filter相似!而map是映射!他返回一个含有所有返回值的列表!







比较一下:

>>> filter((lambda x: x+2),[0, 1, 2,])
[0, 1, 2]
>>> map((lambda x: x+2), [0, 1, 2])
[2, 3, 4]

来看一下图列:

 

然后多个序列作用到map上呢?


>>> map((lambda x: x+2), [0, 1, 2])
[2, 3, 4]
>>> map(lambda x, y: x + y, [1, 2, 3,], [1, 2, 3])
[2, 4, 6]
>>> map(lambda x, y:(x+y, x-y), [1, 2, 3], [1, 2, 3])
[(2, 0), (4, 0), (6, 0)]





然而我们还有一个函数式zip,他的功能是什么呢?


>>> map(None, [1, 2, 3], [1, 2, 3])
[(1, 1), (2, 2), (3, 3)]
>>> zip([1, 2, 3], [1, 2, 3])
[(1, 1), (2, 2), (3, 3)]



Ok,我们看了代码,应该会明白了吧!!!




4、reduce()







reduce(f, [1, 2, 3])



等价于



f(f(1, 2), 3)



用图来解释就是:

 


>>> reduce(lambda x,y:x+y, range(10))
45
>>> reduce(lambda x,y:x+y, 'hello world')
'hello world'








偏函数:





先来看一段代码:


>>> from operator import add, mul
>>> from functools import partial
>>> add1 = partial(add, 1)
>>> mul100 = partial(mul, 100)
>>> add1(10)
11
>>> mul100(10)
1000



通过代码可以看出,利用partial,你可以实现泛华。。 也就是add两个参数中先给你提供一个,然后成立新的函数,提供给这个新函数一个参数就可以了!


当调用含有多个参数的函数的时候,这是一种很好的方法! 这就是PFA(PARTIAL FUNCTION APPLICATION)偏函数应用!

再来看一个实用点的函数:


>>> a = partial(int, base = 16)
>>> a('fff')
4095
>>> a('000f')
15
>>> a('0010')

大家应该能看懂吧,16进制转换成int十进制!  当然你也可以修改base






生成器:


一个函数或者子程序只返回一次,但是一个生成器能暂停执行并返回一个中间结果! 这就是生成器一个带yield语句的函数!


>>> def s():
yield 1
yield 2
yield 3

>>> for eachItem in s():
print eachItem

1
2
3
>>> m = s()
>>> m.next()
1
>>> m.next()
2
>>> m.next()
3
>>> m.next()
Traceback (most recent call last):
File "<pyshell#209>", line 1, in <module>
m.next()
StopIteration



通过上面的代码大家会看清楚吧!


如果你想结束生成器那就用close()方法