Python递归、内置模块、正则表达式
-
一、递归函数
# 递归函数之二分查找算法,有序的数字集合的查找问题 lst = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48] def func(lst,num,start=0,end=None): end = len(lst) - 1 if end is None else end if start > end: return None mid = (end - start) // 2 + start if lst[mid] > num: return func(lst, num, start, mid - 1) elif lst[mid] < num: return func(lst, num, mid + 1, end) else: return mid print(func(lst,2)) # 解析 def func(lst,2,start=0,end=None): end = 24 if 0 > 24: return None mid = 12 if lst[12] > 0: return func(lst, 2, 0, 11) # def func(lst,2,start=0,end=11): end = 11 if 0 > 11: return None mid = 5 if lst[5] > num: return func(lst, 2, 0, 4) def func(lst,2,start=0,end=4): end = 4 if 0 > 4: return None mid = 2 if lst[2] > num: return func(lst, 2, 0, 1) def func(lst,2,start=0,end=1): end = 1 if 0 > 1: return None mid = 0 if lst[mid] > num: return func(lst, num, start, mid - 1) elif lst[0] < 2: return func(lst, 2, 1, 1) else: return mid def func(lst,2,start=1,end=1): end = 1 if 0 > 1: return None mid = 1 if lst[mid] > num: return func(lst, num, start, mid - 1) elif lst[mid] < num: return func(lst, num, mid + 1, end) else: return 1 # 匹配成功
menu = { '北京': { '海淀': { '五道口': { 'soho': {}, '网易': {}, 'google': {} }, '中关村': { '爱奇艺': {}, '汽车之家': {}, 'youku': {}, }, '上地': { '百度': {}, }, }, '昌平': { '沙河': { '老男孩': {}, '北航': {}, }, '天通苑': {}, '回龙观': {}, }, '朝阳': {}, '东城': {}, }, '上海': { '闵行': { "人民广场": { '炸鸡店': {} } }, '闸北': { '火车战': { '携程': {} } }, '浦东': {}, }, '山东': {}, }
current_layer = menu # 当前层 last_layer = [] # 上一层 while True: for k in current_layer:print(k) choice = input(">>>:").strip() if not choice:continue if choice in current_layer: last_layer.append(current_layer) current_layer = current_layer[choice] elif choice.lower() == "b": if len(last_layer) == 0: print("ERROR:已经到顶层") continue current_layer = last_layer.pop() elif choice.lower() == "q": break else: print("ERROR:节点不存在")
def func(dic): while True: for k in dic: print(k) choice = input(">>>:").strip() if not choice:continue # 当choice等于b的时候结束当前递归对应次数的函数 if choice.lower() == "b":return # 当choice等于q的时候返回一个q进行判断。 if choice.lower() == "q":return "q" if choice in dic: res = func(dic[choice]) # 如果返回值为q,则回溯到函数结束 if res == "q":return "q" else: print("ERROR:节点不存在") func(menu)
-
二、模块
# 模块的定义 # 模块就是py文件 # 模块是写好了但不直接使用的功能代码 # 导入模块的方法 import time # 导入整个time模块 import time,os # 导入多个模块 from time import sleep # 导入time模块的sleep方法 from time import sleep,time # 导入time模块的多个方法 # print() len() 这些模块为什么不需要导入也可以使用? # python启动默认会加载一些必备模块到内存中,如果去掉这些模块会影响python的编程方式 # 为什么不在python启动的时候把所有模块都加载到内存中? # 模块是有大小的,如果全部加载到内存中会把内存撑爆 # 模块分为三种: 内置模块 扩展模块 自定义模块
1、内置模块
#!/usr/bin/env python3 # 内置模块 # collections 在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的 # 数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。 import collections # 1.namedtuple: 生成可以使用名字来访问元素内容的tuple # point = collections.namedtuple("point", ["x", "y"]) # res = point(100, 50) # print(res.x) # print(res.y) # 2.deque: 双端队列,可以快速的从另外一侧追加和推出对象 不常用 # 使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。 # deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈: # deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。 # lst = collections.deque(["a", "b", "c"]) # lst.append("e") # lst.appendleft(1) # lst.popleft() # print(lst) # 3.Counter: 计数器,主要用来计数 # Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似 # c = collections.Counter("abcdeabcdabcaba") # print(c) # 输出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1}) # 4.OrderedDict: 有序字典 不常用 # OrderedDict的Key是有序的,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序: # dic = collections.OrderedDict([["a", 1], ["b", 1]]) # print(dic) # 5.defaultdict: 带有默认值的字典 # lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 元素大于5的添加到字典k1的列表中,元素小于5的添加字典k2的列表中 # lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 原生字典解决方法 # dic1 = {} # for i in lst: # if i > 5: # if dic1.get("k1"): # dic1["k1"].append(i) # else: # dic1["k1"] = [] # dic1["k1"].append(i) # else: # if dic1.get("k2"): # dic1["k2"].append(i) # else: # dic1["k2"] = [] # dic1["k2"].append(i) # print(dic1) # 默认值字典解决方法 # dic2 = collections.defaultdict(list) # for i in lst: # if i > 5:dic2["k1"].append(i) # else:dic2["k2"].append(i) # print(dic2)
import time # 时间的3种格式 # 1、时间戳timestamp(机器识别),时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。 print(time.time()) # 2、元组struct_time(可操作类型),struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天等) print(time.gmtime()) # 英国伦敦格林尼治时间 print(time.localtime()) # 本地时间,即中国北京时间 # 3、字符串格式化Format String (人类可以看懂的) 例如:1991-03-22 print(time.strftime("%Y-%m-%d %H:%M:%S")) print(time.strftime("%y-%m-%d %H:%M:%S %a %A %b %B")) print(time.strftime("%c")) print(time.strftime("%x %X")) print(time.strftime("%j")) print(time.strftime("%U")) print(time.strftime("%Z")) # %y 两位数的年份表示(00-99) # %Y 四位数的年份表示(000-9999) # %m 月份(01-12) # %d 月内中的一天(0-31) # %H 24小时制小时数(0-23) # %I 12小时制小时数(01-12) # %M 分钟数(00=59) # %S 秒(00-59) # %a 本地简化星期名称 # %A 本地完整星期名称 # %b 本地简化的月份名称 # %B 本地完整的月份名称 # %c 本地相应的日期表示和时间表示 # %j 年内的一天(001-366) # %p 本地A.M.或P.M.的等价符 # %U 一年中的星期数(00-53)星期天为星期的开始 # %w 星期(0-6),星期天为星期的开始 # %W 一年中的星期数(00-53)星期一为星期的开始 # %x 本地相应的日期表示 # %X 本地相应的时间表示 # %Z 当前时区的名称 # %% %号本身 # 时间格式之间的转换 # 时间戳 ---> 元组格式 struct = time.localtime(1500000) # 把时间戳1500000 转成 北京时间的元组格式 print(struct) struct1 = time.localtime(1500000) # 把时间戳1500000 转成 格林尼治时间的元组格式 print(struct1) struct2 = time.localtime() # 把当前时间转成北京时间的元组格式 print(struct2) # 元组格式---> 时间戳 struct = time.localtime(1500000) time_stamp = time.mktime(struct) print(time_stamp) # 元组格式 ---> 字符串格式 struct = time.localtime() # 定义一个元组格式的时间 str_time = time.strftime("%Y-%m-%d", struct) print(str_time) struct = time.localtime(15000000) # 指定一个元组格式的固定时间 str_time = time.strftime("%Y-%m-%d", struct) print(str_time) # 字符串格式 ---> 元组格式 time.strptime(时间字符串,字符串对应格式) str_time = time.strftime("%Y-%m-%d") struct = time.strptime(str_time, "%Y-%m-%d") print(struct) # 其他 #结构化时间 --> %a %b %d %H:%M:%S %Y串 #time.asctime(结构化时间) 如果不传参数,直接返回当前时间的格式化串 asc_time = time.asctime(time.localtime()) print(asc_time) #时间戳 --> %a %d %d %H:%M:%S %Y串 #time.ctime(时间戳) 如果不传参数,直接返回当前时间的格式化串 ct_time = time.ctime(time.time()) print(ct_time)
# 练习题: 计算时间差 import time true_time=time.mktime(time.strptime('2017-09-11 08:30:00','%Y-%m-%d %H:%M:%S')) # 把字符串转成时间戳格式 time_now=time.mktime(time.strptime('2017-09-12 11:00:00','%Y-%m-%d %H:%M:%S')) # 把字符串转成时间戳格式 dif_time=time_now-true_time # 获取相隔时间戳 struct_time=time.localtime(dif_time) # 时间戳转换成元组格式 print(struct_time) print(time.localtime()) print('过去了%d年%d月%d天%d小时%d分钟%d秒'%(struct_time.tm_year-1970,struct_time.tm_mon-1, struct_time.tm_mday-1,struct_time.tm_hour, struct_time.tm_min,struct_time.tm_sec)) # 计算时间差 last_time = "1991-05-06" last_time_struct = time.strptime(last_time, "%Y-%m-%d") current_time = time.localtime() # time.gmtime() print("距离今天%s年%s月%s日%s时%s分%s秒" % (current_time[0] - last_time_struct[0],current_time[1] - last_time_struct[1],current_time[2] - last_time_struct[2],current_time[3] - last_time_struct[3],current_time[4] - last_time_struct[4],current_time[5] - last_time_struct[5])) print(last_time_struct) print(current_time)
# random 随机数 import random # random 随机小数 print(random.random()) # 0 - 1之间随机小数 # uniform 随机范围小数 print(random.uniform(1, 4)) # 1 - 4 之间随机小数 # 随机整数 # randint 随机范围内整数 print(random.randint(1, 10)) # randrange 随机范围内的奇数 print(random.randrange(1, 10, 2)) # choice 随机一个返回值 print(random.choice([1, 2, 3, 4, 5])) # sample 随机多个返回值 print(random.sample([1, 2, 3, 4, 5], 2)) # shuffle 打乱顺序 lst = [1, 2, 3, 4, 5] random.shuffle(lst) print(lst)
import random def func(num): """ 随机验证码包含大小写字母数字 :param num: 验证码位数 :return: """ code = "" for i in range(num): digit = str(random.randint(0, 9)) letter = chr(random.randint(65, 90)) capital = chr(random.randint(97, 122)) rdom = random.choice([digit, letter, capital]) code += rdom return code print(func(6))
import sys # sys模块是与python解释器交互的一个接口 # sys.argv 命令行参数List,第一个元素是程序本身路径 print(sys.argv) # sys.exit(n) 退出程序,正常退出时exit(0),错误退出sys.exit(1) # sys.version 获取Python解释程序的版本信息 print(sys.version) # sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 print(sys.path) # sys.platform 返回操作系统平台名称 print(sys.platform) # sys.modules 放了所有在解释器运行的过程中导入的模块名 print(sys.modules)
# os模块是与操作系统交互的一个接口 import os # os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 print(os.getcwd()) # os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd # os.chdir(r'F:') # os.chdir(r"F:\3.4") print(os.getcwd()) # os.curdir 返回当前目录: ('.') 基本无用 # os.pardir 获取当前目录的父目录字符串名:('..') 基本无用 # os.makedirs('dirname1/dirname2') 可生成多层递归目录 # os.makedirs(r"c:\a\b\c") os.makedirs(r"c:\a\b\c", exist_ok=True) # os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 # os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname # os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname # os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 # os.remove() 删除一个文件 # os.rename("oldname","newname") 重命名文件/目录 # os.stat('path/filename') 获取文件/目录信息 print(os.stat(r"C:\Users\lanpa\Desktop\蓝帕(北京)科技股份有限公司\172.3.0.23.pdf")) # os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/" print(os.sep) # os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" print(os.linesep) # os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为: print(os.pathsep) # os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' print(os.name) # os.system("bash command") 运行shell命令,直接显示 os.system("dir") # os.popen("bash command).read() 运行shell命令,获取执行结果 res = os.popen("dir").read() print(res) # os.environ 获取系统环境变量 print(os.environ) # # os.path # 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)的第二个元素 print(os.path.abspath("__init__.py")) # os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False print(os.path.exists(r"d:")) print(os.path.exists(r"C:\Users\lanpa\Desktop\Python自动化21期\Python21\day")) # os.path.isabs(path) 如果path是绝对路径,返回True print(os.path.isabs(r"../day5")) # os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False print(os.path.isfile(r"../day5/__init__.py")) # os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False print(os.path.isdir(r"../day5")) # os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 print(os.path.join(r"C:\Users\lanpa", r"day3", r"day2")) # os.path.getatime(path) 返回path所指向的文件或者目录的最后访问时 import time print(os.path.getatime(r"C:\Users\lanpa\Desktop\Python自动化21期\Python21\day5\__init__.py")) print(time.strftime("%x %X", time.gmtime(os.path.getatime(r"C:\Users\lanpa\Desktop\Python自动化21期\Python21\day5\__init__.py")))) # os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间 print(os.path.getmtime(r"C:\Users\lanpa\Desktop\Python自动化21期\Python21\day5\__init__.py")) print(time.strftime("%x %X", time.gmtime(os.path.getmtime(r"C:\Users\lanpa\Desktop\Python自动化21期\Python21\day5\__init__.py")))) # os.path.getsize(path) 返回path的大小 print(os.path.getsize(r"C:\Users\lanpa\Desktop\Python自动化21期\Python21\day5\__init__.py")) print(os.path.getsize(r"C:\Users\lanpa\Desktop\Python自动化21期\Python21\day5"))
import os print("*" * 50) sums = 0 def func(dirs): if os.path.exists(dirs): dir_list = os.listdir(dirs) global sums for i in dir_list: if os.path.isdir(os.path.join(dirs, i)): func(os.path.join(dirs, i)) else: sums += os.path.getsize(os.path.join(dirs, i)) return sums else: return None print(func("../day5"))
''' os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd os.curdir 返回当前目录: ('.') os.pardir 获取当前目录的父目录字符串名:('..') os.makedirs('dirname1/dirname2') 可生成多层递归目录 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 os.remove() 删除一个文件 os.rename("oldname","newname") 重命名文件/目录 os.stat('path/filename') 获取文件/目录信息 os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/" os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为: os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' os.system("bash command") 运行shell命令,直接显示 os.popen("bash command).read() 运行shell命令,获取执行结果 os.environ 获取系统环境变量 os.path 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所指向的文件或者目录的最后修改时间 os.path.getsize(path) 返回path的大小 '''
os.stat('path/filename') 获取文件/目录信息 的结构说明
stat 结构: st_mode: inode 保护模式 st_ino: inode 节点号。 st_dev: inode 驻留的设备。 st_nlink: inode 的链接数。 st_uid: 所有者的用户ID。 st_gid: 所有者的组ID。 st_size: 普通文件以字节为单位的大小;包含等待某些特殊文件的数据。 st_atime: 上次访问的时间。 st_mtime: 最后一次修改的时间。 st_ctime: 由操作系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,在其它系统上(如Windows)是创建时间(详细信息参见平台的文档)。
元组(struct_time) :struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天等)
几种格式之间的转换
-
三、正则表达式
- 正则表达式在线测试地址:http://tool.chinaz.com/regex/
- 参考博客:http://www.cnblogs.com/Eva-J/articles/7228075.html#_label10
-
首先你要知道的是,谈到正则,就只和字符串相关了。在我给你提供的工具中,你输入的每一个字都是一个字符串。
其次,如果在一个位置的一个值,不会出现什么变化,那么是不需要规则的。
比如你要用"1"去匹配"1",或者用"2"去匹配"2",直接就可以匹配上。这连python的字符串操作都可以轻松做到。
那么在之后我们更多要考虑的是在同一个位置上可以出现的字符的范围。 -
字符组 : [字符组] 在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示 字符分为很多类,比如数字、字母、标点等等。 假如你现在要求一个位置"只能出现一个数字",那么这个位置上的字符只能是0、1、2...9这10个数之一。
-
字符
- 正则表达式在线测试地址:http://tool.chinaz.com/regex/
-
- 量词
-
- re模块常用方法
import re ret = re.findall('a', 'eva egon yuan') # 返回所有满足匹配条件的结果,放在列表里 print(ret) #结果 : ['a', 'a'] ret = re.search('a', 'eva egon yuan').group() print(ret) #结果 : 'a' # 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 ret = re.match('a', 'abc').group() # 同search,不过尽在字符串开始处进行匹配 print(ret) #结果 : 'a' ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割 print(ret) # ['', '', 'cd'] ret = re.sub('\d', 'H', 'eva3egon4yuan4', 1)#将数字替换成'H',参数1表示只替换1个 print(ret) #evaHegon4yuan4 ret = re.subn('\d', 'H', 'eva3egon4yuan4')#将数字替换成'H',返回元组(替换的结果,替换了多少次) print(ret) obj = re.compile('\d{3}') #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字 ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串 print(ret.group()) #结果 : 123 import re ret = re.finditer('\d', 'ds3sy4784a') #finditer返回一个存放匹配结果的迭代器 print(ret) # <callable_iterator object at 0x10195f940> print(next(ret).group()) #查看第一个结果 print(next(ret).group()) #查看第二个结果 print([i.group() for i in ret]) #查看剩余的左右结果
-
- findall的优先级查询:
import re ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['www.oldboy.com']
-
- split的优先级查询
ret=re.split("\d+","eva3egon4yuan") print(ret) #结果 : ['eva', 'egon', 'yuan'] ret=re.split("(\d+)","eva3egon4yuan") print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan'] #在匹配部分加上()之后所切出的结果是不同的, #没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项, #这个在某些需要保留匹配部分的使用过程是非常重要的。