Python 装饰器 装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为"装饰器"(Decorator)
,装饰器的功能非常强大,装饰器一般接受一个函数对象作为参数,以对其进行增强,相当于C++中的构造函数,与析构函数.
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有迫切需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用.
总而言之,装饰器具有如下几个特点:
● 装饰器本身也是一个函数,其作用是,用于装饰其他函数. ● 装饰器是一个闭包函数是嵌套函数,通过外层函数提供嵌套函数的环境 ● 装饰器在权限控制,增加额外功能,如增加记录日志,缓存处理,发送邮件用的比较多
◆无参装饰器◆ 原函数中不带参数的装饰器,如下例子假设:我定义了一个函数lyshark()
,现在想要在不改变原来函数定义的情况下,在函数运行前打印一段话,函数运行后打印另一段话,此时我们可以使用装饰器的装饰功能来简单的实现这个需求.
>>> import os>>> import sys>>> >>> def outer (function ): def inner (): print ("主函数开始执行前,会先执行我!" ) result=function() print ("主函数执行结束后,要在执行我!" ) return result return inner >>> @outerdef lyshark (): print ("lyshark 的主函数体,装饰器在装饰我(*^_^*)" ) return "check ok" >>> ret=lyshark()主函数开始执行前,会先执行我! lyshark 的主函数体,装饰器在装饰我(*^_^*) 主函数执行结束后,要在执行我! >>> print ("lyshark()函数的返回值: " ,ret)lyshark()函数的返回值: check
如上代码的执行流程是这样的,步骤如下:
1.当我们调用lyshark()函数时,会自动检查lyshark()函数上是否有装饰器 2.如果有则将lyshark()函数的指针,传递给装饰器outer(function) 3.outer(function)接到指针后,执行嵌套函数内的inner(),则先执行print打印一段话 4.由于lyshark()函数指针,传递给了function变量,执行function()则相当于执行lyshark() 5.紧接着,最后一步执行打印一段结束的话,并执行返回,返回inner
◆有参装饰器◆ 原函数带一个参数的装饰器: 我们在以上的案例中,给装饰器添加一个参数,并在内部使用这个参数.
>>> import os>>> import sys>>> >>> def outer (function ): def inner (args ): print ("主函数开始执行前,会先执行我!" ) ret=function(args) print ("主函数执行结束后,要在执行我!" ) return ret return inner >>> @outerdef lyshark (args ): print (args) return 0 >>> ret=lyshark("hello world!" )主函数开始执行前,会先执行我! hello world! 主函数执行结束后,要在执行我! >>> print ("lyshark 的返回值是:" ,ret)lyshark() 函数的返回值是: 0
原函数带两个参数的装饰器: 接下来继续演示一下,带有两个参数的装饰器,3个4个,以此类推.
>>> import os>>> import sys>>> >>> >>> def outer (function ): def inner (x,y ): print ("主函数开始执行前,会先执行我!" ) ret=function(x,y) print ("主函数执行结束后,要在执行我!" ) return ret return inner >>> @outerdef lyshark (x,y ): print (x,y) return 0 >>> ret=lyshark("Hello" ,"LyShark" )主函数开始执行前,会先执行我! Hello LyShark 主函数执行结束后,要在执行我! >>> print ("lyshark() 函数的返回值是:" ,ret)lyshark() 函数的返回值是: 0
传递一个万能参数: 装饰器也可传递一个万能参数,通过此参数传递列表字典等.
>>> import os>>> import sys>>> >>> def outer (function ): def inner (*args,**kwargs ): print ("主函数开始执行前,会先执行我!" ) ret=function(*args,**kwargs) print ("主函数执行结束后,要在执行我!" ) return ret return inner >>> @outerdef lyshark (*args ): print (args) return 0 >>> num=[1 ,2 ,3 ,4 ,5 ]>>> ret=lyshark(num)主函数开始执行前,会先执行我! ([1 , 2 , 3 , 4 , 5 ],) 主函数执行结束后,要在执行我! >>> >>> print ("lyshark() 函数的返回值是:" ,ret)lyshark() 函数的返回值是: 0 @outer def lyshark_kw (*args,**kwargs ): print (args,kwargs) return 0 num=[1 ,2 ,3 ,4 ,5 ] kw={"1001" :"admin" ,"1002" :"guest" } ret=lyshark_kw(num,kw)
一次使用两个装饰器装饰函数: 如果一个装饰器不够用的话,我们可以使用两个装饰器,首先将函数与内层装饰器结合然后在与外层装饰器相结合,要理解使用@语法
的时候到底执行了什么,是理解装饰器的关键.
>>> import os>>> import sys>>> >>> def outer2 (function2 ): def inner2 (*args,**kwargs ): print ("装饰器2--->【开始】" ) ret=function2(*args,**kwargs) print ("装饰器2--->【结束】" ) return ret return inner2 >>> def outer1 (function1 ): def inner1 (*args,**kwargs ): print ("装饰器1--->【开始】" ) ret=function1(*args,**kwargs) print ("装饰器1--->【结束】" ) return ret return inner1 @outer2 @outer1 def lyshark (): print ("lyshark 函数被执行了" ) >>> lyshark()装饰器2 --->【开始】 装饰器1 --->【开始】 lyshark 函数执行了 装饰器1 --->【结束】 装饰器2 --->【结束】 @outer1 @outer2 def lyshark_and (): print ("lyshark_and 函数被执行了" ) >>> lyshark_and()装饰器1 --->【开始】 装饰器2 --->【开始】 lyshark_and 函数执行了 装饰器2 --->【结束】 装饰器1 --->【结束】
◆带参装饰器◆ 前面的装饰器本身没有带参数,如果要写一个带参数的装饰器怎么办,那么我们就需要写一个三层的装饰器,而且前面写的装饰器都不太规范,下面来写一个比较规范带参数的装饰器,下面来看一下代码,大家可以将下面的代码自我运行一下.
给装饰器本身添加参数: 接下来我们将给装饰器本身添加一些参数,使其能够实现参数传递.
>>> import functools>>> import sys>>> >>> def lyshark (temp="" ): def decorator (function ): @functools.wraps(function ) def wrapper (*args,**kwargs ): print ("主函数开始执行前,会先执行我!" ) print ("{}:{}" .format (temp,function.__name__)) ret=function(*args,**kwargs) print ("主函数执行结束后,要在执行我!" ) return ret return wrapper return decorator >>> >>> @lyshark()def test (x ): print (x+100 ) >>> test(100 )主函数开始执行前,会先执行我! :test 主函数执行结束后,要在执行我! >>> >>> @lyshark("LyShark" )def test (x ): print (x+100 ) >>> test(100 )主函数开始执行前,会先执行我! LyShark:test 主函数执行结束后,要在执行我!
给装饰器本身添加参数: 接下来我们将给装饰器本身添加两个参数,使其能够传递多个参数.
>>> import sys>>> import os>>> >>> def lyshark (x="Hello" ,y="LyShark" ): def decorator (function ): def wrapper (): print ("主函数执行前,应先执行我!" ) print (x,y) ret=function() print ("主函数执行后,要执行我!" ) return ret return wrapper return decorator >>> >>> @lyshark()def test (): print ("我是test(),主函数,装饰器在装饰我" ) >>> test()主函数执行前,应先执行我! Hello LyShark 我是test(),主函数,装饰器在装饰我 主函数执行后,要执行我! >>> >>> @lyshark("My Name Is :" ,"LyShark" )def test (): print ("我是test(),主函数,装饰器在装饰我" ) >>> test()主函数执行前,应先执行我! My Name Is : LyShark 我是test(),主函数,装饰器在装饰我 主函数执行后,要执行我!
◆装饰器实战(练习)◆ 测试程序执行时间: 通过使用装饰器,给一个已存在的函数,测试函数的执行时间.
import osimport sysimport timedef showtime (func ): def main (): start_time=time.time() func() end_time=time.time() print ("程序运行了: %s" %(end_time-start_time)) return main @showtime def timer (): time.sleep(3 ) print ("执行程序结束...." ) timer()
记录登陆状态(1): 使用装饰器记录登陆状态,下次自动登录.
import osimport sysuser_info={} user_name="admin" pass_word="1233" def check_login (func ): def main (): if ((user_info.get("is_login" ,None ) ==True ) and (user_info.get("is_type" ,None )==0 )): print ("你已经登陆过了,不能重复登陆!" ) func() else : print ("你没有登陆,请先登录,在进行此操作" ) return main def login (): username=input ("输入用户名:" ).strip() password=input ("输入密码:" ).strip() if username==user_name and password==pass_word: user_info["is_login" ]=True user_info["is_type" ]=0 print ("你好: " +username+"登陆成功,登录状态已被记录" ) elif username!="" and password!="" : print ("您输入的用户名,或者密码不正确,请重新输入" ) else : print ("您没有输入任何内容,错误" ) @check_login def home (): print ("用户登录成功,显示这个函数中的内容." ) def main (): while True : temp=input ("1.登陆 2.查询状态\n" ) if (temp=="1" ): login() elif (temp=="2" ): home() else : continue main()
记录登陆状态(2): 使用装饰器记录登陆状态,下次自动登录.
USER_INFO = {} def check_login (func ): def inner (*args,**kwargs ): if USER_INFO.get('is_login' ,None ): ret = func() return ret else : print ("请登录" ) return inner def check_admin (func ): def inner (*args,**kwargs ): if USER_INFO.get('user_type' ,None ) == 2 : ret = func() return ret else : print ("无权限查看" ) return inner @check_login @check_admin def index (): """ 管理员用户 """ print ('index' ) @check_login def home (): """ 普通用户 """ print ('home' ) def login (): user = input ("请输入用户名:" ) if user == 'admin' : USER_INFO['is_login' ] = True USER_INFO['user_type' ] = 2 else : USER_INFO['is_login' ] = True USER_INFO['user_type' ] = 1 def main (): while True : inp = input ('1、登录;2、查看信息;3、超级管理员管理\n>:' ) if inp == '1' : login() elif inp == '2' : home() elif inp == '3' : index() main()
Python 生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,还会造成大量空间的白白浪费,如果列表元素可以按照某种算法推算出来,这样我们就不必创建完整的list,从而节省大量的空间.在Python中,这种一边循环一边计算的机制,称为生成器(Generator)
.
生成器是一个特殊的程序,可以被用作控制循环的迭代行为,Python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器.
生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器.
生成器的注意事项,和相关的特性:
● 当我们调用一个生成器函数时,其实返回的是一个迭代器对象 ● 在Python语言中,只要表达式中使用了,yield函数,通常将此类函数称为生成器(generator) ● 运行生成器时,每次遇到yield函数,则会自动保存并暂停执行,直到使用next()方法时,才会继续迭代 ● 跟普通函数不同,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器
在学习生成器之前,我们先来看一下以下两种情况的对比,第一种方法很简单,只有把一个列表生成式的[]中括号改为()小括号,就创建了一个生成器.
>>> lis = [x*x for x in range (10 )]>>> print (lis)[0 , 1 , 4 , 9 , 16 , 25 , 36 , 49 , 64 , 81 ] >>> generator = (x*x for x in range (10 ))>>> print (generator)<generator object <genexpr> at 0x0000022E5C788A98 >
如上的例子,第一个lis
通过列表生成式,创建了一个列表,而第二个generator
则打印出一个内存地址,如果我们想获取到第二个变量中的数据,则需要迭代操作,如下所示:
>>> generator = (x*x for x in range (10 ))>>> print (next (generator))0 >>> print (next (generator))1 >>> print (next (generator))4 >>> print (next (generator))9
以上可以看到,generator保存的是算法,每次调用next(generaotr),就计算出他的下一个元素的值,直到计算出最后一个元素,使用for循环可以简便的遍历出迭代器中的数据,因为generator也是可迭代对象.
>>> generator = (x*x for x in range (10 ))>>> >>> for i in generator: print (i,end="" ) 0149162536496481
◆生成器的实例◆ 实例(1): 通过函数,和yield关键字
,生成几个生成器.
>>> import sys>>> >>> def func (): yield 1 yield 2 yield 3 yield 4 yield 5 >>> temp=func()>>> temp.__next__()1 >>> temp.__next__()2 >>> temp.__next__()3
实例(2): 使用while循环构建一个生成器,并通过for遍历打印出结果.
>>> import sys>>> >>> def yieldNum (x ): y=0 while (y <= x): yield y y += 1 >>> yie=yieldNum(5 )>>> for i in yie: print (i) 0 1 2 3 4 5
实例(3): 使用生成器求1-10的平方.
>>> def yieldNum (): x=1 while (x <=10 ): yield x ** 2 x += 1 >>> yie=yieldNum()>>> >>> for i in yie: print (i) 4 16 36 64 100
实例(4): 使用生成器,自定义实现range函数.
>>> def xrange (num ): temp=-1 while True : temp=temp+1 if (temp >= num): return else : yield temp >>> xrange(10 )<generator object xrange at 0x038E3030 >
实例(5): 通过使用生成器求斐波那契数列.
>>> def fib (max ): n,a,b=0 ,0 ,1 while n < max : yield b a,b=b,a+b n+=1 return "done" >>> f=fib(5 )>>> f<generator object fib at 0x038F4A20 >
实例(6): 使用生成器,在单个进程情况下实现并发效果.
import timedef consumer (name ): print ("%s 准备吃包子啦!" %name) while True : baozi = yield print ("包子[%s]来了,被[%s]吃了!" %(baozi,name)) def producer (name ): c = consumer('A' ) c2 = consumer('B' ) c.__next__() c2.__next__() print ("老子开始准备做包子啦!" ) for i in range (10 ): time.sleep(1 ) print ("做了2个包子!" ) c.send(i) c2.send(i) producer("alex" )
◆生成列表解析◆ 列表解析是Python迭代机制的一种应用,它常用于实现创建新的列表,因此要放置于[]中,列表解析非常灵活,可以用户快速创建一组相应规则的列表元素,且支持迭代操作.
求阶乘: 通过列表解析式,来实现列表的迭代求阶乘.
>>> temp1 = [1 ,2 ,3 ,4 ,5 ]>>> temp2 = [ x ** 2 for x in temp1 ]>>> temp1[1 , 2 , 3 , 4 , 5 ] >>> temp2[1 , 4 , 9 , 16 , 25 ]
求阶乘: 通过列表解析式,实现迭代求阶乘,并且只打印大于2(if x>=2)
的数据.
>>> temp1 = [1 ,2 ,3 ,4 ,5 ]>>> temp2 = [ x**2 for x in temp if x>=2 ]>>> temp1[1 , 2 , 3 , 4 , 5 ] >>> temp2[4 , 9 , 16 , 25 ]
求阶乘: 通过列表解析式,实现迭代求阶乘,并通过range
函数生成相关数据.
>>> temp = [ (x**2 )/2 for x in range (1 ,10 )]>>> temp[0.5 , 2.0 , 4.5 , 8.0 , 12.5 , 18.0 , 24.5 , 32.0 , 40.5 ]
数据合并: 通过列表解析式,实现迭代将两个列表按照规律合并.
>>> temp1=["x" ,"y" ,"z" ]>>> temp2=[1 ,2 ,3 ]>>> temp3=[ (i,j) for i in temp1 for j in temp2 ]>>> temp3[('x' , 1 ), ('x' , 2 ), ('x' , 3 ), ('y' , 1 ), ('y' , 2 ), ('y' , 3 ), ('z' , 1 ), ('z' , 2 ), ('z' , 3 )]
文件过滤: 通过使用列表解析,实现文本的过滤操作.
>>> import os>>> file_list=os.listdir("/var/log" )>>> file_log=[ i for i in file_list if i.endswith(".log" ) ]>>> print (file_log)['boot.log' , 'yum.log' , 'ecs_network_optimization.log' , 'ntp.log' ] >>> file_log=[ i for i in os.listdir("/var/log" ) if i.endswith(".log" ) ]>>> print (file_log)['boot.log' , 'yum.log' , 'ecs_network_optimization.log' , 'ntp.log' ]
◆生成器表达式◆ 生成器表达式并不真正创建数字列表,而是返回一个生成器对象,此对象在每次计算出一个条目后,把这个条目"产生"(yield)
出来,生成器表达式使用了”惰性计算”或称作”延迟求值”的机制序列过长,并且每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析.
>>> import sys>>> >>> yie=( i**2 for i in range (1 ,10 ) )>>> next (yie)1 >>> next (yie)4 >>> next (yie)9
>>> for j in ( i**2 for i in range (1 ,10 )):print (j/2 )... 0.5 2.0 4.5 8.0 12.5 18.0 24.5 32.0 40.5
Python 迭代器 迭代器是访问集合元素的一种方式,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素.迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁.这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G文件的遍历.
关于迭代器的几个特性:
● 迭代器是一个可以记住遍历的位置的对象 ● 字符串,列表或元组对象都可用于创建迭代器 ● 迭代器有两个基本的方法:iter()和next()
● 迭代器便于循环比较大的数据集合,节省了内存开支 ● 迭代是Python最强大的功能之一,是访问集合元素的一种方式 ● next()就相当于调用__next__(),for也是iterable(可迭代)对象 ● 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容 ● 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退
实例(1): 迭代器的基本用法1.
>>> import sys>>> >>> temp=iter ([1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ])>>> temp<list_iterator object at 0x03BD1F90 > >>> temp.__next__()1 >>> temp.__next__()2 >>> temp.__next__()3
实例(2): 迭代器的基本用法2.
>>> import sys>>> >>> temp=[1 ,2 ,3 ,4 ,5 ]>>> ite=temp.__iter__()>>> print (type (temp),type (ite))<class 'list' > <class 'list_iterator' > >>> next (ite)1 >>> >>> next (ite)2 >>> next (ite)3 >>> next (ite)4
实例(3): 通过while语句遍历迭代对象.
>>> ite=iter ([1 ,2 ,3 ,4 ,5 ])>>> >>> while True : try : temp=next (ite) print (temp) except StopIteration: break 1 2 3 4 5