码迷,mamicode.com
首页 > 编程语言 > 详细

Python入门(九) 函数-闭包

时间:2015-08-16 00:53:22      阅读:151      评论:0      收藏:0      [点我收藏+]

标签:

    在Python中,函数也是一种变量类型,也就是说可以用变量去保存一个函数。

def hello():
    print("hello")

print(type(hello))

>>> <class ‘function‘>

#将函数对象赋值为变量func,此时func指向了hello指向的函数对象
func = hello
func() #调用函数

>>> hello

    通过上面可以看出,我们可以把一个函数赋值为一个变量,那么此变量就指向该函数对象。当然,我们也是可以修改hello执行的函数对象的,如:

def say_hi():
    print("Hi")
    
hello = say_hi
hello()

>>> Hi

    把say_hi函数对象赋值为hello,那么hello就指向了say_hi函数对象,不再指向原先的函数对象了,也就无法再调用原先的函数对象。

    基于函数的上述特性,我们可以很容易的实现一个函数功能表,比如我们常见的http的服务队请求的处理,会根据请求的方法分别处理:

def handle_http_get():
    print(‘handle http get request‘)

def handle_http_post():
    print(‘handle http post request‘)

def handle_http_put():
    print(‘handle http put request‘)

http_handler = {‘get‘: handle_http_get, ‘post‘: handle_http_post, ‘put‘: handle_http_put}

#上面分别实现了处理http的get,post,put请求

#当请求的方法为get时,我们可以这么处理:
method = ‘get‘
http_handler[method]()

>>> handle http get request

    2.闭包Closure

    既然函数是对象,那么就可以在函数中返回一个函数对象:

def get_func():
    def func():
        print(‘inside func‘)

    return func

f = get_func() # 此时f指向了func函数对象
f() #执行func函数对象

>>> inside func

    一个函数与它的环境变量结合在一起,就构成Closure。

def power_factory(n):
    def power(list_arg):
        for i in range(len(list_arg)):
            list_arg[i] = list_arg[i]**n

    return power

#计算list中的每个数的平方
list1 = [1, 2, 3]
f1 = power_factory(2)
f1(list1)
print(list1)
f1(list1)
print(list1)

#计算List中每个数的立方
list1 = [1, 2, 3]
f2 = power_factory(3)
f2(list1)
print(list1)

>>> 
[1, 4, 9]
[1, 16, 81]
[1, 8, 27]

    对于power函数对象而言,power_factory函数传递的参数n就是其环境变量,会保存到函数对象的__closure__属性中。这样子每次调用f1函数,执行的都是2的平方操作,所以上面连续两次调用f1,输出的都是平方数。如果我们需要执行立方操作,只需要重新调用power_factory,生成一个环境变量n = 3的闭包。

    一般来说,像c编程中的函数,是没有状态的,除非在c函数中使用static变量来保存其状态,而使用闭包,我们可以很方便的做到函数都有其自己独立的环境变量。

    3. 装饰器

    函数对象有一个__name__属性,表示函数的名字:

print(max.__name__)
>>> max

    如我们前面已经实现了一个hello函数,现在我们想增强hello函数的功能,在执行hello函数前,加入打印调试信息。在不改变hello函数源码的前提下,可以通过闭包来完成。

def debug(func):
    def wrapper(*args, **kw):
        print(‘call %s‘ % func.__name__)
        return func(*args, **kw)

    return wrapper

hello = debug(hello)
hello()

>>> 
call hello
hello

    在上述的使用过程中,需要先执行hello = debug(hello), 感觉代码总是有点怪怪的,为此Python中引入@语法,简化使用的过程。

@debug
def hello():
    print(‘hello‘)
    
hello()
>>>
call hello
hello

    把@debug放在hello的前面,就相当于执行了hello = debug(hello)

    如果需要在debug中传递参数,则需要使用3层函数定义:

def debug(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print(‘%s: call %s‘ % (text, func.__name__))
            func(*args, **kw)
        return wrapper
    return decorator

@debug(‘debug_info‘)
def hello():
    print("hello")

hello()

>>>
debug_info: call hello
hello

    把@debug(‘debug_info‘)放在hello的前面,相当于执行了hello = debug(‘debug_info‘)(hello)

    

    总算写完了,困了,睡觉了。




Python入门(九) 函数-闭包

标签:

原文地址:http://my.oschina.net/kaedehao/blog/493043

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!