包、相对导入和绝对导入、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()

 

posted @ 2019-01-10 14:48  星满夜空  阅读(594)  评论(0编辑  收藏  举报