8 python高阶函数、返回函数、装饰器

  1 ################################################################################
  2 ##------------- 高阶函数  ----------------------------------------------------
  3 
  4 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。
  5 高阶函数:
  6     即是函数的形参,是用来接受函数的。这样的函数叫做高阶函数。
  7 
  8 >>> def now():
  9 ...     print('2015-3-25')
 10 ...
 11 >>> f = now
 12 >>> f()
 13 2015-3-25
 14 函数对象有一个__name__属性,可以拿到函数的名字:
 15 
 16 >>> now.__name__
 17 'now'
 18 >>> f.__name__
 19 'now'
 20 
 21 说明:
 22 既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
 23 
 24 例如:
 25 一个最简单的高阶函数:
 26 
 27 def add(x, y, f):
 28     return f(x) + f(y)
 29 
 30 
 31 ##--------------- 高阶函数之 map()和reduce()函数----------------------------------------------
 32 map说明:
 33     map()函数接收两个参数,一个是函数,一个是 Iterable
 34     map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
 35 
 36 例如:
 37 def f(x):
 38     return x * x
 39 
 40 r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
 41 print list(r)
 42 
 43 
 44 reduce说明:
 45         reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,
 46         reduce把结果继续和序列的下一个元素做累积计算,其效果就是。
 47 
 48 例如:
 49 from functools import reduce
 50 def add(x, y):
 51     return x + y
 52 
 53 print reduce(add, [1, 3, 5, 7, 9])
 54 
 55 
 56 ##---------------- 高阶函数之 sorted() 排序算法函数 ---------------------------------------------------、
 57 
 58 说明:
 59 但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。
 60 
 61 例如1:
 62     python内置的sorted()函数就可以对list进行排序:
 63 
 64 print sorted([36, 5, -12, 9, -21])
 65 结果:[-21, -12, 5, 9, 36]
 66 
 67 
 68 例如2:
 69     此外,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:
 70     key指定的函数将作用于list的每一个元素上,
 71     并根据key函数返回的结果进行排序。对比原始的list和经过key=abs处理过的list:
 72 
 73 print sorted([36, 5, -12, 9, -21], key=abs)
 74 结果:[5, 9, -12, -21, 36]
 75 
 76 
 77 ##---------------- 高阶函数之 filter() 函数----------------------------------------------------
 78 
 79 filter说明:
 80 filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
 81 
 82 例如:
 83 def is_odd(n):
 84     return n % 2 == 1
 85 
 86 print list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
 87 # 结果: [1, 5, 9, 15]
 88 
 89 
 90 ##-----------------返回函数 (函数作为返回值)------------------------------------------------
 91 
 92 返回函数说明:
 93     高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
 94 
 95 
 96 我们来实现一个可变参数的求和。通常情况下,求和的函数是这样定义的:
 97 
 98 def calc_sum(*args):
 99     ax = 0
