包、相对导入和绝对导入、random模块、解压缩
一. 包,也是一种模块
函数多了,可以分模块文件去管理
模块多了,可以将模块分类,放在一个个文件夹中,这些文件夹就是包
为的是使组织机构更加合理清晰
模块本来就是拿来用的,而包是一些模块的集合,因此它也是被调用的
文件:
1.被别人使用
2.当作脚本自己使用
执行文件运行时,会将执行文件当前目录加载到sys.path列表中
import sys print(666) print(sys.path) # 666 # ['C:\\Users\\Shawn_Huang\\Desktop\\ATM' # 'C:\\Users\\Shawn_Huang\\Desktop\\ATM', # 'D:\\Python36\\python36.zip', 'D:\\Python36\\DLLs', # 'D:\\Python36\\lib', 'D:\\Python36', 'D:\\Python36\\lib\\site-packages', # 'E:\\PyCharm 2018.3.1\\helpers\\pycharm_matplotlib_backend'] # 这里列表中的第一个元素就是执行文件当前目录
回顾,执行一个模块会发生三件事:
1.在内存中创建一个以模块名命名的临时名称空间
2.执行模块代码,将模块里面的代码加载到以模块名命名的临时名称空间
3.调用模块内的名字必须通过模块名. 的方式调用
因为包也是模块,是模块的集合体,因此import 一个包名,也会发生三件事:
1.内存中创建一个以包名命名的名称空间
2.执行包中的 __init__ 文件,将 __init__ 里面的代码块加载到以包名命名的名称空间
3.调用包内的名字必须通过包名. 的方式调用
# 假设有一个包,名为aaa,则在包aaa的 __init__ 文件中创建一个变量x,并给它赋值 # 在本文件中,可以这样调用: # 这里能直接引用aaa,是因为本文件与 aaa 这个包在同一个目录下 import aaa # 执行 __init__ 文件里的内容 print(aaa.x) # 如果 aaa 包里又有另一个 m2.py 文件,怎么办? import sys print(sys.path) # ['C:\\Users\\Shawn_Huang\\Desktop\\ATM', # 'C:\\Users\\Shawn_Huang\\Desktop\\ATM', # 'D:\\Python36\\python36.zip', 'D:\\Python36\\DLLs', # 'D:\\Python36\\lib', 'D:\\Python36', 'D:\\Python36\\lib\\site-packages', # 'E:\\PyCharm 2018.3.1\\helpers\\pycharm_matplotlib_backend'] # 这里 aaa 在这个 path 里面,但是 aaa 里面的 m2 不在这个 path 里 # 因此在 __init__ 里面添加: from aaa import m2 # 这样的话就可以在本文件里这样: import aaa print(aaa.m2) # 这样就会引用 m2 文件里的所有内容 # <module 'aaa.m2' from 'C:\\Users\\Shawn_Huang\\Desktop\\ATM\\aaa\\m2.py'> print(aaa.m2.s1) # 这里可以被调用
# 如果 aaa 包里还有很多文件,要想调用它,则可以在 __init__ 里面这样写
# from aaa import *
import aaa # 如果 aaa 包里还有一个 bbb 包,为了在本文件引用它 # 应该在 __init__ 文件里加: from aaa import bbb # 引用 包 bbb 里的 __init__ 文件的 s2 变量,可以这样: print(aaa.bbb.s2) # 包bbb的 __init__ 文件内容在这里 # 如果包 bbb 里面又有一个m3.py文件,要引用这个文件的内容,按照以下步骤: # 1.在本文件 import aaa # 2.在 aaa 包的 __init__ 文件这样写: from aaa import bbb # 3.在 bbb 包的 __init__ 文件这样写: from aaa.bbb import m3 print(aaa.bbb.m3.s3) # 包 bbb 内的 m3 文件内容在这里 # 上面三步只是为了了解过程,真正程序中可以这样写:—— 直接在本文件中写 from aaa.bbb import m3 print(m3.s3) # 包 bbb 内的 m3 文件内容在这里 # 一定要记住:本文件是执行文件,因此在 sys.path 里面会把它所在的目录添加进去 # 而 aaa 这个包跟本文件在同一个文件夹内,即同一个目录,因此可以直接引用 aaa 的 __init__ 文件 # 总结 # 1. from a.b import c .的左边一定是个包,import后面一定有个具体的名字 # 2. 包里面的 __init__ 文件想要引用模块必须是from...import... 只有在执行文件里直接写 import,而包是被引用的,不能直接 import # 3.from a.b.c.d import e.f.g 错误,import 后面必须只有一个,应该把 .f.g 去掉后才行
# 相对导入,绝对导入 # 假设与本文件同目录有个nb.py,内容是这样: def f1(): print("111") def f2(): print("222") def f3(): print("333") # 在本文件是这样引用的: import nb # 但是,如果随着代码更新,nb模块又增加了一百个函数,放在一个文件肯定不行,要分文件 # 这时要注意,假如分文件时不能改变调用这个模块的调用方式 # 这时py文件就应该改为一个包,然后在这个包里创建比如 m1, m2, m3文件,里面放内容 # 如果只能以下这样调用,怎么改? import nb nb.f1() # 111 nb.f2() # 222 nb.f3() # 333 nb.f4() # 444 nb.f5() # 555 nb.f6() # 666 # 在nb 的 __init__ 里面这样写:—— 这是绝对导入 from nb.m1 import f1, f2 from nb.m2 import f3, f4 from nb.m3 import f5, f6 # 但是如果 nb 这里包必须改名,可以直接把 nb 包复制一份,包名重命名为 NB1, # 然后在 NB1 的 __init__ 文件里这样写:—— 相对导入 from .m1 import f1, f2 from .m2 import f3, f4 from .m3 import f5, f6
绝对导入与相对导入总结
绝对导入: 以执行文件的sys.path为起始点开始导入,称之为绝对导入
优点: 执行文件与被导入的模块中都可以使用
缺点: 所有导入都是以sys.path为起始点,导入麻烦
相对导入: 参照当前所在文件的文件夹为起始开始查找,称之为相对导入符号:
.代表当前所在文件的文件夹
..代表上一级文件夹
...代表上一级的上一级文件夹
优点: 导入更加简单
缺点: 只能在导入包中的模块时才能使用
# 二. random 模块 随机模块 import random print(random.random()) # 大于0小于1之间的随机一个小数 print(random.uniform(1, 3)) # 1-3之间的所有小数中的随机一个 print(random.randint(1, 5)) # 1-5之间的整数,包括1和5 print(random.randrange(1, 10, 2)) # 10以内的奇数的随机一个 print(random.choice(["alex", "wusir", "日天"])) # 多选一, choice()里面必须是容器类数据类型 print(random.sample(["alex", "wusir", "日天", "太白"], 2)) # 多选多 l1 = [1, 2, 3, 4, 5] random.shuffle(l1) print(l1) # 对原列表打乱顺序
# 生成随机验证码 # 5个字符(包含0-9的数字,a-z的小写字母) # 思路:验证码肯定是字符串形式 # 0-9 random.randrange(10) # a-z 利用小写字母对应的ascii来写 [chr[i] for i in range(97, 123)] # 二选一个字符 # print(random.randrange(10)) # print([chr(i) for i in range(97, 123)]) def get_code(): code = "" for i in range(5): num = str(random.randrange(10)) s = chr(random.randint(97, 122)) # 下面加个大写字母 s1 = chr(random.randint(65, 90)) single_s = random.choice([num, s, s1]) code += single_s return code print(get_code())
# shutil模块 # 高级的 文件、文件夹、压缩包 处理模块 # shutil.copyfileobj(fsrc, fdst[, length]) # 将文件内容拷贝到另一个文件中: import shutil shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w')) # shutil.copyfile(src, dst) # 拷贝文件 shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在 # shutil.copymode(src, dst) # 仅拷贝权限。内容、组、用户均不变 shutil.copymode('f1.log', 'f2.log') #目标文件必须存在 # shutil.ignore_patterns(*patterns) shutil.copytree(src, dst, symlinks=False, ignore=None) # 递归的去拷贝文件夹 # import shutil shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除
# 打包与压缩 import shutil import time import tarfile # 同一个文件夹下,直接写 "NB1_bak%s", 不在同一个文件夹写清路径 # 然后如果压缩至同一个文件夹下,"gztar" 后面不用写 root_dir="路径",反之则反 shutil.make_archive("NB1_bak%s" % time.strftime("%Y-%m-%d"), "gztar",) # 解压 t = tarfile.open("NB1_bak2019-01-10.tar.gz", "r") t.extractall("这是新创的文件夹名字") t.close()