您的位置:首页 > 编程语言 > Python开发

【python学习】之二、函数式编程

2012-07-30 14:35 387 查看
作者:jofranks 原创作品,转载请标明出处!版权所有,侵权必究!

来源:http://blog.csdn.net/jofranks

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

来看一下函数的形式:

>>> 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:
print 'invorrect... try again'
oops += 1

except (KeyboardInterrupt, EOFError, ValueError):
print 'invalid input... try again'

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()方法




--------------2012/7/30





---------------jofranks 于南昌





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: