zoukankan      html  css  js  c++  java
  • 【python学习】之二、函数式编程

    作者: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 于南昌

  • 相关阅读:
    vgrant使用简易教程
    php数组常用函数总结
    php面向对象基础知识整理之类中的属性和方法的使用
    apache和nginx的区别
    thinkphp发送邮箱(以thinkphp5作为示例)。
    利用html2canvas将当前网页保存为图片.
    作为一名程序员该如何思考自己的职业人生?
    js常用返回网页顶部几种方法
    如何本地搭建centos7虚拟主机?
    Spark报错
  • 原文地址:https://www.cnblogs.com/java20130723/p/3211430.html
Copyright © 2011-2022 走看看