1、装饰器原理
def f1(arg): print '验证' arg() def func(): print '12' #1、将被调用函数封装到另外一个函数 func = f1(func) #2、对原函数重新赋值 func()
现在有这样一种需求,原来的基础设施组提供的API接口函数需要都添加验证功能,解决的方法如下:
def auth(func): def inner(): #添加验证功能 print 'before' func() return inner def f1(): #原来的函数 print 'f1' ret1 = auth(f1) = def inner(): #func()<====>f1() print 'before' func() #执行原来的f1函数 f1 = auth(f1) = def inner(): #将f1函数进行重命名,会添加验证功能 print 'before' func() f1() #执行新的f1函数
事实上Python提供的语法,可以将上述功能自动实现:
def auth(func): def inner(): print 'before' func() return inner @auth def f3(): print 'f3'
此处的@auth有两层含义:
1、func() === f3()
2、将auth()函数的返回值作为f3()函数的返回值
2、函数含参数的装饰器
def auth_arg(func): #含参数的装饰器必须传入参数 def inner(arg): print 'before' func(arg) print 'after' return inner @auth_arg def f2(arg): #执行函数 print arg
basic.f2('1.1.1.1') #调用函数
3、装饰器的内层函数设置为动态参数
def auth_arg(func): def inner(*arg,**kwargs): print 'before' func(*arg,**kwargs) print 'after' return inner @auth_arg def f1(): print 'f1' @auth_arg def f2(arg): print arg
调用:任意调用
import basic
basic.f1()
print '======'
basic.f2('1.1.1.1')
简单总结:
在写装饰器的时候,如果有参数传入,至少要写两层函数:
1、第一层(外层)函数传入函数func,返回第二层的函数名,不执行函数;
2、第二层传入参数,并return 第一层传入的函数的执行结果;
4、简单回顾
1、装饰器是一个函数,至少两层 2、执行auth函数,被装饰的函数作为参数auth(foo),auth函数的返回值赋值给被装饰的函数的函数名; 3、动态参数 4、函数的返回值 5、多装饰器 6、至少三层,三层如何使用?
5、装饰器的返回值
def auth(func): def inner(*arg,**kwargs): print 'before' temp = func(*arg,**kwargs) print 'after' return temp return inner @auth def fetch_server_list(arg): #fetch_server_list === func server_list = ['c1','c2','c3'] return server_list
import basic
ret_list = basic.fetch_server_list('test')
print ret_list
6、利用装饰器实现登录验证
#Basic.py的内容
def login(): #登录验证函数 name = 'Charles' if name == 'Charles': return True else: return False def auth(func): def inner(*arg,**kwargs): is_login = login() # if is_login: # pass # else: # return "非法请求" if not is_login: return '非法请求' temp = func(*arg,**kwargs) print 'after' return temp return inner @auth def fetch_server_list(arg): server_list = ['c1','c2','c3'] return server_list
#调用b1.py
import basic
ret_list = basic.fetch_server_list('test')
print ret_list
7、利用python装饰器实现token登录验证
#Basic.py
def login(key): local = "dddddddddddddddddddddddd" if local == key: return True else: return False def auth(func): def inner(*arg,**kwargs): key = kwargs['token'] is_login = login(key) # if is_login: # pass # else: # return "非法请求" if not is_login: return '非法请求' temp = func(*arg,**kwargs) print 'after' return temp return inner @auth def fetch_server_list(arg): server_list = ['c1','c2','c3'] return server_list
调用:
import basic
key = "dddddddddddddddddddddddd"
ret_list = basic.fetch_server_list('test',token=key)
print ret_list
此时执行会报错
E:\python\python.exe E:/11S_05day/b1.py
Traceback (most recent call last):
File "E:/11S_05day/b1.py", line 12, in <module>
ret_list = basic.fetch_server_list('test',token=key)
File "E:\11S_05day\basic.py", line 99, in inner
temp = func(*arg,**kwargs)
TypeError: fetch_server_list() got an unexpected keyword argument 'token'
fetch_server_list函数只允许传入一个参数
解决方法:
def login(key):
local = "dddddddddddddddddddddddd"
if local == key:
return True
else:
return False
def auth(func):
def inner(*arg,**kwargs):
#key = kwargs['token']
#del kwargs['token']
key = kwargs.pop('token') #加粗的上述语句等价,获取之后删除
is_login = login(key)
# if is_login:
# pass
# else:
# return "非法请求"
if not is_login:
return '非法请求'
temp = func(*arg,**kwargs)
print 'after'
return temp
return inner
@auth
def fetch_server_list(arg):
server_list = ['c1','c2','c3']
return server_list
8、多装饰器
def w1(func): def inner(): print "w1,before" func() print "w1,after" return inner def w2(func): def inner(): print "w2,before" func() print "w2,after" return inner @w2 @w1 def foo(): print "foo" foo()
1、登录验证
2、用户权限验证
9、装饰器之加参数(至少三层)
def Filter(before_func,after_func): def outer(main_func): def wrapper(request,kargs): before_result = before_func(request,kargs) if(before_func !=None): return before_func; main_result = main_func(request,kargs) if(main_result !=None): return main_result; after_result = after_func(request,kargs) if(after_result !=None): return after_result; return wrapper return outer @Filter(f1,f2) #等价于 outer函数 #1、先执行函数Filter(f1,f2),得到返回值outer
#2、将outer函数的返回值赋值给被装饰的函数的函数名 def Index(request,kargs): print "index"
Index(11,22) ret = Filter(f1,f2) =outer
解释器执行流程:
Filter(before_func,after_func)--->Filter(f1,f2)--->outer(main_func)--->outer--->@outer(Index==wrapper)--->wrapper(11,22)
装饰器参考:http://www.cnblogs.com/wupeiqi/articles/4980620.html#3546425
10、python递归原理
def func(arg1,arg2): if arg1 == 0: print arg1,arg2 arg3 = arg1 + arg2 print arg3 func(arg2,arg3) func(0,1)
11、python递归的返回值
#!/usr/bin/env python # _*_ coding:utf-8 _*_ def func(arg1,arg2): if arg1 == 0: print arg1,arg2 arg3 = arg1 + arg2 if arg3 > 1000: return arg3 func(arg2,arg3) result = func(0,1) print result #返回值为None,原因是函数的返回值return是将值返回给他的调用者,arg3的值返回给它的上一个func函数了,但是上一个函数没有return E:\python\python.exe E:/11S_05day/rescur.py 0 1 None
正确的代码为如下:
def func(arg1,arg2): if arg1 == 0: print arg1,arg2 arg3 = arg1 + arg2 if arg3 > 1000: return arg3 return func(arg2,arg3) #返回结果,依次递归 result = func(0,1) print result 结果为: E:\python\python.exe E:/11S_05day/rescur.py 0 1 1597
12、python模块的导入
在window上使用第三方模块的时候,模块的安装目录为:E:\python\Lib\site-packages
import sys print sys.path #python默认找模块的路径,是一个列表 E:\python\python.exe E:/11S_05day/model.py ['E:\\11S_05day', 'E:\\11S_05day', 'C:\\Windows\\SYSTEM32\\python27.zip', 'E:\\python\\DLLs', 'E:\\python\\lib', 'E:\\python\\lib\\plat-win', 'E:\\python\\lib\\lib-tk', 'E:\\python', 'E:\\python\\lib\\site-packages']
因为python默认寻找模块的路径sys.path为一个列表,如果有需要导入的模块不在该列表当中,那么可以将该需要导入的模块的路径append到列表sys.path中
import sys
sys.path.append("E:\\")
print sys.path
python模块导入的三种方式:
import sys
from sys import argv
from mysys import argv as test
如果导入的是python的包,那么就存在init文件,在python包被导入的时候,先执行__init__文件内容,如果没有该文件,那么就无法找到其他.py文件.
如果单单是文件夹,那么不包含__init__文件。
12、os和sys模块
os:系统相关的模块
###os.walk方法,用于遍历指定目录下的文件和目录,该方法本生是一个生成器,如下: os.walk('/scripts/shell') <generator object walk at 0x8c69edc> 除了使用for循环遍历找出文件夹下的目录或者文件之外,还可以通过.next()方法找出文件夹下面的文件或者目录,如下: >>> print os.walk('/scripts/shell').next() ('/scripts/shell', ['CTPHPRestart', 'ConnectivitiesTests'], ['ConnectivitiesTests.zip', 'CTPHPRestart.zip']) #生成元组,包含文件夹的名称,目录和文件,目录和文件分别用列表表示 >>> print os.walk('/scripts/shell').next()[0] /scripts/shell >>> print os.walk('/scripts/shell').next()[1] #目录 ['CTPHPRestart', 'ConnectivitiesTests'] >>> print os.walk('/scripts/shell').next()[2] #文件 ['ConnectivitiesTests.zip', 'CTPHPRestart.zip']
sys:解释器相关的模块
subprocess是python管理子进程的模块,方法call执行成功返回0,方法check_call执行成功返回0,否则抛出异常; Popen在创建子进程之后,主进程不会等待子进程执行完毕,除非调用wait方法 import subprocess aa=subprocess.Popen('ls -l',shell=True) aa.wait() #如果不调用wait方法,子进程会block,而print后面的内容会先打印出来; print 'test is finished!!!'
child1=subprocess.Popen('cat /etc/passwd',shell=True,stdout=subprocess.PIPE) #PIPE是缓存区,可以指定将输入、输出或者错误输出放入缓冲区中 #print child1.stdout.read() with open('test.txt','wb') as f: f.write(child1.stdout.read())
13、python内置模块ConfigParser
配置文件i.cfg内容为: [section1] k1=123 k2=Charles [section2] name = eric age = 18 import ConfigParser config = ConfigParser.ConfigParser() config.read('i.cfg') # ########## 读 ########## secs = config.sections() print secs 结果为: E:\python\python.exe E:/11S_05day/index.py ['section1', 'section2'] ####################### options = config.options('section1') print options 结果为: E:\python\python.exe E:/11S_05day/index.py ['k1', 'k2'] ####################### item_list = config.items('section1') print item_list 结果为: E:\python\python.exe E:/11S_05day/index.py [('k1', '123'), ('k2', 'Charles')] ####################### val = config.get('section1','k1') print val 结果为: E:\python\python.exe E:/11S_05day/index.py 123 val = config.getint('section1','k1') #等价于上述语句,再加int(val) print val # ########## 改写 ########## sec = config.remove_section('section1') #只在内存中删除 config.write(open('i.cfg', "w")) #将删除的结果写入文件 结果: [section1]被删除 [section2] name = eric age = 18 ######################## sec = config.has_section('section1') #是否存在section1 print sec ######################## config.set('section1','k1',11111) #添加option config.write(open('i.cfg', "w")) ######################## config.remove_option('section1','k1') #删除option config.write(open('i.cfg', "w"))
配置文件应于示例:在不使用数据库的情况下,可以将数据列表写入配置文件中,在每次操作的时候,将主机列表添加到列表中,循环列表,结合paramiko模块,远程执行SHELL命令,返回结果;
14、python内置模块hashlib
################################MD5加密
import md5 hash = md5.new() hash.update('admin') ret = hash.hexdigest() print ret 结果为: E:\python\python.exe E:/11S_05day/index.py 21232f297a57a5a743894a0e4a801fc3
事实上加密算法有很多,在python中很多加密算法散落在不同的模块中,而hashlib将众多的加密算法集中到该模块中
import hashlib hash = hashlib.md5('123') #‘123’为加密的key hash.update('admin') print hash.hexdigest()