代码改变世界

Python学习笔记《Python核心编程》第11章 函数和函数式编程

2013-01-26 15:50  VVG  阅读(3706)  评论(0编辑  收藏  举报

如果函数没有返回值。则函数的返回值为None。函数可以返回一个值或者对象。

     def foo():

           return ['xyz',1000000,-98.6]

     def bar():

           return 'abc',[12,'python'],'Guido'      #其实返回的是一个元组。省略了圆括号('abc',[12,'python'],'Guido')

     用圆括号来调用函数。如:bar()     foo()

     关键字参数:允许参数缺失或者不按顺序,解释器能通过给出的关键字来匹配参数的值。如:

          def foo(x,y):

               '文档字符串'

               foo_suite   

          标准调用函数foo: foo(1,2)  foo("bar","foo")   # 按照顺序输入参数

          关键字调用foo:foo(x=1,y=2)or foo(y=2,x=1)         foo(y="foo",x="bar")   #按照关键字赋值参数,可以不按顺序

函数示例:

#!/usr/bin/env python

from operator import add, sub
from random import randint, choice

ops = {'+':add,'-':sub}           # 全局字典
MAXTRIES = 2                      # 全局尝试次数

def doprob():                     #定义函数doprob
    op = choice("+-")             #random.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 'incorrect...try again'
                oops += 1
        except (KeyboardInterrupt,\
                EOFError,ValueError):
            print 'invalid input ...try agin'
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 不允许在函数未申明之前,对其进行引用或者调用。

 内部/内嵌函数:

      在函数体内创建另外一个函数式完全可以的,这种函数叫做内部/内嵌函数。    ————内部函数作用域只在外部函数作用域内,外部访问不了。    

 函数装饰器 ——装饰器就是函数,装饰器仅仅用来“装饰”函数的包装,返回一个修改后的函数对象,将其重新赋值原来的标识符,并永久失去对原始函数对象的访问。

      装饰器的语法以@开头,接着是装饰器函数的名字和可选的参数。紧跟着装饰器声明的是被修饰的函数和装饰函数的可选参数。如下:

      @decorator(dec_opt_args)

      def func2bdecorated(func_opt_args):

             :

示例:

#!usr/bin/env python

from time import ctime,sleep

def tsfunc(func):
    def wrappedFunc():
        print '[%s] %s() called' % (ctime(),func.__name__)   # 时间戳调用
        return func()   #目标函数调用
    return wrappedFunc

@tsfunc
def foo():
    pass

foo()
sleep(4)

for i in range(2):
    sleep(1)
    foo()

输出:

[Sat Jan 26 20:39:47 2013] foo() called
[Sat Jan 26 20:39:52 2013] foo() called
[Sat Jan 26 20:39:53 2013] foo() called

传递函数——与JS类似,python中的函数 也可以作为参数传递,并在函数体内调用这些函数。   

#!/usr/bin/env python
# 传递和调用函数

def convert(func,seq):
    'conv.sequence of nubers to same type'
    return [func(eachNum) for eachNum in seq]
myseq = (123,45.67,-6.2e8,9999999L)
print convert(int,myseq)   # 传递int函数
print convert(long,myseq)  # 传递long函数
print convert(float,myseq) # 传递float函数

输出为:

[123, 45, -620000000, 9999999]
[123L, 45L, -620000000L, 9999999L]
[123.0, 45.67, -620000000.0, 9999999.0]

函数的默认参数:python中用默认值声明变量的语法是所有的位置参数必须出现在任何一个默认参数之前。

     def func(posargs,defarg1=dva11,defarg2=dva2,...):

           pass

抓取web页面示例代码: 

#!/usr/bin/env python

from urllib import urlretrieve

def firstNonBlank(lines):
    for eachLine in lines:
        if not eachLine.strip():
            continue
        else:
            return eachLine

def firstLast(webpage):
    f = open(webpage)
    lines = f.readlines()
    f.close()
    print firstNonBlank(lines),   # 输出文件非空白的第一行
    print '\n-----------------\n'
    lines.reverse()               # 翻转lines
    print firstNonBlank(lines),   # 输出第一行也就是倒数一行

def download(url = 'http://www.baidu.com',process = firstLast):
    try:
        retval = urlretrieve(url)[0]     # 下载代码到文件 'c:\\users\\admini~1\\appdata\\local\\temp\\tmp7msit8'
    except IOError:
        retval = None
    if retval:
        process(retval)

if __name__ == '__main__':
    download()

 返回值:

<!doctype html><html><head><meta http-equiv="Content-Type" content="text/html;charset=gb2312"><title>百度一下,你就知道      </title><style>html,body{height:100%;}html{overflow-y:auto}#wrapper{position:relative;_position:;min-height:100%}#content{padding-bottom:100px;text-align:center;}#ftCon{height:100px;position:absolute;bottom:44px;text-align:center;width:100%;margin:0 auto;z-index:0;overflow:hidden;}#ftConw{width:720px;margin:0 auto;}body{font:12px arial;text-align:;background:#fff}body,p,form,ul,li{margin:0;padding:0;list-style:none}body,form,#fm{position:relative}td{text-align:left}img{border:0}a{color:#00c}a:active{color:#f60}#u{color:#999;padding:4px 10px 5px 0;text-align:right}#u a{margin:0 5px}#u .reg{margin:0}#m{width:720px;margin:0 auto;}#nv a,#nv b,.btn,#lk{font-size:14px}#fm{padding-left:110px;text-align:left;z-index:1;}input{border:0;padding:0}#nv{height:19px;font-size:16px;margin:0 0 4px;text-align:left;text-indent:137px;}.s_ipt_wr{width:418px;height:30px;display:inline-block;margin-right:5px;background:url(http://s1.bdstatic.com/r/www/img/i-1.0.0.png) no-repeat -304px 0;border:1px solid #b6b6b6;border-color:#9a9a9a #cdcdcd #cdcdcd #9a9a9a;vertical-align:top}.s_ipt{width:405px;height:22px;font:16px/22px arial;margin:5px 0 0 7px;background:#fff;outline:none;-webkit-appearance:none}.s_btn{width:95px;height:32px;padding-top:2px\9;font-size:14px;background:#ddd url(http://s1.bdstatic.com/r/www/img/i-1.0.0.png);cursor:pointer}.s_btn_h{background-position:-100px 0}.s_btn_wr{width:97px;height:34px;display:inline-block;background:url(http://s1.bdstatic.com/r/www/img/i-1.0.0.png) no-repeat -202px 0;*position:relative;z-index:0;vertical-align:top}#lg img{vertical-align:top;margin-bottom:3px}#lk{margin:33px 0}#lk span{font:14px "宋体"}#lm{height:60px}#lh{margin:16px 0 5px;word-spacing:3px}.tools{position:absolute;top:-4px;*top:10px;right:7px;}#mHolder{width:62px;position:relative;z-index:296;display:none}#mCon{height:18px;line-height:18px;position:absolute;cursor:pointer;padding:0 18px 0 0;background:url(http://s1.bdstatic.com/r/www/img/bg-1.0.0.gif) no-repeat right -134px;background-position:right -136px\9}#mCon span{color:#00c;cursor:default;display:block}#mCon .hw{text-decoration:underline;cursor:pointer}#mMenu a{width:100%;height:100%;display:block;line-height:22px;text-indent:6px;text-decoration:none;filter:none\9}#mMenu,#user ul{box-shadow:1px 1px 2px #ccc;-moz-box-shadow:1px 1px 2px #ccc;-webkit-box-shadow:1px 1px 2px #ccc;filter: progid:DXImageTransform.Microsoft.Shadow(Strength=2, Direction=135, Color="#cccccc")\9;}#mMenu{width:56px;border:1px solid #9b9b9b;list-style:none;position:absolute;right:27px;top:28px;display:none;background:#fff}#mMenu a:hover{background:#ebebeb}#mMenu .ln{height:1px;background:#ebebeb;overflow:hidden;font-size:1px;line-height:1px;margin-top:-1px}#cp,#cp a{color:#666666;}#seth{display:none;behavior:url(#default#homepage)}#setf{display:none;}#sekj{margin-left:14px;}</style>

-----------------

<!--708867ba7d22710c-->

可变长度的参数:

      非关键字可变长度参数(元组)—— 可变产长度参数元组必须在位置和默认参数之后,带元组的函数普遍语法如下:

      def function_name([formal_args,] *vargs_tuple):

            "function_doc"

            function_body_suite

 星号操作符之后的形参将作为元组传递给函数,元组保存了所有传递给函数的额外的参数(匹配了所有位置和具名参数后剩余的)。

 如果没有给出额外的参数,元组为空。示例:

>>> def tupleVarARGS(arg1,arg2='defaultB',*theRest):
    'display regular args and non-keyword variable args'
    print 'rotmal arg1:',arg1
    print 'formal arg 2:',arg2
    for eachXtrArg in theRest:
        print 'another arg:',eachXtrArg

        
>>> tupleVarARGS('ABC')
rotmal arg1: ABC
formal arg 2: defaultB
>>> tupleVarARGS('ABC','EFG')
rotmal arg1: ABC
formal arg 2: EFG
>>> tupleVarARGS('ABC','EFG',123,456,78,88)
rotmal arg1: ABC
formal arg 2: EFG
another arg: 123
another arg: 456
another arg: 78
another arg: 88
>>> 

 关键字变量参数(字典)语法如下:

      def function_name ([formal_args,][*vargst,] **vargsd):

           function_doc

           functnion_body_suite

关键字变量参数应该为函数定义的最后一个参数,带**,示例:        

def dictVarArgs(arg1,arg2='defaultB',**theRest):
    'display w regular args and keyword variable args'
    print 'formal arg1:',arg1
    print 'formal arg2:',arg2
    for eachXtrArg in theRest.keys():
        print 'xtra arg %s:%s' % \
              (eachXtrArg,str(theRest[eachXtrArg]))

输出:

>>> dictVarArgs(1220,740.0,c='grail')
formal arg1: 1220
formal arg2: 740.0
xtra arg c:grail
>>> dictVarArgs(arg2='vvg',c=123,d='vvg2',arg1='asdfasd')
formal arg1: asdfasd
formal arg2: vvg
xtra arg c:123
xtra arg d:vvg2
>>> dictVarArgs('one',d=10,e='zoo',men = ('freud','gaudi'))
formal arg1: one
formal arg2: defaultB
xtra arg men:('freud', 'gaudi')
xtra arg e:zoo
xtra arg d:10

关键字和非关键字可变长参数都有可能在同一函数中,只要关键字字典是最后一个参数并且非关键字元组先与它之前出现.

def newfoo(arg1,arg2,*nkw,**kw):
    'doc'
    print 'arg1 is:',arg1
    print 'arg2 is:',arg2
    for eachNKW in nkw:
        print 'non-keword arg:',eachNKW
    for eachKW in kw.keys():
        print 'kew word arg "%s": %s' % \
              (eachKW,kw[eachKW])
输出:
>>> newfoo('wolf',3,'projiects',freud=90,gamble=96)
arg1 is: wolf
arg2 is: 3
non-keword arg: projiects
kew word arg "gamble": 96
kew word arg "freud": 90

函数式编程举例:      

#!usr/bin/env python

def testit(func,*nkwargs,**kwargs):
    try:
        retval = func(*nkwargs,**kwargs)
        result = (True,retval)
    except Exception,diag:
        result = (False,str(diag))
    return result

def test():
    funcs = (int,long,float)
    vals = (123,12.34,'1234','12.34')

    for eachFunc in funcs:
        print '_'*20
        for eachVal in vals:
            retval = testit(eachFunc,eachVal)
            if retval[0]:
                print '%s(%s) = ' %\
                      (eachFunc.__name__,eachVal),retval[1]
            else:
                print '%s(%s) = FAILED:'%\
                      (eachFunc.__name__,eachVal),retval[1]
if __name__ =='__main__':
    test()
输出:
____________________
int(123) =  123
int(12.34) =  12
int(1234) =  1234
int(12.34) = FAILED: invalid literal for int() with base 10: '12.34'
____________________
long(123) =  123
long(12.34) =  12
long(1234) =  1234
long(12.34) = FAILED: invalid literal for long() with base 10: '12.34'
____________________
float(123) =  123.0
float(12.34) =  12.34
float(1234) =  1234.0
float(12.34) =  12.34

 函数式编程:

         匿名函数与lambda----------------------与javascript中的匿名函数类似

         lambda [arg1[, arg2, ... argN]]: exprission

         python 允许用lambda关键字创建匿名函数。一个完整的lambda“语句”代表了以个表达式,这个表达式的定义体必须和声明放在同一行。

         def add(x,y):return x + y   <==> lambda x, y: x + y

         def usuallyAdd2(x,y=2):return x + y  <==>  lambda x,y=2 : x + y

         def showAllAsTuple(*z):return z        <==>  lambda *z : z

         内建函数apply(),filter(),map(),reduce()

         ----------------------------------------------------------------------------------------------

          内建函数                                                   描述

        apply(func[,nkw][,kw])                                用可选的参数来调用func,nkw为非关键字参数,kw为关键字参数;返回值是函数调用的返回值

        filter(func,seq)                                           调用一个布尔函数func来遍历迭代每一个seq中的元素;返回一个是fanc返回值为ture的元素的序列

        map(func,seq1[,seq2...])                            将函数func作用于给定序列s的每个元素,并用以个列表来提供返回值;如果fanc为None,func表现为一个身份函                                     数,返回一个含有每个序列中元素集合的N个原始的列表

        reduce(func,seq[,init])                                将二元函数作用与seq序列的元素,每次携带一堆,连续地将现有的结果和下一个值作用在获得的随后的结果上,最后减少我们的序列为一个单一的返回值;如果初始值init给定,第一个比较会是init和第一个序列元素而不是序列的头两个元素。

 

        apply()-------已经被淘汰掉.....

        filter() -------为已知的序列的每个元素调用给定布尔函数。每个filter返回的非零(true)值元素添加到一个列表中,返回的对象是以个从原始队列中“过滤后”的队列。

示例:过滤掉偶数返回奇数列表: 

#!/usr/bin/env python

from random import randint

def odd(n):
    return n % 2

allNums = []
for eachNum in range(10):  # 只是为了循环10次
    allNums.append(randint(1,99))   # 每次添加一位随机数
    
print filter(odd,allNums) # 过滤

     上面示例中的add()函数可以用一个lambda表达式替换:

from random import randint
allNums = []
for eachNum in range(10):
    allNums.append(randint(1,99))
print filter(lambda n: n%2,allNums)

    也可以用列表解析代替如下: 

from random import randint as ri
print[n for n in [ri(1,99) for i in range(9)] if n%2]

     map()  --  将函数调用“映射”到每个序列的元素上,并返回含有所有返回值的列表。   

map(lambda x : x+2,[0,1,2,3,4,5,6])    #[2, 3, 4, 5, 6, 7, 8]
map(lambda x : x**2,range(6))          #[0, 1, 4, 9, 16, 25]
[x+2 for x in range(6)]                #[2, 3, 4, 5, 6, 7]
[x**2 for x in range(6)]               #[0, 1, 4, 9, 16, 25]

 map() 使用带多个序列的示例:

map(lambda x,y:x+y,[1,3,5],[2,4,6])         #[3, 7, 11]
map(lambda x,y:(x+y,x-y),[1,3,5],[2,4,6])   #[(3, -1), (7, -1), (11, -1)]
map(None,[1,3,5],[2,4,6])                   #[(1, 2), (3, 4), (5, 6)]   同zip()函数

     reduce()  ----  使用一个二元函数(接受两个参数,返回一个值),一个序列,一个可选的初始化器。将那个列表的内容“减少”为以个单一的值。(它通过取出序列的头两个元素,将他们传入二元行数来获得一个单一的值来实现。然后又用这个值和序列的下一个元素来获得又一个值,然后继续,知道整个序列的内容都遍历完毕以及最后的值会被计算出来为止).......

     reduce(func,[1,2,3]) == func(func(1,3), 3)    #  如果给定了初始化器,则一开始的迭代会用初始化器和易个序列的元素来进行。

     如果用程序来模拟reduce,实际就是这样:

def mySum(x,y):return x + y
allNums = range(5) #[0,1,2,3,4]
total = 0

for eachNum in allNums:
    total = mySum(total,eachNum)

print 'the total is:',total    #the total is: 10

使用lambda 和 reduce(),如下:

print 'the total is:',reduce((lambda x,y:x+y),range(5))

偏函数应用:   ------ 通过functional模块中partial()函数来创建PFA(偏函数).  

from operator import add,mul
from functools import partial

add1 = partial(add,1)     # add1(x) ==  add(1,x)
mul100 = partial(mul,100) # mul100(x) == mul(100,x)

print add1(10)     #11
print mul100(10)   #100

 变量的作用域:

       global语句:为了明确地引用一个已命名的全局变量,必须使用global语句,语法如下:

        flobal var1[, var2 [, ....varN]]       

def foo():
        global is_this_global
    this_is_local = 'abc'
    is_this_global = 'def'
    print this_is_local + is_this_global
    
 foo()    # abcdef
print is_this_global #def

闭包:-----与javascript中的闭包相似

       简单示例:

def counter(start_at = 0):
    count = [start_at]
    def incr():
        count[0] += 1
        return count[0]
    return incr

count = counter(5)

print count()  #6
print count()  #7
print count()  #8
print count()  #9

变量作用域和名称空间

#!/usr/bin/env python
j,k=1,2
def proc1():
    j,k = 3,4
    print "j==%d and k == %d" % (j,k)
    k = 5

def proc2():
    j = 6
    proc1()   #3,4 
    print "j==%d and k == %d" % (j,k)

k = 7
proc1()   # 3,4
print "j==%d and k == %d" % (j,k)  #1,7

j = 8
proc2()   #6,7
print "j==%d and k == %d" % (j,k)  #8,7
输出:
j==3 and k == 4
j==1 and k == 7
j==3 and k == 4
j==6 and k == 7
j==8 and k == 7

递归:函数包含了对其自身的调用,该函数就是递归的。 

def factorial(n):
    if n==0 or n==1:    # 0! =1! =1
        return 1
    else:
        return (n*factorial(n-1))

>>> factorial(10)     #3628800

生成器: 从语法上讲,生成器是一个带yield语句的函数。?