Noah的学习笔记之Python篇:html
1.装饰器编程
2.函数“可变长参数”app
3.命令行解析函数
注:本文全原创,做者:Noah Zhang (http://www.cnblogs.com/noahzn/)学习
年前工做事务比较繁琐,我只能用零碎的时间继续学习Python,决定开一个系列的博文,做为本身深刻学习Python的记录吧。名字也取好了,就叫《ZMAN的学习笔记之Python篇》~开篇是关于装饰器的,春节假期码的字哈哈~就让咱们开始吧!spa
本文的例子都是本身想的,若是不是很合适,请你们提出宝贵意见哈~谢谢啦!命令行
1、为何要用“装饰器”日志
好比咱们写了以下一段代码:code
# 打印0~99 def func(): for i in range(100): print(i)
咱们想要监测执行这个函数花费了多少时间,因而咱们将这个函数改为了这样:htm
import time # 打印0~99 def func(): start = time.time() for i in range(100): print(i) end = time.time() print("耗时:%.4f" % (end - start))
虽然达到了目的,可是咱们却改变了原有的函数,并且若是有几十个不一样的函数,都这样改动一下,工做量也是很是大的。
使用了“装饰器”后,就能在不修改原函数的前提下,达到相同的功能。
2、什么是“装饰器”
在Python中,函数是“对象”,而装饰器是函数,它的做用就是对已经存在的函数进行装饰。Python中的“装饰器”能够很好地解决那些有“面向切面编程”需求的问题。
请看例子:
def deco(ex): print('func函数被调用前') ex() print('func函数被调用后') return ex def func(): print('func函数被调用') func = deco(func) >>> func函数被调用前 func函数被调用 func函数被调用后
我写了两个函数,将函数func做为参数传入deco函数,并将返回值赋给func变量。咱们能够当作是func函数通过了deco的装饰~
而这就是装饰器的概念了:装饰器能够说是封装器,让咱们在被装饰的函数以前或以后执行一些代码,而没必要修改函数自己。利用这点,咱们能够作出许多酷炫的功能~
3、写第一个“装饰器”
刚才我介绍了装饰器的概念,但这是一个“手工”的装饰器,并无用到Python的装饰器语法,实际上,装饰器语法很是简单,看例子:
def deco(ex): def _deco(): print('func函数被调用前') ex() print('func函数被调用后') return _deco @deco def func(): print('func函数被调用') #return('OK') func() >>> func函数被调用前 func函数被调用 func函数被调用后
你们能够看到,我在定义函数func的上一行,加了一句“@deco”,这就是装饰器语法了,这样写了以后,能确保每次调用func函数都被deco函数装饰,是否是很是简单呀~~
4、让被装饰函数带上肯定的参数
若是被装饰函数带能够肯定的参数,须要像下面这样对装饰器函数进行修改:
def deco(ex): def _deco(a, b): print('%s函数被调用前' % ex.__name__) c = ex(a, b) print('%s函数被调用后,结果为:%s' % (ex.__name__, c)) return _deco @deco def func(a, b): print('func函数被调用,传入%s,%s' % (a, b)) return a+b func(1, 2) >>> func函数被调用前 func函数被调用,传入1,2 func函数被调用后,结果为:3
这个例子的装饰器实现了:打印传入函数的名字、打印两个数字相加结果的功能。咱们在原先的deco函数内又定义了一个函数_deco用来接收func函数中的参数。
5、让被装饰函数带上不肯定的参数
def deco(ex): def _deco(*args, **kwargs): print('%s函数被调用前' % ex.__name__) c = ex(*args, **kwargs) print('%s函数被调用后,结果为%s' % (ex.__name__, c)) return _deco @deco def func(a, b): print('func函数被调用,传入%s,%s' % (a, b)) return a+b @deco def func2(a, b, c): print('func2函数被调用,传入%s,%s,%s' % (a, b, c)) return a+b+c func(1, 2) func2(1, 2, 3) >>> func函数被调用前 func函数被调用,传入1,2 func函数被调用后,结果为3 func2函数被调用前 func2函数被调用,传入1,2,3 func2函数被调用后,结果为6
简单修改咱们的代码,使用*args, **kwargs来捕捉不定量的传参,便实现了多个参数的求和。
6、让装饰器带上参数
def deco(ex): def _deco(func): def _deco2(): print('%s函数被调用前,传入参数为:%s' % (func.__name__, ex)) func() print('%s函数被调用后' % func.__name__) return _deco2 return _deco @deco('parameter1') def func(): print('func函数被调用') func() >>> func函数被调用前,传入参数为:parameter1 func函数被调用 func函数被调用后
若是要让装饰器带上参数,咱们要在装饰器函数内部再多定义一层函数,用来接收装饰器的参数~你们可不要搞混了装饰器参数和函数的参数哟~
7、来个任性的:装饰器和被装饰函数都带参数
def deco(ex): def _deco(func): def _deco2(c, d): print('%s函数被调用前,装饰器参数为:%s' % (func.__name__, ex)) x = func(c, d) if x > 3: x = x-ex else: x = x+ex print('%s函数被调用后,计算结果为:%d\n' % (func.__name__, x)) return _deco2 return _deco @deco(3) def func(a, b): print('func函数执行结果为:%s' % int(a+b)) return(a+b) func(3, 4) func(1, 2) >>> func函数被调用前,装饰器参数为:3 func函数执行结果为:7 func函数被调用后,计算结果为:4 func函数被调用前,装饰器参数为:3 func函数执行结果为:3 func函数被调用后,计算结果为:6
最初的func函数只是实现两个数字的相加,通过装饰后实现了对func返回的和的大小进行了分支处理:若是“两数的和大于3”,最后结果为“两数的和减去3”,不然最后结果为“两数的和加上3”。我在这个例子中使用的是“肯定”的参数,你们能够本身更改哦~
8、同时使用多个装饰器
以前的例子都是只用了一个装饰器,咱们固然能够装饰屡次啦~
def deco1(ex): def _deco1(string): print('deco1被调用前') string = ex(string) if 'hello' in string: string = "You are my old friend." else: string = "You are my new friend." print('deco1被调用后,%s\n' % string) return string return _deco1 def deco2(ex): def _deco2(string): print('deco2被调用前') string = ex(string) if 'ZMAN' in string: string = 'hello, ' + string else: string = 'Is your name ' + string + '?' print('deco2被调用后,%s' % string) return string return _deco2 @deco1 @deco2 def func(string): print('func函数被调用') return string func('ZMAN') deco1(deco2(func('John'))) >>> deco1被调用前 deco2被调用前 func函数被调用 deco2被调用后,hello, ZMAN deco1被调用后,You are my old friend. deco1被调用前 deco2被调用前 func函数被调用 deco2被调用后,Is your name John? deco1被调用后,You are my new friend.
在这个例子中,咱们主要要关注装饰器调用的前后顺序,此时func('ZMAN')和deco1(deco2(func('ZMAN')))是等同的,这个调用顺序你们一看就明白了吧~
9、实际应用
最后来个实际应用~好吧,我实在是绞尽脑汁了,写代码的时候正好在吃苹果,那就来个跟水果有关的实例吧(别打我 - -!)
#综合运用:简单地检测函数传参是否合法 def deco(ex): def _deco(*args, **kwargs): print('***%s函数被调用前***' % ex.__name__) if args: if not isinstance(args[0], str): print('★店名参数错误:%s' % args[0]) if not(isinstance(args[1], int) and args[1]>0): print('★员工参数错误:%s' % args[1]) else: print('★未传入店名和员工数信息!') if kwargs: for i in kwargs: if not ((isinstance(kwargs[i], int) or isinstance(kwargs[i], float)) and kwargs[i]>0): print('★水果单价参数错误:%s:%r' % (i, kwargs[i])) else: print('★未传入水果单价信息!') a = ex(*args, **kwargs) print('***%s函数被调用后***\n' % ex.__name__) return _deco @deco # 假设传入几家水果店的名称、员工数以及水果单价。店名为字符,员工数为正整数,单价为正数 def func(*args, **kwargs): print('***函数func被调用***') brief = args detail = kwargs return(brief, detail) func('水果之家', -4, apple=3.5, strawberry=6, orange=3, cherry=8.5,) func(123, 8, apple=3, orange=2,) func('自然果园', 0.2, ) func() >>> ***func函数被调用前*** ★员工参数错误:-4 ***函数func被调用*** ***func函数被调用后*** ***func函数被调用前*** ★店名参数错误:123 ***函数func被调用*** ***func函数被调用后*** ***func函数被调用前*** ★员工参数错误:0.2 ★未传入水果单价信息! ***函数func被调用*** ***func函数被调用后*** ***func函数被调用前*** ★未传入店名和员工数信息! ★未传入水果单价信息! ***函数func被调用*** ***func函数被调用后***
代码有点长,可是只要你们耐心看,其实仍是挺简单的,没有什么花里胡哨的东西。这个装饰器用来检测传参是否合法~
10、小结
第一篇洋洋洒洒那么多个例子,终于写完了!利用“装饰器”,咱们无须改写原函数,就能对它进行功能扩充,好比计时、检测传参、记录日志等等。就好比咱们有一把枪,咱们能够给它加上消音器,又或者是刺刀…不用的时候就拿掉,仍是原来的枪~~
(本文不免有写错或不足的地方,但愿你们不吝赐教哦~谢谢!)