作者:赵俊 发布日期:2020/09/03
三、模块定义、导入、优化详解1
1、定义
模块:用来从逻辑上组织python代码,本质就是.py结尾的一个python文件
包:从逻辑上组织模块,本质就是一个目录(必须带有一个__init__.py文件)
2、导入方法
导入单个模块>>>>>import 模块名
导入多个模块>>>>>import 模块名1,模块名2,............
以上导入使用时格式,模块名.变量或函数名()
直接导入所有>>>>>from 模块名 import *(不建议这么使用,会和本身代码中的函数冲突)
直接导入函数或变量>>>>>from 模块名 import 函数名
直接导入函数或变量>>>>>from 模块名 import 函数名 as 别名,调用时使用别名,避免冲突
以上导入使用时格式,直接使用变量或函数名()
3、import本质
导入模块的本质就是把python文件解释一遍
导入包的本质就是执行包下面的init.py文件
四、模块定义、导入、优化详解2
在__init__.py文件里直接使用import好像不起作用,使用from . import module可以导入模块
导入优化 -----------from 模块名 import 函数名,使用这个避免了重复查找模块,提高程序效率
五、内置模块详解之time与datetime模块
python模块的分类:
标准库,系统自带的模块
开源模块,程序爱好者开发并开源的模块
自定义模块,自己写的模块
1、time模块
在python中有三种表示时间的方式:
1)时间戳,是当下时间与1970年1月1日零时零分零秒的一个时间差
2)格式化的时间字符串
3)元祖(共九个元素) 返回值分别代表,年/月/日/时/分/秒/一周第几天/一年第几天/夏令时
1 # Author:ZHJ 2 import time 3 print(time.sleep(1)) # 休眠几秒 4 #返回元祖的语句 5 print("返回元祖------------------------------------------------------") 6 print(time.gmtime()) # 传入时间戳参数,返回元祖形式时间,转换的时间是UTC时间,不是当地时间 7 print(time.localtime()) # 传入时间戳参数,返回元祖形式时间,转换的时间是本地时间(UTC+8) 8 print(time.strptime("2803-2>>12","%Y-%m>>%d")) # 传入需要的格式化的字符串时间和格式标注,返回元祖 9 print("返回秒------------------------------------------------------") 10 #返回秒的语句 11 print(time.timezone) # 本地标准时间与标准UTC的时间差,单位为秒,除以3600就为时区,负数为东,正数为西 12 print(time.altzone) # 本地夏令时间与标准UTC的时间差,单位为秒 13 print("返回时间戳------------------------------------------------------") 14 #返回时间戳 15 print(time.time()) # 获取时间戳 16 x = time.localtime() 17 print(time.mktime(x)) # 传入元祖,返回时间戳 18 print("返回格式化字符串------------------------------------------------------") 19 #返回格式化字符串时间 20 print(time.strftime("%Y-%m>>%d", x)) # 传入需要的标准格式和元祖,返回格式化的字符串时间 21 print(time.asctime()) # 传入元祖,返回格式化字符串时间,没有传变量使用当前时间元祖 22 print(time.ctime()) # 传入秒,返回格式化字符串时间,没有传变量使用当前时间秒 23 """ 24 strftime格式化 25 %Y Year with century as a decimal number. 26 %m Month as a decimal number [01,12]. 27 %d Day of the month as a decimal number [01,31]. 28 %H Hour (24-hour clock) as a decimal number [00,23]. 29 %M Minute as a decimal number [00,59]. 30 %S Second as a decimal number [00,61]. 31 %z Time zone offset from UTC. 32 %a Locale's abbreviated weekday name. 33 %A Locale's full weekday name. 34 %b Locale's abbreviated month name. 35 %B Locale's full month name. 36 %c Locale's appropriate date and time representation. 37 %I Hour (12-hour clock) as a decimal number [01,12]. 38 %p Locale's equivalent of either AM or PM. 39 """
1 None 2 返回元祖------------------------------------------------------ 3 time.struct_time(tm_year=2020, tm_mon=8, tm_mday=26, tm_hour=3, tm_min=41, tm_sec=13, tm_wday=2, tm_yday=239, tm_isdst=0) 4 time.struct_time(tm_year=2020, tm_mon=8, tm_mday=26, tm_hour=11, tm_min=41, tm_sec=13, tm_wday=2, tm_yday=239, tm_isdst=0) 5 time.struct_time(tm_year=2803, tm_mon=2, tm_mday=12, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=2, tm_yday=43, tm_isdst=-1) 6 返回秒------------------------------------------------------ 7 -28800 8 -32400 9 返回时间戳------------------------------------------------------ 10 1598413273.624613 11 1598413273.0 12 返回格式化字符串------------------------------------------------------ 13 2020-08>>26 14 Wed Aug 26 11:41:13 2020 15 Wed Aug 26 11:41:13 2020
2、datetime模块
1 # Author:ZHJ 2 import datetime 3 4 print(datetime.datetime.now()) # 返回2020-08-26 11:46:14.354203 5 print(datetime.datetime.now() + datetime.timedelta(3)) # 返回三天后时间2020-08-29 11:47:53.891897 6 print(datetime.datetime.now() + datetime.timedelta(hours=3)) # 返回三小时后时间2020-08-26 14:48:56.034451 7 print(datetime.datetime.now() + datetime.timedelta(minutes=30)) # 返回30分钟后时间2020-08-26 12:19:50.847586 8 # 需要之前时间传递参数为负值 9 10 11 # 时间替换,不是真的改系统时间 12 print(datetime.datetime.now()) 13 c_time = datetime.datetime.now() 14 print(c_time.replace(minute=30,hour=12))
六、内置模块详解之Random模块
自己取文件名一定要与导入的模块名区别开,如果相同会导致导入模块错误
1 # Author:ZHJ 2 import random 3 4 # print(random.random()) 5 print(random.random()) # 0-1的随机浮点数 6 print(random.randint(1, 5)) # 左闭右闭区间取随机整数 7 print(random.randrange(1, 2)) # 左闭右开区间取随机整数,random.randrange([start], stop[, step]) 8 print(random.choice("asdfghjk1234567890")) # 从序列中获取一个随机元素,list, tuple, 字符串都属于序列 9 print(random.sample("asdfg34sdfw34", 5)) # 从序列中随机获取5个元素,作为一个片断返回 10 print(random.uniform(1,2)) # 区间随机浮点数 11 12 list_t = [1,2,3,5,5,15,12,5,1,25,12,] 13 random.shuffle(list_t) # 将列表的元素打乱 14 print(list_t)
1 验证码 2 # Author:ZHJ 3 import random 4 code = "" 5 for i in random.sample("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 5): 6 code += i 7 print(code)
七、内置模块详解之OS模块
1 # Author:ZHJ 2 import os 3 import time 4 # print(os.getcwd()) # 获取当前工作目录,及当前python脚本目录路径 5 # print(os.chdir("F:PythonProject")) # 改变当前脚本的工作目录 6 # print(os.curdir) # 返回当前目录 7 # os.makedirs("aa/bb/cc") # 可生成多层递归目录,注意反斜杠 8 # os.removedirs("aa/bb/cc") # 若目录为空则删除,递归到上一层,若也为空则山,以此类推 9 # os.mkdir("cc") # 生成单级目录 10 # os.rmdir("cc") # 删除单级目录,非空则不删除,报错 11 # os.listdir("C:\") # 列出目录下的所有子目录和文件,包括隐藏文件,返回列表 12 # os.remove("新建文本文档.txt") # 删除指定文件 13 # os.rename("456.txt","123.txt") # 重命名文件 14 # print(os.stat("F:PythonProjectDay5")) #获取文件或目录信息 15 # print(os.sep) # 输出操作系统路径分隔符 16 # print(os.linesep) # 输出操作系统行终止符 17 # print(os.pathsep) # 用于分割文件路径的字符串,就是环境 变量里分割路径的字符串 18 # print(os.name) # 指示当前使用平台 19 # print(os.system("dir")) # 指示当前使用平台,dos命令 20 # print(os.environ) # 获取系统环境变量 21 # print(os.path.abspath(os.getcwd())) # 返回path规范化的绝对路径 22 print(os.path.split(os.getcwd())) # 将path分割成目录和文件名元组返回 23 print(os.path.dirname(os.getcwd())) # 返回这个os.path.split返回元祖的第一个元素 24 print(os.path.basename(os.getcwd())) # 返回这个os.path.split返回元祖的第二个元素 25 print(os.path.exists(os.getcwd())) # 路径存在返回True,否则返回false 26 print(os.path.isabs(os.getcwd())) # 是否是绝对路径 27 print(os.path.isfile(os.getcwd())) # 路径是一个存在的文件返回True 28 print(os.path.isdir(os.getcwd())) # 是否是一个目录 29 print(os.path.join(os.getcwd()),"/au") # 多个路径组合后返回,第一个绝对路径前的参数将被忽略 30 print(time.ctime(os.path.getatime(r"F:PythonProject123.txt"))) # 路径所指文件或目录的最后访问时间 31 print(time.ctime(os.path.getmtime(r"F:PythonProject123.txt"))) # 路径所指文件或目录的最后修改时间
1 import sys,os 2 def run(): 3 print("sys.path[0]返回路径-----",sys.path[0]) 4 print("sys.argv[0]返回路径-----",sys.argv[0]) 5 print("os.getcwd()返回路径-----",os.getcwd()) 6 print("__file__返回路径-----",__file__) 7 print("os.path.abspath('.')返回路径-----",os.path.abspath('.')) 8 print("os.path.realpath('.')返回路径-----",os.path.realpath('.')) 9 run() 10 11 # 被调用时执行结果 12 # sys.path[0]返回路径----- F:PythonProject路径测试 13 # sys.argv[0]返回路径----- F:/Python/Project/路径测试/test.py 14 # os.getcwd()返回路径----- F:PythonProject路径测试 15 # __file__返回路径----- F:PythonProject路径测试adsss .py 16 # os.path.abspath('.')返回路径----- F:PythonProject路径测试 17 # 自己执行结果 18 # sys.path[0]返回路径----- F:PythonProject路径测试adsss 19 # sys.argv[0]返回路径----- F:/Python/Project/路径测试/ad/sss/t.py 20 # os.getcwd()返回路径----- F:PythonProject路径测试adsss 21 # __file__返回路径----- F:/Python/Project/路径测试/ad/sss/t.py 22 # os.path.abspath('.')返回路径----- F:PythonProject路径测试adsss
根据上面的执行结果,可以看出使用__file__形式可以保证路径的一致性
八、内置模块详解之Sys和shutil模块
1、sys
1 import sys 2 x = sys.argv # 接收命令行传递的参数 3 print(x) 4 5 x = sys.path # 打印系统环境变量 6 print(x) 7 8 x = sys.version # 获取解释器版本 9 print(x) 10 11 x = sys.platform # 返回操作系统平台名称 12 print(x) 13 14 sys.stdout.write("输出的文本") # print输出自动换行,这个不换行 15 print("输出的文本") # 16 17 """ 18 sys.stdin.readline( )会将标准输入全部获取,包括末尾的' ', 19 因此用len计算长度时是把换行符' '算进去了的,但是input( )获取输入时返回的结果是不包含末尾的换行符' '的。 20 """ 21 print("请输入!") 22 x = sys.stdin.readline() # input()括号内可以直接填写说明文字,sys.stdin还需要加个print方法给出提示信息。 23 print(x) 24 x = input("请输入!") 25 print(x) 26 27 x = sys.stdin.readline( )[:-1] # 去掉结尾换行
2、shutil
高级的文件、文件夹、压缩包处理模块
1 import shutil 2 """ 3 必须先打开文件才可以复制 4 """ 5 # f1 = open("复制.txt", "r", encoding="utf-8") 6 # f2 = open("复制_副本.txt", "w", encoding="utf-8") 7 # shutil.copyfileobj(f1, f2, 20) 8 9 """ 10 直接给文件名,就可以复制,源文件必须存在 11 """ 12 # shutil.copyfile("复制.txt", "复制_副本.txt") 13 14 """ 15 递归的拷贝目录和文件 16 """ 17 # shutil.copytree("a", "aa") 18 19 """ 20 递归的删除目录和文件 21 """ 22 #shutil.rmtree("aa") 23 24 """ 25 shutil.make_archive(base_name, format,...) 26 base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径, 27 如:www =>保存至当前路径 28 如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/ 29 format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar” 30 root_dir: 要压缩的文件夹路径(默认当前目录) 31 owner: 用户,默认当前用户 32 group: 组,默认当前组 33 logger: 用于记录日志,通常是logging.Logger对象 34 """ 35 shutil.make_archive("ATM", "zip", "F:PythonProjectDay4") # 指定文件所在目录的所有文件打包
shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的
1 import zipfile 2 3 # 压缩 4 z = zipfile.ZipFile('laxi.zip', 'w') 5 z.write('a.log') 6 z.write('data.data') 7 z.close() 8 9 # 解压 10 z = zipfile.ZipFile('laxi.zip', 'r') 11 z.extractall() 12 z.close()
九、内置模块详解之Shelve模块
shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式
1 import shelve 2 """ 3 shelve模块是一个简单的k,v将内存数据通过文件持久化的模块 4 """ 5 d = shelve.open("test123") # 文件可以不用存在 6 # d["a"] = [123, 244, "hello"] 7 # d.close() 8 9 print(d.get("a")) # 取回时使用get方法
十、内置模块详解之Xml模块1
遍历
1 import xml.etree.ElementTree as ET 2 3 tree = ET.parse("xmltest.xml") 4 root = tree.getroot() 5 print(root.tag) 6 7 #遍历xml文档 8 for child in root: 9 print(child.tag, child.attrib) 10 for i in child: 11 print(i.tag,i.text) 12 13 #只遍历year 节点 14 for node in root.iter('year'): 15 print(node.tag,node.text)
十一、内置模块详解之Xml模块2
修改和删除xml文档内容
1 import xml.etree.ElementTree as ET 2 3 tree = ET.parse("xmltest.xml") 4 root = tree.getroot() 5 6 #修改 7 for node in root.iter('year'): 8 new_year = int(node.text) + 1 9 node.text = str(new_year) 10 node.set("updated","yes") 11 12 tree.write("xmltest.xml") 13 14 15 #删除node 16 for country in root.findall('country'): 17 rank = int(country.find('rank').text) 18 if rank > 50: 19 root.remove(country) 20 21 tree.write('output.xml')
自己创建xml文档
1 import xml.etree.ElementTree as ET 2 3 4 new_xml = ET.Element("namelist") 5 name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"}) 6 age = ET.SubElement(name,"age",attrib={"checked":"no"}) 7 sex = ET.SubElement(name,"sex") 8 sex.text = '33' 9 name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"}) 10 age = ET.SubElement(name2,"age") 11 age.text = '19' 12 13 et = ET.ElementTree(new_xml) #生成文档对象 14 et.write("test.xml", encoding="utf-8",xml_declaration=True) 15 16 ET.dump(new_xml) #打印生成的格式
十二、内置模块详解之Configparser模块
用于生成和修改常见配置文档,当前模块的名称在 python 3.x 版本中变更为 configparser。
来看一个好多软件的常见文档格式如下
[DEFAULT] ServerAliveInterval = 45 Compression = yes CompressionLevel = 9 ForwardX11 = yes [bitbucket.org] User = hg [topsecret.server.com] Port = 50022 ForwardX11 = no
如果想用python生成一个这样的文档怎么做呢?
1 import configparser 2 3 config = configparser.ConfigParser() 4 config["DEFAULT"] = {'ServerAliveInterval': '45', 5 'Compression': 'yes', 6 'CompressionLevel': '9'} 7 8 config['bitbucket.org'] = {} 9 config['bitbucket.org']['User'] = 'hg' 10 config['topsecret.server.com'] = {} 11 topsecret = config['topsecret.server.com'] 12 topsecret['Host Port'] = '50022' # mutates the parser 13 topsecret['ForwardX11'] = 'no' # same here 14 config['DEFAULT']['ForwardX11'] = 'yes' 15 with open('example.ini', 'w') as configfile: 16 config.write(configfile)
写完了还可以再读出来
1 >>> import configparser 2 >>> config = configparser.ConfigParser() 3 >>> config.sections() 4 [] 5 >>> config.read('example.ini') 6 ['example.ini'] 7 >>> config.sections() 8 ['bitbucket.org', 'topsecret.server.com'] 9 >>> 'bitbucket.org' in config 10 True 11 >>> 'bytebong.com' in config 12 False 13 >>> config['bitbucket.org']['User'] 14 'hg' 15 >>> config['DEFAULT']['Compression'] 16 'yes' 17 >>> topsecret = config['topsecret.server.com'] 18 >>> topsecret['ForwardX11'] 19 'no' 20 >>> topsecret['Port'] 21 '50022' 22 >>> for key in config['bitbucket.org']: print(key) 23 ... 24 user 25 compressionlevel 26 serveraliveinterval 27 compression 28 forwardx11 29 >>> config['bitbucket.org']['ForwardX11'] 30 'yes'
configparser增删改查语法
1 [section1] 2 k1 = v1 3 k2:v2 4 5 [section2] 6 k1 = v1 7 8 import ConfigParser 9 10 config = ConfigParser.ConfigParser() 11 config.read('i.cfg') 12 13 # ########## 读 ########## 14 #secs = config.sections() 15 #print secs 16 #options = config.options('group2') 17 #print options 18 19 #item_list = config.items('group2') 20 #print item_list 21 22 #val = config.get('group1','key') 23 #val = config.getint('group1','key') 24 25 # ########## 改写 ########## 26 #sec = config.remove_section('group1') 27 #config.write(open('i.cfg', "w")) 28 29 #sec = config.has_section('wupeiqi') 30 #sec = config.add_section('wupeiqi') 31 #config.write(open('i.cfg', "w")) 32 33 34 #config.set('group2','k1',11111) 35 #config.write(open('i.cfg', "w")) 36 37 #config.remove_option('group2','age') 38 #config.write(open('i.cfg', "w"))
十三、内置模块详解之Hashlib、Hmac模块
用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
1 import hashlib 2 3 m = hashlib.md5() 4 m.update(b"Hello") 5 m.update(b"It's me") 6 print(m.digest()) 7 m.update(b"It's been a long time since last time we ...") 8 9 print(m.digest()) #2进制格式hash 10 print(len(m.hexdigest())) #16进制格式hash 11 ''' 12 def digest(self, *args, **kwargs): # real signature unknown 13 """ Return the digest value as a string of binary data. """ 14 pass 15 16 def hexdigest(self, *args, **kwargs): # real signature unknown 17 """ Return the digest value as a string of hexadecimal digits. """ 18 pass 19 20 ''' 21 import hashlib 22 23 # ######## md5 ######## 24 25 hash = hashlib.md5() 26 hash.update('admin') 27 print(hash.hexdigest()) 28 29 # ######## sha1 ######## 30 31 hash = hashlib.sha1() 32 hash.update('admin') 33 print(hash.hexdigest()) 34 35 # ######## sha256 ######## 36 37 hash = hashlib.sha256() 38 hash.update('admin') 39 print(hash.hexdigest()) 40 41 42 # ######## sha384 ######## 43 44 hash = hashlib.sha384() 45 hash.update('admin') 46 print(hash.hexdigest()) 47 48 # ######## sha512 ######## 49 50 hash = hashlib.sha512() 51 hash.update('admin') 52 print(hash.hexdigest())
散列消息鉴别码,简称HMAC,是一种基于消息鉴别码MAC(Message Authentication Code)的鉴别机制。使用HMAC时,消息通讯的双方,通过验证消息中加入的鉴别密钥K来鉴别消息的真伪;
一般用于网络通信中消息加密,前提是双方先要约定好key,就像接头暗号一样,然后消息发送把用key把消息加密,接收方用key + 消息明文再加密,拿加密后的值 跟 发送者的相对比是否相等,这样就能验证消息的真实性,及发送者的合法性了。
1 import hmac 2 h = hmac.new('中文'.encode(encoding="utf-8"), '中文怎么办'.encode(encoding="utf-8")) 3 print h.hexdigest()
十四、正则表达式Re模块使用详解
用正则表达式符号
1 '.' 默认匹配除 之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行 2 '^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a"," abc eee",flags=re.MULTILINE) 3 '$' 匹配字符结尾,或e.search("foo$","bfoo sdfsf",flags=re.MULTILINE).group()也可以 4 '*' 匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac") 结果为['abb', 'ab', 'a'] 5 '+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb'] 6 '?' 匹配前一个字符1次或0次 7 '{m}' 匹配前一个字符m次 8 '{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb'] 9 '|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC' 10 '(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c 11 12 13 'A' 只从字符开头匹配,re.search("Aabc","alexabc") 是匹配不到的 14 '' 匹配字符结尾,同$ 15 'd' 匹配数字0-9 16 'D' 匹配非数字 17 'w' 匹配[A-Za-z0-9] 18 'W' 匹配非[A-Za-z0-9] 19 's' 匹配空白字符、 、 、 , re.search("s+","ab c1 3").group() 结果 ' ' 20 21 '(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}
最常用的匹配语法
re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.splitall 以匹配到的字符当做列表分隔符
re.sub 匹配字符并替换
反斜杠的困扰
与大多数编程语言相同,正则表达式里使用""作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\"表示。同样,匹配一个数字的"\d"可以写成r"d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
1 import re 2 info = "abbb3cabb3abc6bbac" 3 # x = re.match("ab*", info) # 从头开始匹配,匹配一个 4 # x = re.search("ab*", info) # 整个字符串,找到匹配样式的第一个位置,并返回一个相应的 匹配对象 5 # x = re.fullmatch("abbbcabb3abcbbac", info) # 完全匹配,表达式和字符串完全一样 6 # lt1 = re.split("d", info) # 用正则表达式分开字符串,并返回列表 7 # lt2 = re.findall("ab{0,2}", info) # 匹配所有, string 从左到右进行扫描,匹配按找到的顺序返回 8 # info = "heggfdello" 9 # lt3 = re.findall("e.+e", info) 10 # info = "576h" 11 # x = re.search("A[0-9]+[a-z]$", info) 12 # print(lt1) 13 # print(lt2) 14 # print(lt3) 15 # if x: 16 # print(x.group()) 17 # else: 18 # print("没有匹配对象") 19 20 #(?P<name>...)' 分组匹配 ' 21 # 分割身份证号码案例 22 # x = re.search("(?P<province>[0-9]{2})(?P<city>[0-9]{2})(?P<county>[0-9]{2})(?P<birthday>[0-9]{8})(?P<ID>[0-9]{4})", "610121198711026734") 23 # if x: 24 # print(x.groupdict()) 25 # else: 26 # print("没有匹配对象") 27 28 x = re.sub("[0-9]","@","cjh378jj68ubdh9jhd3du8",count= 2) # 将字符串中的数字替换成@符号,count替换几次 29 print(x)
作业:开发一个简单的python计算器
- 实现加减乘除及括号优先级解析
- 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式(不能调用eval等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致
过程中遇到的麻烦:
# int()函数里面不能传浮点数,但fload()函数里可以传整数
# TypeError: 'str' object is not callable
# 细看了一下代码,原来是之前将一个变量命名为 str,
# 之后又把它作为底层 str() 进行调用。其实这时候,它已经不再是 Python 的底层函数咯。
# 递归函数返回值为None 的问题,解决办法的思路就是:使每次递归都要能够执行到return语句 。
# 不匹配两边括号的正则,只匹配括号里内容(?<=()[^()]+(?=))
1 # Author:ZHJ 2 import re 3 # int()函数里面不能传浮点数,但fload()函数里可以传整数 4 5 # TypeError: 'str' object is not callable 6 # 细看了一下代码,原来是之前将一个变量命名为 str, 7 # 之后又把它作为底层 str() 进行调用。其实这时候,它已经不再是 Python 的底层函数咯。 8 9 #递归函数返回值为None 的问题,解决办法的思路就是:使每次递归都要能够执行到return语句 。 10 11 # 不匹配两边括号的正则,只匹配括号里内容(?<=()[^()]+(?=)) 12 13 def calculate_dual(equation): 14 """ 15 计算两个数值的加减乘除 16 :param equation: 是一个字符串,例:3*4 17 :return: 返回加减乘除的结果 18 """ 19 if re.search("[0-9]+*(-?)[0-9]+",equation): # 如果两个数相乘可以匹配到 20 lt = re.split("*", equation) # 以乘号分割 21 return float(lt[0]) * float(lt[1]) #分隔后两个列表元素相乘返回 22 elif re.search("(-?)[0-9]+/(-?)[0-9]+",equation): 23 lt = re.split("/", equation) 24 return float(lt[0]) / float(lt[1]) 25 elif re.search("(-?)[0-9]++(-?)[0-9]+",equation): 26 lt = re.split("+", equation) 27 return float(lt[0]) + float(lt[1]) 28 elif re.search("(-?)[0-9]+-(-?)[0-9]+",equation): 29 lt = re.split("-", equation) 30 return float(lt[0]) - float(lt[1]) 31 32 33 def cl_mul_and_div(equation): 34 """ 35 计算一个算式中的乘除,用正则匹配第一个乘或除,计算后替换原来算式,递归后接着算,知道匹配不上乘除 36 说明式子中只剩加减; 37 递归函数中是用返回值,返回none,需要在每一次递归时要执行返回值,需要把递归那一句代码也加return 38 :param equation: 39 :return: 40 """ 41 # print(equation) 42 z = re.search("[0-9]*.?[0-9]+(*|/)(-?)[0-9]*.?[0-9]+",equation) 43 if z: 44 # print(z.group()) 45 t = re.sub(re.escape(z.group()), str(calculate_dual(z.group())),equation) 46 # print(calculate_dual(z.group())) 47 return cl_mul_and_div(t) 48 else: 49 # print("sss",equation) 50 return equation 51 52 53 def cl_add_and_sub(equation): 54 """ 55 计算一个算式中的加减,用正则匹配第一个加或减,计算后替换原来算式,递归后接着算,知道匹配不上加减 56 说明已经算出结果 57 :param equation: 58 :return: 59 """ 60 # print(equation) 61 z = re.search("(-?)[0-9]*.?[0-9]+(+|-)[0-9]*.?[0-9]+",equation) 62 if z: 63 # print(z.group()) 64 t = re.sub(re.escape(z.group()), str(calculate_dual(z.group())),equation) 65 #print(t) 66 return cl_add_and_sub(t) 67 else: 68 return equation 69 70 71 def cl_inner_brackets(p): 72 """ 73 计算在括号里的算式 74 :param p: 75 :return: 76 """ 77 return cl_add_and_sub(cl_mul_and_div(p)) 78 def remove_brackets(s): 79 """ 80 去掉两边的括号 81 :param s: 82 :return: 83 """ 84 #print(s) 85 return re.search("(?<=()[^()]+(?=))", s).group() 86 def chu_li_fu_hao(s): 87 """ 88 处理正负号 89 :param s: 90 :return: 91 """ 92 # print("处理符号前",s) 93 while True: 94 a = re.search("(+-)", s) 95 #print(a) 96 b = re.search("(--)", s) 97 if a: 98 s = re.sub(re.escape(a.group()), "-", s) 99 # print("处理符号后",s) 100 elif b: 101 s = re.sub(re.escape(b.group()), "+", s) 102 # print("处理符号后", s) 103 else: 104 return s 105 temp = "1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))" 106 # temp = "(9-10+5)*3+3-98/(4+99)*3/3+(1*6)" 107 def cl(temp): 108 x = re.search("(()[^()]+())", temp) 109 110 if x: 111 # print("被替换的",x.group()) 112 # print("计算结果", remove_brackets(cl_inner_brackets(x.group()))) 113 t = re.sub(re.escape(x.group()),remove_brackets(cl_inner_brackets(x.group())),temp) 114 115 t = chu_li_fu_hao(t) 116 # print("ass",x) 117 return cl(t) 118 else: 119 if re.search("[+-*/]", temp): 120 # print(temp) 121 w = chu_li_fu_hao(cl_inner_brackets(temp)) 122 return cl(w) 123 else: 124 return temp 125 print("user->",cl(temp)) 126 print("eval->",eval(temp))
Python 递归函数返回值为None的解决办法
https://blog.csdn.net/ha_hha/article/details/79393041
__file__