100     for n in args:
101         ax = ax + n
102     return ax
103 
104 
105 但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数:
106 
107 def lazy_sum(*args):
108     def sum():
109         ax = 0
110         for n in args:
111             ax = ax + n
112         return ax
113     return sum
114 当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数:
115 
116  f = lazy_sum(1, 3, 5, 7, 9)
117  print f()                    --调用函数f时,才真正计算求和的结果:
118 
119 结果:25
120 
121 说明:
122     在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,
123     当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。
124 
125 ##------------- 装饰器函数(即形参是函数的返回函数)  ----------------------------------------------------
126 
127 装饰器的定义
128 本质是函数。(装饰其他函数) 它可以让其他函数在不需要做任何代码变动的前提下增加额外功能。
129 
130 装饰器的重要性
131 比如:已经上线的生产环境上有100个函数,需要增加新功能,新增功能不能修改源代码,也不能修改原函数的,这个时候就用到了装饰器。
132 
133 装饰器经常有切面需求的场景,
134     比如:插入日志,性能测试,事务处理,缓存,权限校验等场景。
135     装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。 
136     概括的讲,装饰的作用就是为已经存在的对象添加额外的功能。
137 
138 说明:
139 现在,假设我们要增强now()函数的功能,
140 比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,
141 这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
142 本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,
143 
144 装饰器函数:
145     其实本质就是一个返回函数,只不过是此返回函数本身又是高阶函数。
146     即 即是高阶函数(参数是函数)又是返回函数(返回值是函数)
147 
148 装饰器函数的原理:
149     就是利用返回函数的作用,将一个函数包在返回函数里面,
150     1,第一次调用返回函数,并且将需要被装饰的函数传参进去
151     2,第二次调用返回值,就是调用了内部函数,就是调用了被装饰过后的第一次传参进去的函数(在这次调用时可以加上其它功能的代码运行)
152     
153 ##装饰器的经典应用
154 import os
155 import sys
156 import re
157 import time
158 
159 # 这里的timer就是一个装饰器   ,
160 #func形参就是用来接受需要被装饰的函数,
161 #后面test1就是需要被装饰的函数,
162 #装饰的效果就是在被装饰的函数运行前后加上了start_time和end_time
163 def timer(func):
164     def deco(*args, **kwargs):
165         start_time = time.time()
166         func(*args, **kwargs)
167         end_time = time.time()
168         print("the func [%s] run time is %s" %(func.__name__,end_time-start_time))
169     return deco
170 
171 # 装饰器的调用,将函数返回值赋值给test1(注意:!! 装饰器,在装饰的时候就已经调用了第一次,即已经装饰好了,后面直接再第二次调用函数即可)
172 # test1 = timer(test1)
173 @timer  
174 def test1():
175     time.sleep(3)
176     print("in the test1")
177 
178 
179 ##test1函数调用(此时的test1已经不再是之前定义的,而是timer 装饰器返回的一个函数)
180 test1()
181 
182 ########################装饰器之wraps###################################################################
183 #coding=utf-8  
184 # -*- coding=utf-8 -*-   
185 from functools import wraps     
186 def my_decorator(func):  
187     #@wraps(func)  
188     def wrapper(*args, **kwargs):  
189         '''''decorator'''  
190         print('Calling decorated function...')  
191         return func(*args, **kwargs)  
192     return wrapper    
193  
194 @my_decorator   
195 def example():  
196     """Docstring"""   
197     print('Called example function')  
198 print(example.__name__, example.__doc__)
199 
200 例如:
201     以上代码,
202     没有@wraps(func)此句时:
203     >>('wrapper', 'decorator')
204     有@wraps(func)时:
205     >>('example', 'Docstring')
206 
207 说明:
208     __name__   属性是类或函数的名字属性
209     __doc__   属性,是类、函数、文件中特殊位置的字符串
210     1. 一个文件任何一条可执行的代码之前  #模块的__doc__
211 
212     2. 一个类,在类定义语句后,任何可执行代码前  #类的__doc__
213 
214     3. 一个函数,在函数定义语句后,任何可执行代码前  #函数的__doc__
215 
216 作用:
217 Python装饰器(decorator)在实现的时候,
218 被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),
219 为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。
220 写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring。
221 
222 
223 
224 ############### 基于python的-@property与@setter装饰器 ####################################
225 此装饰器所添加的功能:
226 property可以将方法转化成属性。
227 所以一般用于类中,写在类中方法上面,(即此装饰器装饰了这个方法,后面调用这个方法就可以用属性的方式来调用方法)
228 
229 class People(object):  
230     @property  
231     def getAge(self):  
232         return self.age  
233     @age.setter  
234     def setAge(self, age):  
235         if age<0:  
236             raise ValueError('age error!')  
237         else:  
238         self.age = age 
239 
240 在getter上加上property装饰器之后就可以直接以这种方式people.age获取age的值,settler的做法差不多只是装饰器的写法不一致而已将【变量名】
241 .setter写在setter上面即可完成,从此设置age不用使用setter那么麻烦了,可以直接使用people.age=60这样的写法啦

猜你喜欢

转载自www.cnblogs.com/2mei/p/9254089.html