day5(老男孩-Python3.5-S14期全栈开发)

作者:赵俊            发布日期: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:\Python\Project"))  # 改变当前脚本的工作目录
 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:\Python\Project\Day5")) #获取文件或目录信息
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:\Python\Project\123.txt")))  # 路径所指文件或目录的最后访问时间
31 print(time.ctime(os.path.getmtime(r"F:\Python\Project\123.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:\Python\Project\路径测试
13 # sys.argv[0]返回路径----- F:/Python/Project/路径测试/test.py
14 # os.getcwd()返回路径----- F:\Python\Project\路径测试
15 # __file__返回路径----- F:\Python\Project\路径测试\ad\sss\t.py
16 # os.path.abspath('.')返回路径----- F:\Python\Project\路径测试
17 # 自己执行结果
18 # sys.path[0]返回路径----- F:\Python\Project\路径测试\ad\sss
19 # sys.argv[0]返回路径----- F:/Python/Project/路径测试/ad/sss/t.py
20 # os.getcwd()返回路径----- F:\Python\Project\路径测试\ad\sss
21 # __file__返回路径----- F:/Python/Project/路径测试/ad/sss/t.py
22 # os.path.abspath('.')返回路径----- F:\Python\Project\路径测试\ad\sss

根据上面的执行结果,可以看出使用__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( )会将标准输入全部获取,包括末尾的'\n',
19 因此用len计算长度时是把换行符'\n'算进去了的,但是input( )获取输入时返回的结果是不包含末尾的换行符'\n'的。
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:\Python\Project\Day4") # 指定文件所在目录的所有文件打包

  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 '.'     默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
 2 '^'     匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
 3 '$'     匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",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 '\Z'    匹配字符结尾,同$
15 '\d'    匹配数字0-9
16 '\D'    匹配非数字
17 '\w'    匹配[A-Za-z0-9]
18 '\W'    匹配非[A-Za-z0-9]
19 's'     匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
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. 用户输入 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__
posted @ 2020-09-03 21:34  daban2009  阅读(309)  评论(0编辑  收藏  举报