Python基础-函数[2]

来源:互联网 发布:广东粤数大数据忽悠 编辑:程序博客网 时间:2024/06/10 06:51

函数嵌套

在一个函数定义中再定义一个函数 def outfunc(): def infunc(): expression
返回一个函数:
格式:

1234
def outfunc():    def infunc():        expression    return infunc

eg:

1234567891011121314151617
#!/usr/bin/env  python# coding=utf-8def outfunc():    print 'this is calling outfunc.....'    def infunc():        print 'this is calling infunc....'    return infuncf = outfunc()    #这里返回infunc函数f()=========结果==========root@tonglele /code/Python/function/test # python code1.pythis is calling outfunc.....this is calling infunc....

此时我们举一个例子:例如,我们现在想测试一个函数的运行时间,但又不破坏这个函数,不给这个函数增加代码,我们该怎样做?

12345678910111213141516171819202122232425262728
 #!/usr/bin/env  python# coding=utf-8import timeimport datetimedef func(arg):    time.sleep(arg)def timeIt(func):    def warp(arg):        start = datetime.datetime.now()        func(arg)        end = datetime.datetime.now()        cost = end - start        print "execute %s spend %s" % (func.__name__,cost.total_seconds())    return warpnew_func = timeIt(func)    #此时timeIt返回一个新的函数warpnew_func(3)    #调用新的函数,并传值进去=========运行结果===========root@tonglele /code/Python/function/test # python code2.pyexecute func spend 3.003061

这样我们便使用了一种非入侵的方式包装了这个函数,并且增加了我们需要的功能,这就是Python中的装饰器。

装饰器

12345678910111213141516171819202122232425262728
#!/usr/bin/env  python# coding=utf-8import timeimport datetimedef timeIt(func):    def warp(arg):        start = datetime.datetime.now()        func(arg)        end = datetime.datetime.now()        cost = end - start        print "execute %s spend %s" % (func.__name__,cost.total_seconds())    return warp@timeIt   #此时,func函数被timeIt装饰器包装def func(arg):    print func.__name__    time.sleep(arg)func(3)============运行结果=========root@tonglele /code/Python/function/test # python code2.pywarp        #此时func.__name__返回的名字不再是‘func’了,而是被装饰器改变成了warp。如果想要保留原来的__name__,__doc__等元信息,需要做如下修改。execute func spend 3.003148
1234567891011121314151617181920212223242526
#!/usr/bin/env  python# coding=utf-8import timeimport datetimeimport functoolsdef timeIt(func):    @functools.wraps(func)    #增加这一行,将原函数作为值传进去,表示将原函数的__name__,__moudle__,__doc__等信息更新到装饰器里    def warp(arg):        start = datetime.datetime.now()        func(arg)        end = datetime.datetime.now()        cost = end - start        print "execute %s spend %s" % (func.__name__,cost.total_seconds())    return warp@timeItdef func(arg):    print func.__name__    time.sleep(arg)func(3)

lambda匿名函数

Python使用lambda关键字创造匿名函数。匿名,即不再用def语句这样的标准形式定义一个函数。
这种语句的目的是由于性能原因,在调用时绕过函数的栈分配
语法为:lambda [arg1[,arg2,...argN]]:expression其中,参数是可选的,如果使用参数的话,参数通常也会在表达式中出现

lambda语句的使用方法(无参数)

12345
>>> lambda:1<function <lambda> at 0x7f02d5f3f398>>>> f = lambda:1    #lambda会返回一个函数,将该函数赋值给变量f>>> f()1

lambda语句的使用方法(有参数)

12345678910111213
>>> f = lambda x,y:x+y>>> f(2,3)5>>> f = lambda x,y = 10:x+y     #带默认值参数>>> f(2)12>>> f(19,20)39>>> f = lambda *x:map(lambda x:x + 10,x)  #可变位置参数>>> f(1,2,3,4)[11, 12, 13, 14]>>> f(*[2,3,4,5,6])[12, 13, 14, 15, 16]

一个计算器的例子

123456789101112131415161718192021
 #!/usr/bin/env python# coding=utf-8func = {    "add":lambda x,y : x + y,    "sub":lambda x,y : x - y,    "mul":lambda x,y : x * y,    "div":lambda x,y : x / y}print func["add"](3,4)print func["sub"](3,4)print func["mul"](3,4)print func["div"](3,4)=============运行结果======root@tonglele /code/Python/function/test # python code3.py7-1120

generator生成器

与列表解析语法类似,只不过把列表解析的[]换成了()
生成器表达式能做的事,列表解析基本都能处理,只不过在需要处理的序列比较大时,列表解析比较费内存

简单的生成器表达示例:

12345678910111213141516171819
>>> gen = (x ** 2 for x in range(5))>>> gen<generator object <genexpr> at 0x7fc2e26b3690>>>> >>> gen.next()0>>> gen.next()1>>> gen.next()4>>> gen.next()9>>> gen.next()16>>> gen.next()Traceback (most recent call last):  File "<stdin>", line 1, in <module>  StopIteration>>>

