5.10 包
5.10.1 包的概念
【官网解释】
Packages are a way of structuring Python’s module namespace by using “dotted module names”
包是一种通过使用‘.模块名’来组织python模块名称空间的方式。
具体的:包就是一个包含有__init__.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来
【强调】:
在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块
【创建包时发生的三件事】:
将该包内 __init__py文件加载到内存.
创建一个以该包 命名的名称空间.
通过 包名. 的方式引用__init__里的所有的名字.
5.10.2 import导入
这种方法不常用,但要了解
1 import glance.db.models
2 glance.db.models.register_models('mysql')
示例练习:
import aaa
# 1. 在执行文件写入 import aaa
# 2. aaa的 __init__ 里面 写 from aaa import m1
# 3. 然后在执行文件 aaa.m1.a
# print(aaa.m1.a)
5.10.3 from ... import ...导入
from a.b.c import d
【注意】from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法
from与import 之间的a.b.c 中的b必须是包
# from ... import ...练习
# 通过这种方式不用设置__init__文件
# from aaa import m1
# m1.func()
# from aaa.bbb.m2 import func1 #aaa外包,bbb内包
# func1()
# from aaa.bbb import m2
# m2.func1()
# from a.b.c import d
# c的. 的前面一定是包
# import 的后面一定是名字,并且不能 再有点
【包里嵌包】:如果要把内层包里的模块加到外层__init__里,需要用
from wrapper import inner # wrappe外包名,inner内包名
# 举例
# 如何在当前文件中,引用 aaa包的bbb包.
# 1. 在执行文件写入 import aaa
# 2. aaa的 __init__ 里面 写 from aaa import bbb
# 3. 然后在执行文件 aaa.bbb
# print(aaa.bbb)
# 如何在当前文件中,引用 aaa包的bbb包 的 变量 name.
# 1. 在执行文件写入 import aaa
# 2. aaa的 __init__ 里面 写 from aaa import bbb
# 3. 然后在执行文件 aaa.bbb
# print(aaa.bbb)
# 如何在当前文件中,引用 aaa包的bbb包 的 mb文件的函数func.
# 1. 在执行文件写入 import aaa
# 2. 在aaa包的__init__ 写上 from aaa import bbb (这样写 bbb包的__init__里面所有的名字都能引用)
# print(aaa.bbb.name)
# 3. 在bbb包的__init__ 写上 from aaa.bbb import mb
# aaa.bbb.mb.func3()
5.10.4 绝对导入和相对导入
最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:
绝对导入:以glance作为起始
相对导入:用 . 或者 .. 的方式最为起始(只能在一个包中使用,不能用于不同目录内)
例如:我们在glance/api/version.py中想要导入glance/cmd/manage.py
【总结】
绝对导入与相对导入
# 绝对导入: 以执行文件的sys.path为起始点开始导入,称之为绝对导入
# 优点: 执行文件与被导入的模块中都可以使用
# 缺点: 所有导入都是以sys.path为起始点,导入麻烦
# 相对导入: 参照当前所在文件的文件夹为起始开始查找,称之为相对导入
# 符号: .代表当前所在文件的文件加,..代表上一级文件夹,...代表上一级的上一级文件夹
# 优点: 导入更加简单
# 缺点: 只能在导入包中的模块时才能使用
#注意:
1. 相对导入只能用于包内部模块之间的相互导入,导入者与被导入者都必须存在于一个包内
2. attempted relative import beyond top-level package # 试图在顶级包之外使用相对导入是错误的,言外之意,必须在顶级包内使用相对导入,每增加一个.代表跳到上一级文件夹,而上一级不应该超出顶级包
【注意】当对包的命名进行了更新,但是很多项目已经沿用了老的名称,可以使用import 新名称 as 老名称在项目中起别名,就可以解决
5.11 collection模块
在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
1.namedtuple: 生成可以使用名字来访问元素内容的tuple
2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
3.Counter: 计数器,主要用来计数
4.OrderedDict: 有序字典
5.defaultdict: 带有默认值的字典
# namedtuple 带名称的元组
from collections import namedtuple
point = namedtuple('point',['x','y'])
p = point(1,2)
print(p)
print(p.x)
# deque双端列表
from collections import deque
q = deque([1,2,3,4,5])
q.appendleft('d')
print(q)
q.popleft()
print(q)
# OrderDict 有序字典
from collections import OrderedDict
d = OrderedDict([('1','a'),('2','b'),('3','c')])
print(d)
#counter计数器
from collections import Counter
c = Counter('asdsadgasdasdasfsgfasgf')
print(c) #生成一个字典,里边存放的是每个字母已经弃数量
# defaultdict
# 有如下值集合 [11,22,33,44,55,77,88,99,90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中,即: {'k1': 大于66 , 'k2': 小于66}
#普通版
li = [11,22,33,44,55,77,88,99,90]
result = {}
for row in li:
if row > 66:
if 'key1' not in result:
result['key1'] = []
result['key1'].append(row)
else:
if 'key2' not in result:
result['key2'] = []
result['key2'].append(row)
print(result)
#defaultdict版
from collections import defaultdict
values = [11, 22, 33,44,55,77,88,99,90]
my_dict = defaultdict(list)
for value in values:
if value>66:
my_dict['k1'].append(value)
else:
my_dict['k2'].append(value)
print(my_dict)
5.12 re模块
正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
5.12.1 元字符
元字符
匹配内容
\w
匹配字母(包含中文)或数字或下划线
\W
匹配非字母(包含中文)或数字或下划线
\s
匹配任意的空白符
\S
匹配任意非空白符
\d
匹配数字
\D
p匹配非数字
\A
从字符串开头匹配
\z
匹配字符串的结束,如果是换行,只匹配到换行前的结果
\n
匹配一个换行符
\t
匹配一个制表符
^
匹配字符串的开始
$
匹配字符串的结尾
.
匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
[...]
匹配字符组中的字符
[^...]
匹配除了字符组中的字符的所有字符
*
匹配0个或者多个左边的字符。
+
匹配一个或者多个左边的字符。
?
匹配0个或者1个左边的字符,非贪婪方式。
{n}
精准匹配n个前面的表达式。
{n,m}
匹配n到m次由前面的正则表达式定义的片段,贪婪方式
a|b
匹配a或者b。
()
匹配括号内的表达式,也表示一个组
5.12.2 匹配模式
import re
#单个字符匹配
print(re.findall('\d\d','12a34567890 alex *(_'))
print(re.findall('\w','太白jx 12*() _'))
print(re.findall('\d','1234567890 alex *(_'))
print(re.findall('\Ahel','hello 太白金星 -_- 666'))
print(re.findall('\n','hello \n 太白金星 \t*-_-*\t \n666'))
print(re.findall('.','da\nsdasda\nsdf231\t2314!#!@#!@'))
print(re.findall('hh$','dajqwdadnhhldsdoashhdosasdhh'))
# 元字符匹配
# . 匹配任意一个字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符
print(re.findall('a.b','ab aacb a*b a2b a牛ab a\nb')) #以a开头,以b结尾中间必须有一个字符
print(re.findall('a..b','ab aacb a*b a2b a牛ab a\nb',re.DOTALL)) #以a开头,以b结尾中间必须有两个字符
# ?匹配0个或1个由左边字符定义的片段
print(re.findall('a?b', 'ab aab abb aaaab a牛b aba**b')) #要么有一个a要么没有a
# * 匹配0个或多个左边字符表达式,满足贪婪算法
print(re.findall('a*b','ab aab aaab abbbbb')) #以b结尾,前边有多少个a都无所谓
print(re.findall('ab*','ab cacacb aaab abbbbb')) #比较前后两个字符,必须要以a开头,结尾可以是1个或者0个b
print(re.findall('b*','ab aab aaab abbbbb')) #一个字符一个字符的比较,是b输出,不是b跳过
# + 匹配1个或者多个左边字符的表达式,满足贪婪算法
print(re.findall('a+b',' b ab aab acaab aaab abbb')) #以b结尾,前边可以有一个甚至多个a
print(re.findall('ca+b',' cb ab aab acaab aaab cabbb')) #以b结尾,前边可以有一个甚至多个ca组合
print(re.findall('a+bc',' cbc abc aabc acaab aaab cabbbc')) #以bc结尾,前边可以有一个甚至多个a组
# {n,m}匹配n个至m个左边字符表达式,满足贪婪算法
print(re.findall('a{2,4}b','ab aab aaab aaaaabb'))
# .* 组合,贪婪匹配,从头到尾
print(re.findall('a.*b','ab aab a*()b aasbdsdsdsb')) #以a开头,以b结尾,中间可以有任意字符,ab中间如果还有ab以最外层的ab为准
# .*? 此时的?不是对左边的字符进行0次或者1次的匹配,
# 而只是针对.*这种贪婪匹配的模式进行一种限定:告知他要遵从非贪婪匹配 推荐使用!
print(re.findall('a.*?b','ab aab a*()b aasbdsadsdsb'))
# 练习,寻找_zs结尾的元素
s = '皇子_zs 赵信_zs 盖伦_zs 凯特琳_adc 慎_rz'
print(re.findall('\w*_zs',s))
print(re.findall('\w+_zs',s))
#输出时间
s1 = '''
时间就是1995-04-27,2005-04-27
1999-04-27 德玛西亚
赵信 1980-04-27:1980-04-27
2018-12-08
'''
print(re.findall('\d{4}-\d{2}-\d{2}',s1))
# 匹配一个qq账号 10000开始 第一个元素规定就是非零数字,后面的是随意的数字长度大于5位.
print(re.findall('[1-9][0-9]{4,}','12335345 3453453453 45345123123 0432040320 4324'))
5.12.3 重要语法
re 的匹配语法
re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中,返回列表
re.split 以匹配到的字符当作列表分隔符
re.sub 匹配字符以替换
re.fullmatch 全部匹配
re.match (pattern,string,flages = 0)
从起始位置开始根据模型去字符串中匹配指定的内容,匹配单个
pattern 正则表达式
string 要匹配的字符串
flags 标志位,用于控制正则表达式的匹配了方式
falgs标志位
re.I(re.IGNORECASE)忽略大小写(括号内是完整写法,下同)
M(MULTILINE):多行模式,改变'^'和'$'的行为
S(DOALL):改变 . 的行为,make the '.' special character match any character at all ,including a newline ;without this flag, '.' will match anthing except a newline.
x(re.VERBOSE) 给表达式写注释,使其更可读
re.search(pattern,string,flags = 0)
根据模型去字符串中匹配指定的内容,匹配单个
re.findall(pattern,string,flags=0)
匹配字符串中所有符合条件的元素
re.sub( pattern, repl, string, counts=0, flags=0)
用于替换匹配的字符串,相比于str.replace功能更强大
re.split( pattern, string, maxsplit=0, flags=0)
支持多字符切割,而str.split只支持单字符切割且不感知空格的数量
re.fullmatch(pattern,string,flags=0)
整个字符串匹配成功就返回re object ,否则返回None
5.12.3 重要语法
re 的匹配语法
re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中,返回列表
re.split 以匹配到的字符当作列表分隔符
re.sub 匹配字符以替换
re.fullmatch 全部匹配
re.match (pattern,string,flages = 0)
从起始位置开始根据模型去字符串中匹配指定的内容,匹配单个
pattern 正则表达式
string 要匹配的字符串
flags 标志位,用于控制正则表达式的匹配了方式
falgs标志位
re.I(re.IGNORECASE)忽略大小写(括号内是完整写法,下同)
M(MULTILINE):多行模式,改变'^'和'$'的行为
S(DOALL):改变 . 的行为,make the '.' special character match any character at all ,including a newline ;without this flag, '.' will match anthing except a newline.
x(re.VERBOSE) 给表达式写注释,使其更可读
re.search(pattern,string,flags = 0)
根据模型去字符串中匹配指定的内容,匹配单个
re.findall(pattern,string,flags=0)
匹配字符串中所有符合条件的元素
re.sub( pattern, repl, string, counts=0, flags=0)
用于替换匹配的字符串,相比于str.replace功能更强大
re.split( pattern, string, maxsplit=0, flags=0)
支持多字符切割,而str.split只支持单字符切割且不感知空格的数量
re.fullmatch(pattern,string,flags=0)
整个字符串匹配成功就返回re object ,否则返回None