初设大蟒蛇之Python函数篇

初设大蟒蛇之Python函数篇

 

1、内嵌函数:

内嵌函数,顾名思义,就是在一个已经定义的函数内部再定义一个函数,如下简单的内嵌函数:

#!/usr/bin/env python

 

def func_out():            ###外部函数

print "This is func_out"

def func_in(): ###内部函数

print "This is func_in"

return func_in() ###注意,此处返回内部函数值

print func_out()

 

输出结果:

[student@localhost day3]$ python 1.py

This is func_out ###外部函数输出

This is func_in ###内部函数输出

None                   ###由于此时调用的返回值为内部函数的返回值,但内部函 数无返回值,所以输出为None

 

对于内嵌函数,它的作用域仅限于外部函数,在全局中除了外部函数,其他地方都不能调用该内嵌函数,否则会发生异常,如下例:

 

#!/usr/bin/env python

 

def func_out():

print "This is func_out"

def func_in():

print "This is func_in"

return func_in          ###注意,此处返回一个函数对象,也就是内部函数 func_in的函数体

print func_out()

 

输出结果:

[student@localhost day3]$ python 1.py    

This is func_out

<function func_in at 0x7f1306295a28>    ###注意此输出,由于在整段程序中没有调用内部函数,所以没有内部函数的输出结果,但是有返回值,返回值为一个函数对象,也就是内部函数的地址。

 

对于内嵌函数,在实际当中使用还是较为常见,上面的例子只是一个简单的内嵌函数结构,并没有对其进行传参,如果对内嵌函数进行传参,则会用到python中自带的一类函数--装饰器

 

2、函数装饰器

2.1对于函数装饰器,先分别观察下面两段程序的不同,下面的两个函数用来统计函数的运行时间,我们用sleep函数来模仿程序运行时间:

一:正常对函数进行调用  

  1 #!/usr/bin/env python

  2

  3 import time ###加入时间函数模块

  4 import datetime

  5

  6 def func_test(func):

  7 #    print "This is func_test"

  8     def func_time(*arg,**kwargs):

  9         print '[%s]' % time.ctime()     ###输出当前时间

 10         start_time = datetime.datetime.now() ###对调用函数前对时间进行统计

 11         func(*arg,**kwargs) ###调用函数

 12         end_time = datetime.datetime.now() ###对调用完函数进行时间统计

 13         cost_time = end_time - start_time ###计算函数运行时间

 14         print '[%s]' % time.ctime() ###输出当前时间

 15         print 'running [%d] mins' % cost_time.total_seconds()    ###将运行时间用秒输

 16     return func_time

 17

 18

 19 def func_test_1():                   ###测试函数

 20     time.sleep(3)  ###暂停3

 21

 22 f=func_test(func_test_1)  ###对函数进行调用

 23 f()

输出结果:

[student@localhost day3]$ python 3.py

[Mon Jun 20 21:25:40 2016]

[Mon Jun 20 21:25:43 2016]

This function running [3] mins

 

二:  利用装饰器对函数进行调用

  1 #!/usr/bin/env python

  2

  3 import time

  4 import datetime

  5

  6 def func_test(func):

  7 #   print "This is func_test"

  8     def func_time(*arg,**kwargs):

  9         print '[%s]' % time.ctime()

 10         start_time = datetime.datetime.now()

 11         func(*arg,**kwargs)

 12         end_time = datetime.datetime.now()

 13         cost_time = end_time - start_time

 14         print '[%s]' % time.ctime()

 15         print 'This function running [%d] mins' % cost_time.total_seconds()

 16     return func_time

 17

 18 @func_test ###装饰器调用

 19 def func_test_1():

 20     time.sleep(3)

 21

 22 func_test_1()

运行结果:

[student@localhost day3]$ python 3.py

[Mon Jun 20 21:33:20 2016]

[Mon Jun 20 21:33:23 2016]

This function running [3] mins

 

对于上面的两个例子,我们可以看出使用装饰器i对函数进行调用和正常调用,产生的结果是相同的,而在第二个例子中,@func_test 作为装饰器函数,该装饰器的作用相当于:func_test_1=func_test(func_test_1),但是,注意在使用装饰器函数时,所需要装饰的函数必须要紧跟在该函数后,在上面的举例中,也就是func_test_1()这个需要装饰的函数必须紧跟在@func_test后,如果中间插入其他代码,则有可能会出现异常报错,例如:

 18 @func_test

 19 print 'hello '

 20 def func_test_1():

 21     time.sleep(3)

2.1 我们在上面的函数中,装饰函数中插入一条无关语句,则会产生下面的结果:

[student@localhost day3]$ python 3.py

  File "3.py", line 19

    print 'hello '

        ^