生成器表达式并不能实现较为复杂的功能,所以我们一般都使用生成器函数

生成器函数

在函数中如果出现了yield关键字,那么该函数就不再是普通函数,而是生成器函数
生成器函数可以生成一个无限的序列,列表解析是无法这么做的
yield的作用就是把一个函数变成一个generator,带有yield的函数不再是一个普通函数,Python解释器会将其视为一个
generator。
eg1:简单使用生成器函数 :

12345678910111213141516171819202122232425262728
 #!/usr/bin/env python# coding=utf-8def odd():    n = 1    while True:        yield n        n += 2od = odd()count = 0for i in od:    if count > 5:        break    print i    count += 1=========运算结果=======root@tonglele /code/Python/function/test # python code4.py 1357911

在for 循环执行的时候,每次都会执行odd 函数内的代码。
执行到yield n 时,将n 的值返回出去,此时函数内的代码不再往下执行, 挂起状态,但会保存函内变量的相关信息
下次迭代的时,从yield n 的下一条语句,n += 2 开始执行,
这个时候n 的值是之前保留的值,函数体内的while 循环继续执行,当再次执行到yield n 的时候,将n 返回出去,此时的n 是已经计算过n+=2 了
看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。

yeild与return

在一个生成器中,如果没有return,则默认执行到函数结束时返回stopiteration;

12345678910
>>> def gen():    #定义一个生成器...     yield 1... >>> g = gen()>>> next(g)   #第一次使用next(g)时,会在执行完yield语句后挂起,此时程序并没有执行结束1>>> next(g)   #此时,程序从yield语句的下一条语句开始执行,发现已经到了结尾,所以抛出StopIteration异常。Traceback (most recent call last):  File "<stdin>", line 1, in <module>StopIteration

如果在执行的过程中遇到了return,则直接抛出StopIteration终止迭代

12345678910111213141516171819202122232425262728293031
>>> def gen():...     count = 0...     while count < 3:...             yield count...             count += 1...             return... >>> g = gen()>>> next(g)        #第一次执行next时,程序停留在执行完yield count之后的位置0>>> next(g)    #当这次执行时,先执行count += 1,再向下执行时,遇到了return,所以抛出StopIteration 异常,退出Traceback (most recent call last):  File "<stdin>", line 1, in <module>StopIteration>>> def gen():...     count = 0...     while count < 3:...             yield count...             count += 1... >>> g = gen()>>> next(g)0>>> next(g)1>>> next(g)2>>> next(g)Traceback (most recent call last):  File "<stdin>", line 1, in <module>StopIteration

close()

手动关闭生成器函数,后面的调用会直接返回StopIteration 异常。

1234567891011121314
 >>> def gen():...     count = 0...     while count < 3:...             yield count...             count += 1... >>> g = gen()>>> next(g)0>>> g.close()>>> next(g)Traceback (most recent call last):  File "<stdin>", line 1, in <module>StopIteration

send()

生成器函数最大的特点就是可以接受外部传入的一个变量,并根据变量内容计算结果后返回。这是生成器函数最难理解也是最重要的地方。后面的协程部分会经常用到

123456789101112131415161718192021222324252627282930313233343536
 #!/usr/bin/env python#coding=utf-8def gen():    value = 0    while True:        receive = yield value        if receive == 'e':            break        value = 'got : %s' % receiveg = gen()print g.send(None)print g.send('hello')print g.send(8989)print g.send('e')print g.send('world')===========运行结果===========root@tonglele /code/Python/function/test # python code6.py0got : hellogot : 8989Traceback (most recent call last):  File "code6.py", line 16, in <module>    print g.send('e')StopIteration###执行流程:1. 通过g.send(None)或者next(g)可以启动生成器函数,并执行到第一个yield语句结束的位置。此时,执行完了yield语句,但是没有给receive赋值。yieldvalue会输出初始值0注意:在启动生成器函数时只能send(None),如果试图输入其它的值都会得到错误提示信息。2. 通过g.send(‘hello’),会传入hello,并赋值给receive,然后计算出value的值,并回到while头部,执行yield value语句有停止。此时yield value会输出”got:hello”,然后挂起。3. 通过g.send(8989),会重复第2步,最后输出结果为”got: 8989′′4. 当我们g.send(‘e’)时,程序会执行break然后推出循环,最后整个函数执行完毕,所以会得到StopIteration异常。

总结:

1、 按照鸭子模型理论,生成器就是一种迭代器,可以使用for进行迭代。
2、第一次执行next(generator)时,会执行完yield语句后程序进行挂起,所有的参数和状态会进行保存。再一次执行next(generator)时,会从挂起的状态开
始往后执行。在遇到程序的结尾或者遇到StopIteration时,循环结束。
3、 可以通过generator.send(arg)来传入参数,这是协程模型。
4、 next()等价于send(None)

感谢阅读,欢迎指正。

0 0