标签:
在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)
总算写完了,困了,睡觉了。
标签:
原文地址:http://my.oschina.net/kaedehao/blog/493043