SyntaxError: invalid syntax

产生该异常,因为装饰器无法读取装饰函数,才会提示如下错误。

2.2 此外,装饰器也可以像函数一样堆叠起来,如下举例:

@func_test_2

@func_test_1

def func(arg1,arg2,...):

pass

 

重叠装饰器相当于:

def func(arg1,arg2,...):

pass

func = func_test_2(func_test_1(func))

还有,装饰器也可以带有参数,例如:

@func_test_2(arg)

@func_test_1

def func():

pass

等价于:func = func_test_2(arg) (func_test_1(func))

 

对于上面的例子,我们大概可以理解装饰器的作用,装饰器实际上也就是一类函数,他们可以接受函数对象,简化我们对内嵌函数的调用,我们可以用装饰器来进行:引入日志、增加计时逻辑来检测性能、给函数加入事务的能力。

 

2.3 对于装饰器来讲,当函数使用装饰器时,原函数的元数据便会变成装饰器内部函数的元数据,请看下面的例子:

 18 @func_test

 19 def func_test_1():

 20     time.sleep(3)

 21

 22 func_test_1()

 23 print func_test_1.__name__      ###我们在上面的函数中加入这句程序,将func_test_1函数的函数名进行输出,检测这个函数在利用装饰器进行调用后函数名(元数据)是否发生变化。

输出结果:

 


在输出结果中我们可以看到,原函数的元数据已经被装饰器函数更改。如果我们在使用装饰器函数时不需要更改元数据时,我们需要加入另一个模块functools,具体如下:

 

如上图,我们加入functools模块,并且在装饰器中加入第9行代码,将传入的函数元数据进行保存,而不进行修改,输出结果:

 

在上面的输出中,我们可以看到输出的函数名还是原来的函数名,元数据并没有进行更改。但是,这种方法相当于更改了内嵌函数的元数据,我们再对源程序进行修改,如下:

 

我们在内嵌函数后面加入输出内嵌函数元数据代码,第18行,输出结果如下:

 

在上面输出的结果中,我们可以看到内嵌函数的元数据(函数名)被更改。

 

 

3、匿名函数lambda

3.1 python中,我们可以使用一个匿名函数来对函数进行定义:

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

 

在上图中,我们简单的使用了lambda进行函数定义,但是,由于lambda创建了一个函数对象,自身并不进行保存,所以会直接返回一个函数对象,这样我们需要对lambda返回对象进行保存,如上图中,用result进行保存函数对象,由于lambda创建函数中创建了两个参数,并且返回了x+y这个表达时的值,所以我们载调用时需要进行传参。

 

同样,lambda函数也可以进行位置传参,也可以覆盖参数。

 

 3.2 lambda的作用域

如同普通函数一样,lambda函数也同样遵循固定的作用域范围

 


 

对于作用域的范围,在上面两幅图中,我们可以看到,lambda函数的使用作用域和普通函数相同。

 

4、生成器

4.1 python中,生成器的作用类似于迭代器,不过生成器使用另一种方式来运作,当到达一个真正的返回或者函数结束没有更多的返回值时,就会退出(当调用next(),出现StopIteration异常时,就会退出)。生成器在python中可以当作无限迭代来使用,我们来看个例子:

 

 

在下图中,我们定义一个生成器,打印10以内的奇数:

 

在上面的例子中,利用for循环,相当于进行了多次next()操作。

生成器中,我们不仅可以使用next()将生成器返回值进行输出,也可以对生成器进行send()传入数据,在使用send()传入参数时,默认将传入的参数进行next()操作,如下举例:

 

在上图中的例子中,我们对生成器传入参数,如果传入字符为’q’,则退出。注意,在上面的程序中,recv = yield value 这句代码相当于,先对value进行一次中断,然后等待外界的参数传入,并且对recv进行赋值,在这里,由于由于第一次运行时没有对外界请求传入参数,所以我们在第一次send传参时需要传入一个空值,否则会有异常。而当最后一次传入参数为’q’时,由于生成器在请求完,默认进行next()输出时,函数已经退出,所以,无法正常输出,所以在上面的例子中,输出结果会报出异常。

 

我们来做一个简单的对话生成器:

  1 #!/usr/bin/env python

  2

  3 def gen():

  4     value = 0

  5     while True:

  6         recv = yield value

  7         if recv == 'hello':

  8             value = 'hello~~~~'

  9         elif recv == 'age':

 10             value = '18'

 11         else:

 12             value = 'what do say?'

 13         recv = value

 14

 15 g=gen()

 16 g.send(None)

 17 while True:

 18     text=raw_input("please input: ")

 19     if text == 'bye':

 20         print "bye~~~"

 21         break

 22     print g.send(text)

 

输出结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值