博客地址:http://www.cnblogs.com/yudanqu/python
概念:装饰器是一个闭包,把一个函数当作参数返回一个替代版的函数,本质上就是一个返回函数的函数闭包
装饰器就是在咱们须要的一个函数外面包装一个外壳,当咱们但愿这个函数更漂亮时,能够经过改变这个包装的样子便可,而不须要更改原函数,也能够避免出错。框架
def func2(func): def inner(): print('************') func() return inner def func1(): print("this is one") f = func2(func1) f()
下面我解释一下这个装饰器,能够看到,func1是咱们真正须要的函数,这时候咱们想在输出这个函数时再多添加一些功能,那么咱们就须要对func1这个函数进行装饰。func2是一个外部的输出函数,他的参数是func,这只是个形参,使用的时候将须要装饰的函数传入便可,当咱们执行func2这个函数的时候,其内部还有一个函数inner(),可是里面inner只是建立了这个函数而没有被调用(这个你们能理解吗,就是咱们在定义一个函数时,他不会自动被调用,咱们使用他时须要人为的经过这个函数来调用一下)内部读取代码仅读到def inner()这里并不进去,继续向下就到了return inner,这里返回了内部的那个函数名,但也只是个名字没有被调用(函数名后面加上小括号才能够调用)。那么return返回给谁呢,就给了下面的f,用f来接收func2的return值,如今f就是return的inner。进行最后一步,调用inner,上一步咱们已经知道f就是inner,调用他就加个小括号就能够了。调用了inner函数后,他的内部有func()这个函数,而且调用了,因此能够直接执行func内的语句块。func就是最外面传进来的参数,也就是咱们须要被装饰的函数。小伙伴们慢慢理一下思路,必定要把第一个理清楚了,那么后面就垂手可得了。函数
def func4(func): def inner(age): if age < 0: age = 0 func(age) return inner def func3(age): print("this is two %d" % age) f = func4(func3) f(-7)
看一下,这个框架和第一个几乎同样对吧,惟独多了一个参数,这个参数是最后由咱们装饰的那个函数来使用,由最外部传入。咱们把参数给在了inner函数,这是为何呢?咱们想一下,咱们装饰的函数是在何时调用的,是否是在调用了inner函数后,inner函数内自动调用的啊。那么在调用inner函数时才调用的目标函数,咱们不就应该把目标函数的参数从这里传进去吗(最外层的函数是个包装的做用,他是为了返回inner函数的地址,来为以后调用inner作准备),咱们在用f接收这个inner函数,咱们调用他还须要加个小括号f(),这才是调用inner,既然这里调用,正好有个传入参数的接口,咱们趁着这个机会把想要实现的func3函数的参数扔进去,岂不美哉,接下来咱们执行func3函数的时候,只须要把上面接收到的参数再传到本身的接口里就行了。this
@func4 def func3(age): print("this is two %d" % age) # 这时就能够直接使用原来的func3函数了,不须要引入变量来接收,就已经可使用装饰器里的内容 func3(-7)
@符号是装饰器的语法糖,在定义函数时,能够避免赋值操做spa
那么这段代码有什么做用呢?code
其实他能够替换掉上方代码的后四行,代码中最开始的装饰器是同样的,咱们改进在使用装饰器上。上面咱们经过先定义一个目标函数,而后把他做为参数传入装饰器里,而后用一个变量f来接收,最终调用f()来实现装饰做用,这样是否是繁琐了点呢,咱们作了这么多工做,并且可能会把咱们搞晕,其中还引入了变量,当代码很长时,那么多的变量咱们怎么记得住呢。这时就有了语法糖。大约在python2.4就开始可使用@符号了。也许你们见过,有时候会有@staticmethod,@classmethod的字眼,这就是python的内置装饰器。blog
@func4的做用就是替代了上方在装饰器里传参数而后赋值的过程,能够理解为经过这样一个符号,就已经把本身变成装饰了以后的样子,那么咱们再使用的时候,只须要和以往同样,调用函数,传参就能够了。固然是否是真正的变了,当下方再次使用这个函数时,若是不添加语法糖还会是函数本身。接口
但此时的装饰器只能接收一个参数,为整形,由于内部使用了判断,这样的话咱们不少事情就不是很方便了,使用装饰器就是方便咱们进行后续的操做,这样的话咱们使用不同的功能还得老是修改装饰器。那么,咱们继续向下看。字符串
def func5(func): def inner(*args,**kwargs): # 功能 print("&&&&&&") func(*args,**kwargs) return inner @func5 def func6(name,age,gender=1,number='00000000'): print('%s is %d years old,number is %s,gender:%d' % (name,age,number,gender)) func6('张三',18,0,'05162002') # 函数的参数理论上是无限制的,但实际上最好不要超过6到7个
这个其实没有太多要说的,只是把参数换成了不定长参数
*args:能够接受不限量个参数,将他们打包成tuple给函数
**kwargs:能够将关键字参数打包成字典给函数
有了上面两个,那么几乎全部的参数均可以随便输入了。
1 ''' 2 我理解为偏函数就是能够经过控制参数来实现功能 3 ''' 4 5 # 这样的一个功能,接下来实现它 6 print(int('1010', base = 2)) 7 # base = 2 意思是把字符串当作二进制来计算,就是把这个字符串以二进制来判断他是多少,以十进制输出 8 9 # 第一种方法 10 def int2(str, base = 2): # 表示设置默认值为2.未来用base值来转换 11 return int(str, base) 12 13 # 第二种方法(偏函数) 14 import functools # 这个模块帮咱们定义偏函数 15 int2 = functools.partial(int, base = 2)
1 ''' 2 断言 3 ''' 4 5 def func(num, div): 6 assert (div != 0), "div不能为0" # 断言 7 return num/div 8 9 func(10, 0) 10 # 函数自己分母不为零,若是为零那么将报错,使用断言,当没有错误时不产生效果,当有错误时会告诉你哪里错了
做者:渔单渠(yudanqu)