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这样的写法啦