文成小盆友python-num6 -反射 ,常用模块
本次主要内容:
- 内容补充
- python中的反射
- 常用模块
一,内容补充:
利用上次说到的递归的方法来实现阶乘。
说明:利用函数递归的方法来实现阶乘如: 1*2*3*4*5*6*7
代码实现如下:
1 def fuck(num): 2 if num == 1 or num == 0: #这里直接把等于0的情况也写到这里了。 3 return 1 4 return num * fuck(num - 1) #这里用到了递归 5 6 res = fuck(7) 7 print(res) 8 # 9 #显示如下: 10 5040 11 12 Process finished with exit code 0
二。python中的反射
反射:基于字符串的形式去对象(模块)中操作(寻找,检查,删除,设置)其成员,这里所有的操作都是基于内存来操作的。
常用的方法:
- getattr: 寻找对象中的指定成员
- hasattr:判断对象中是否有某成员
- setattr:为对象设置成员
- delattr:删除对象中的成员
应用实例:模拟web框架的路由系统,当输入(或者后期的传入)指定的url时,到特定的对象中去执行对应的函数输出特定的内容。
分析:需要两个文件,一个文件获取用户输入的url,一个文件创建件不同的函数作为模块来等待调用。
如:所有的功能模块有如下几个:
# -*- coding:utf-8 -*- #Author:wencheng.zhao # def index(): #定义一个模块当被调用时用于显示首页内容 print("首页页面内容") def quit(): #定义一个模块当被调用时用于显示退出内容 print("退出页面内容") def home(): #定义一个模块当被调用时用于显示主页内容 print("主页内容")
如上是已经成功创建的模块,现在只要在获取url后根据url的不同来调用不同的模块达到显示不同内容的目的就ok了,如下是一种方法:
1 import commons #导入模块 2 3 while True : 4 inp = input("please insert your url:") #获取用户的输入 5 if inp == "index": 6 commons.index() 7 elif inp == "quit": 8 commons.quit() 9 elif inp == "home": 10 commons.home() 11 else: 12 print("-404-") ###上面为到用刀if 来判断用户的输入 13 14 15 ## 显示如下 16 please insert your url:index 17 首页页面内容 18 please insert your url:home 19 主页内容 20 please insert your url:quit 21 退出页面内容 22 please insert your url:sss 23 -404-
像上面这样就实现了需要的功能。现在问题来了!!! 现实中像这样的页面很多远不止这3个而已,如果还这样if else来判断,虽然是能够实现但是显得十分的low,那么现在的解决方案的来了,python中的反射可以解决此问题:实现如下
#####反射练习 ---调用commons模块 import commons def geturl(): while True: inp = input("请输入要访问的内容:") #inp 为字符串类型 if hasattr(commons,inp): #先判断这个模块中是否有这个方法 func = getattr(commons,inp) 如果有这个方法就把这个函数名获得到 func() #执行对应的函数 else: print("--404--") if __name__ == '__main__': #这种形式前面没有介绍,后续会补充。。 geturl() #调用。 #显示如下: 请输入要访问的内容:index 首页页面内容 请输入要访问的内容:home 主页内容 请输入要访问的内容:quit 退出页面内容 请输入要访问的内容:sss --404--
上面的代码即使模块中有上百个函数,那么调用界面也无需改动代码,这样就实现了。还有需要考虑的情况就是当需要导入的模块并不在同一模块中时,这里就用到了一个额外的import的小知识。
__import__(): 可以接收字符串来导入,这个模块。如下:
我在文件manager中创建了一个函数:
# -*- coding:utf-8 -*- #Author:wencheng.zhao # def guanli (): print("管理界面--")
下面就需要动态的导入需要查找的模块,这时候需要用户同时输入模块的名称和模块中函数的名称来使用,实现如下:
1 def geturl(): 2 while True: 3 4 inp = input("请输入要访问的内容:") #输入格式 manager/login 5 m,u = inp.split("/") #将获得的字符串分别赋值给m,和u 6 obj = __import__(m) # 这里导入的m为字符串,##注意 如果导入的模块不在一级目录上 那么需要用到字符串拼接,并且需要值fromlist = True 7 if hasattr(obj,u): 8 func = getattr(obj,u) 9 func() 10 else: 11 print("--404--") 12 13 14 if __name__ == '__main__': 15 geturl() 16 17 ##显示如下: 18 请输入要访问的内容:commons/index 19 首页页面内容 20 请输入要访问的内容:commons/quit 21 退出页面内容 22 请输入要访问的内容:commons/home 23 主页内容 24 请输入要访问的内容:manager/guanli 25 管理界面--
三。基本模块使用补充
1.sys
用于提供对python解释器相关的操作
sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit(0) sys.version 获取Python解释程序的版本信息 sys.maxint 最大的Int值 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 sys.platform 返回操作系统平台名称 sys.stdin 输入相关 sys.stdout 输出相关 sys.stderror 错误相关 ##部分功能如下: print(sys.argv) print(sys.version) print(sys.path) print(sys.platform) ####分别对应展示 ['/Users/wenchengzhao/PycharmProjects/s13/day6/temp.py'] 3.5.1 (v3.5.1:37a07cee5969, Dec 5 2015, 21:12:44) [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] ['/Users/wenchengzhao/PycharmProjects/s13/day6', '/Users/wenchengzhao/PycharmProjects/s13', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python35.zip', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/plat-darwin', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages'] darwin
应用实例:
利用sys对输出的控制来实现进度条功能:
import sys import time def view_bar(num, total): rate = float(num) / float(total) rate_num = int(rate * 100) balck_num = 100 - rate_num r = '\r[%s%s]%d%%' % ("#"*rate_num," "*balck_num,rate_num, ) sys.stdout.write(r) sys.stdout.flush() if __name__ == '__main__': for i in range(0, 101): time.sleep(0.1) view_bar(i, 100) ##显示如下: [########################################################################### ]75%
2.os
用于提供系统级别的操作:
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd os.curdir 返回当前目录: ('.') os.pardir 获取当前目录的父目录字符串名:('..') os.makedirs('dir1/dir2') 可生成多层递归目录 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 os.remove() 删除一个文件 os.rename("oldname","new") 重命名文件/目录 os.stat('path/filename') 获取文件/目录信息 os.sep 操作系统特定的路径分隔符,win下为"\\",Linux下为"/" os.linesep 当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" os.pathsep 用于分割文件路径的字符串 os.name 字符串指示当前使用平台。win->'nt'; Linux->'posix' os.system("bash command") 运行shell命令,直接显示 os.environ 获取系统环境变量 os.path.abspath(path) 返回path规范化的绝对路径 os.path.split(path) 将path分割成目录和文件名二元组返回 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False os.path.isabs(path) 如果path是绝对路径,返回True os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
3.hashlib模块
hashlib是个专门提供hash算法的库,现在里面包括md5, sha1, sha224, sha256, sha384, sha512,使用非常简单、方便。
md5经常用来做用户密码的存储。而sha1则经常用作数字签名。具体如下:
import hashlib ##md5### obj = hashlib.md5() obj.update(bytes('zhaowencheng',encoding='utf-8')) result = obj.hexdigest() print(result) ######## sha1 ######## hash = hashlib.sha1() hash.update(bytes('zhaowencheng', encoding='utf-8')) print(hash.hexdigest()) # ######## sha256 ######## hash = hashlib.sha256() hash.update(bytes('zhaowencheng', encoding='utf-8')) print(hash.hexdigest()) # ######## sha384 ######## hash = hashlib.sha384() hash.update(bytes('zhaowencheng', encoding='utf-8')) print(hash.hexdigest()) # ######## sha512 ######## hash = hashlib.sha512() hash.update(bytes('zhaowencheng', encoding='utf-8')) print(hash.hexdigest())
以上内容使用简单方变,但是能够通过一定的手段如撞库的方法可以对密码进行反解,对于这个问题hashlib提供了自定义添加key来增加安全度:
import hashlib obj = hashlib.md5(bytes("sjdfjskfj",encoding='utf-8'))#可增加人意长度 obj.update(bytes('zhaowencheng',encoding='utf-8')) result = obj.hexdigest() print(result)
还有一个模块hmac它内部对我们创建 key 和 内容 进行进一步的处理然后再加密
import hmac h = hmac.new(bytes('898oaFs09f', encoding="utf-8")) h.update(bytes('zhaowencheng', encoding="utf-8")) print(h.hexdigest()) #
4.re
就正则表达式(re)本身来讲,他就是一种小型的高度专业化的编程语言,在python中也有内嵌,通过re模块来实现,正则表达式模式被编译成一系列的字节码,然后由c编写的匹配引擎执行。
字符匹配:
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
次数匹配:
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
函数:
1、match(pattern, string, flags=0)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # flags 2 I = IGNORECASE = sre_compile.SRE_FLAG_IGNORECASE # ignore case 3 L = LOCALE = sre_compile.SRE_FLAG_LOCALE # assume current 8-bit locale 4 U = UNICODE = sre_compile.SRE_FLAG_UNICODE # assume unicode locale 5 M = MULTILINE = sre_compile.SRE_FLAG_MULTILINE # make anchors look for newline 6 S = DOTALL = sre_compile.SRE_FLAG_DOTALL # make dot match newline 7 X = VERBOSE = sre_compile.SRE_FLAG_VERBOSE # ignore whitespace and comments 8 9 flags
从起始位置开始根据模型去字符串中匹配指定内容,匹配单个
- 正则表达式
- 要匹配的字符串
- 标志位,用于控制正则表达式的匹配方式
obj = re.match('\d+','d1234ssdff') #以字母d 开头 print(obj) #显示 None obj = re.match('\d+','1234ssdff') print(obj) #显示 <_sre.SRE_Match object; span=(0, 4), match='1234'> Process finished with exit code 0 ##如上说明match是从开始位置匹配的。
2、search(pattern, string, flags=0)
根据模型去字符串中匹配指定内容,匹配单个
1 obj = re.search('\d+', 'u123u888asf') 2 if obj: 3 print (obj.group()) 4 5 #显示如下: 6 123 7 8 Process finished with exit code 0 9 10 #从前往后匹配,只要匹配到则停止向后匹配。
3、group和groups
group(N) 返回第N组括号匹配的字符
m.groups() 返回所有括号匹配的字符,以tuple格式
a = "123abc456" print (re.search("([0-9]*)([a-z]*)([0-9]*)", a).group()) print (re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(0)) print (re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(1)) print (re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(2)) print (re.search("([0-9]*)([a-z]*)([0-9]*)", a).groups()) ####显示如下: 123abc456 123abc456 123 abc ('123', 'abc', '456')
4、findall(pattern, string, flags=0)
上述两中方式均用于匹配单值,即:只能匹配字符串中的一个,如果想要匹配到字符串中所有符合条件的元素,则需要使用 findall。
import re obj = re.findall('\d+', 'fa123uu888asf') print (obj) #显示 #['123', '888'] obj = re.search('\d+', 'fa123uu888asf') print (obj.group()) #显示 123
5、sub(pattern, repl, string, count=0, flags=0)
用于替换匹配的字符串
content = "123abc456" new_content = re.sub('\d+', '这里以前是数字', content) # new_content = re.sub('\d+', 'sb', content, 1) print (new_content) #显示如下: 这里以前是数字abc这里以前是数字 Process finished with exit code 0
6、split(pattern, string, maxsplit=0, flags=0)
根据指定匹配进行分组
content = "'1 - 2 * ((60-30+1*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2) )'" new_content = re.split('\*', content) # new_content = re.split('\*', content, 1) print (new_content) #以乘号分隔 ["'1 - 2 ", ' ((60-30+1', '(9-2', '5/3+7/3', '99/4', '2998+10', '568/14))-(-4', '3)/(16-3', "2) )'"] Process finished with exit code 0
content = "'1 - 2 * ((60-30+1*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2) )'" new_content = re.split('[\+\-\*\/]+', content) # new_content = re.split('\*', content, 1) print (new_content) #显示:一 + - * \ 等任意分隔 ["'1 ", ' 2 ', ' ((60', '30', '1', '(9', '2', '5', '3', '7', '3', '99', '4', '2998', '10', '568', '14))', '(', '4', '3)', '(16', '3', "2) )'"] Process finished with exit code 0
inpp = '1-2*((60-30 +(-40-5)*(9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2))' inpp = re.sub('\s*','',inpp) new_content = re.split('\(([\+\-\*\/]?\d+[\+\-\*\/]?\d+){1}\)', inpp, 1) print (new_content) #显示如下: ['1-2*((60-30+', '-40-5', '*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'] Process finished with exit code 0