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