常用模块>包

序列化模块
序列
  • 列表
  • 元组
  • 字符串
  • bytes
什么叫序列化
  • 把一个数据类型转换成 字符串、byets类型的过程就是序列化
为什么要把一个数据类型序列化?
  • 当你需要把一个数据类型存储在文件中
  • 当你需要把一个数据类型通过网络传输的时候
  • json模块
    • Json模块提供了四个功能:dumps、dump、loads、load
import json
stu = {'name':'何青松','sex':'male'}
ret = json.dumps(stu)  # 序列化的过程,将一个字典转换成一个字符串
print(stu,type(stu))
print(ret,type(ret))

d = json.loads(ret)    # 反序列化的过程,将一个字符串格式的字典转换成一个字典
print('d-->',d,type(d))
  • dump、load 和文件打交道
  • 可以多次向一个文件dump,但load的时候会报错
  • 定义一个函数调用函数输入多个类型
def func(dic):
    with open('json_file','a',encoding='utf-8') as f:
        res = json.dumps(dic,ensure_ascii=False)
        f.write('%s\n'%res)

dic = {'k1':'v1','k2':'v2','k3':'何青松'}
func(dic)
import json
f = open('json_file','w')
dic = {'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f)  #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
f.close()

f = open('json_file')
dic2 = json.load(f)  #load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
f.close()
print(type(dic2),dic2)
import json
data = {'username':['李华','二愣子'],'sex':'male','age':16}
json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False)#sort_keys,字符编码排序 #indent=2默认换行空格# separators格式化
print(json_dic2)
json的优点
  • 所有的语言都通用
缺点
  • 只支持非常少的数据类型
  • 对数据类型的约束很苛刻
    • 字典的key必须是字符串
    • 只支持 : 数字 字符串 列表 字典(不支持元祖)
  • dumps(dic/list) dic/list --> 序列化方法

  • loads(str) str -->dic/list 反序列化方法

  • dump(dic/list,f) dic/list -->文件写入,序列化方法

  • load(f) 文件 -->dic/list 反序列方法

  • 参数:ensure_ascii = False 希望序列化的中文能以中文形式显示

  • pickle模块

  • pickle模块提供了四个功能:dumps、dump(序列化,存)、loads(反序列化,读)、load (不仅可以序列化字典,列表...可以把python中任意的数据类型序列化

import pickle
stu = {'name':'何青松','sex':'male',1:('a','b')}
ret = pickle.dumps(stu)
print(ret)
d = pickle.loads(ret)
print(d,type(d))
class Course():
    def __init__(self,name,price):
        self.name = name
        self.price = price

python = Course('python',29800)
ret = pickle.dumps(python)
print(ret)

p = pickle.loads(ret)
print(p.name,p.price)
import pickle
class Course():
    def __init__(self,name,price):
        self.name = name
        self.price = price

python = Course('python',29800)
linux = Course('linux',25800)
mysql = Course('mysql',18000)
ret = pickle.dumps(python)
print(ret)

p = pickle.loads(ret)
print(p.name,p.price)

with open('pickle_file','wb') as f:
    pickle.dump(python,f)

with open('pickle_file','rb') as f:
    course = pickle.load(f)
print(course.name)
pickle
    dump
    load
        操作文件文件必须以+b打开
    在load的时候 如果这个要被load的内容所在的类不在内存中,会报错
    pickle支持多次dump和多次load(需要异常处理)
pickle 能不能多次 dump
总结:
内置方法
    __new__ :
        构造方法,在对象实例化的时候帮助对象开辟一块儿空间
        __new__ 比init先执行
        单例模式
    __del__: 析构方法
        删除一个对象之前调用
    __eq__ : obj1 == obj2  obj1.__eq__(obj2)
    __len__:len(obj)
    __hash__:# 一种算法,把一个对象转换成一个数字
        字典的一次寻址
        set去重
模块
    三种:
        内置模块
        第三方模块
        自定义模块
    序列化模块 把数据类型 -->  str、bytes
        数据的持久化存储 :文件存储
        数据的网络传输
        json
            所有语言都支持
            支持的数据类型有限
        pickle
            只有python语言支持
            支持几乎所有的数据类型
时间模块

import time

  • 时间模块
  • 三种格式
    • 时间戳时间 浮点数 秒为单位
      1970.1.1 0:0:0 英国伦敦时间
    • 结构化时间 元组
    • 格式化时间 str数据类型的
import time
print(time.localtime())  #显示结构化时间  得到的是北京时间 开始于1970-1-1  8:0:0
print(time.gmtime()) #得到的是伦敦时间  开始于1970-1-1  0:0:0
print(time.time())    #显示时间戳
print(time.strftime('%Y-%m-%d %X'))  #显示格式化时间
print(time.strptime('2018-8-8','%Y-%m-%d'))  # 转化格式化时间到结构化时间

计算本月1号的时间戳时间

import  time
def get_timestamp():
    time1 = time.strftime('%Y-%m-1')
    time2 = time.strptime(time1,'%Y-%m-%d')
    time3 = time.mktime(time2)
    return time3

print(get_timestamp())
随机数模块

import random

  • 取随机小数

print(random.random()) #(0,1) 默认0到1之间
print(random.uniform(2,3)) #(n,m) n 到 m 之间

  • 取随机整数
    print(random.randint(1,2)) # [1,2]
    print(random.randrange(1,2)) # [1,2)
    print(random.randrange(1,100,2))

  • 从一个列表中随机抽取

    print(random.choice(list))

    print(random.choice(range(100)))

    print(random.sample(lst,3)) #在列表中随机去除3个数

  • 乱序
    lst = [1,2,3,4,5,('a','b'),'cc','dd']
    random.shuffle(lst)
    print(lst)

随机生成n位数的数字验证码

def get_code(n):
    code = ''
    for i in range(n):
        num = random.randint(0,9)
        code += str(num)
    return code

print(get_code(6))

65-90 A-Z 字符编码数 chr() 内置函数
97-122 a-z

生成6位验证码

def get_code(n=6):
    code = ''
    for i in range(n):
        num = str(random.randint(0,9))
        alpha_upper = chr(random.randint(65, 90))
        alpha_lower = chr(random.randint(97, 122))
        c = random.choice([num,alpha_upper,alpha_lower])
        code += c
    return code

进阶

def get_code(n = 6 ,alph_flag = True):
    code = ''
    for i in range(n):
        c = str(random.randint(0,9))
        if alph_flag:
            alph_A = chr(random.randint(65,90))
            alph_a = chr(random.randint(97,122))
            c = random.choice([c,alph_A,alph_a])
        code += c
    return code
print(get_code(alph_flag=False))
OS模块
  • 创建
    os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname
    os.makedirs('dirname1/dirname2') 可生成多层递归目录
  • 删除
    os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
    os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推

os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印

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)是创建时间(详细信息参见平台的文档)。

os.path.abspath(path) 返回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.abspath 拼接完再规范化

os.path.getatime(path) 返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间

os.path.getsize(path) 返回path的大小(文件大小)

os.system("bash command") # - 以字符串的形式来执行操作系统的命令 运行shell命令,直接显示
exec - 以字符串的形式来执行python代码

os.popen("bash command).read() 运行shell命令,获取执行结果
eval 以字符串的形式来执行python代码 且返回结果

os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
print(os.getcwd())
open('file','w').close() # 文件在执行这个文件的目录下创建了
不是当前被执行的文件所在的目录,而是执行这个文件所在的目录
工作目录在哪儿,所有的相对目录文件的创建,都是在哪儿执行这个文件,就在哪儿创建

os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd
改变os.getcwd() 操作系统特性

os.chdir('D:\骑士计划PYTHON1期\day23')
open('file3','w').close()
print('-->cwd : ',os.getcwd())
print(__file__)   #当前文件的绝对路径
  • import sys
    • sys模块是与python解释器交互的一个接口
    • sys.argv
    • sys.path
    • sys.modules

sys.modules 查看当前内存空间中所有的模块,和这个模块的内存空间

print(sys.path)
一个模块能否被导入,就看这个模块所在的目录在不在sys.path路径中
内置模块和第三方扩展模块都不需要我们处理sys.path就可以直接使用
自定义的模块的导入工作需要自己手动的修改sys.path

  • print(sys.argv) # python D:/骑士计划PYTHON1期/day23/6.sys模块.py

总结:

time模块
时间戳格式 浮点型
结构化时间 元组
格式化时间 字符串
    '%Y %m % d %H %M %S'
时间戳时间 -localtime/gmtime->  结构化时间 -strftime-> 格式化时间
时间戳时间 <-mktime-  结构化时间 <-strptime- 格式化时间
random模块
random.random 随机小数(0,1)
random.uniform 随机小数(n,m)
random.randint 随机整数 [n,m]
random.randrange(start,end,step)  随机整数 [n:m:s)
random.choice(list/range/tuple/str) 随机抽取一个值
random.sample(list/range/tuple/str,n) 随机抽取n个值
random.shuffle(list) 乱序,在原有基础上乱序
os 和操作系统交互
文件和文件夹的操作
    os.remove
    os.rename
    os.mkdir
    os.makedirs
    os.rmdir
    os.removedirs
    os.listdir
    os.stat 获取文件的信息
路径的操作
    os.path.join   目录的拼接
    os.path.split(path) # 将路径分割成两个部分,目录、文件/文件夹的名字
    os.path.dirname(path) # 返回这个path的上一级目录
    os.path.basename(path) # 文件/文件夹的名字
    os.path.exits  这个路径是否存在
    os.path.isfile 是否文件目录
    os.path.isdir  是否文件夹目录
    os.path.abspath 规范文件目录、返回一个绝对路径
    os.path.getsize
和python程序的工作目录相关的
    getcwd  # 获取当前的工作目录 get current working dir
    chdir   # 改变当前的工作目录 change dir
执行操作系统命令
    os.system(命令)
    os.popen(命令).read()

file文件中的一个内置变量,描述的是这个文件的绝对路径

sys 和python解释器
sys.argv 执行py文件的时候传入的参数
sys.path 查看模块搜索路径 import 模块的时候从这个路径下来寻找
sys.modules 查看当前导入的模块和它的命名空间
collections
  • 内置的数据类型
    int float complex
    str list tuple
    dict set

  • 基础数据类型
    int float complex
    str list tuple
    dict

  • collections模块
    根据基础数据类型又做了一些扩展
    有序字典 py3.6以后自动有序
    Counter 计数器(计算字符串单字符个数返回一个字典)
    默认字典
    可命名元组
    双端队列

from collections import Iterable
from collections import Iterator

  • d = dict([('a',1),('k1','v1')]) #创建字典的方法
from collections import OrderedDict
dd = OrderedDict([('a',1),('k1','v1')])  #创建有序字典  插入的时候默认在末尾,,默认有序

from collections import defaultdict #默认字典 { defaultdict(lambda : 默认值) }
d = defaultdict(可调用的) #d是一个默认字典 如果是list,可以直接append ,也可以和匿名函数结合使用

from collections import defaultdict

values = [11, 22, 33,44,55,66,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)
  • namedtuple
    from collections import namedtuple #可命名元祖 不能用索引方式访问
    birth = namedtuple('Struct_time',['year','month','day']) #'Struct_time是一个类名
    b1 = birth(2018,9,5) #可看作实例化对象 ,结构化时间就是一个可命名元祖
    可命名元组非常类似一个只有属性没有方法的类的对象
    这个类最大的特点就是一旦实例化 不能修改属性的值,安全性能好
    定义一个自由属性没有方法的类就可以用 namedtuple

  • 双端队列

    • list的缺点双端队列可以弥补
      from collections import deque
      dq = deque() #dq就是一个双端队列
      dq.append(1) #左加
      dq.appendleft(3) #右加
      print(dq) #deque([3, 1])
      print(dq.pop()) #1
      print(dq.popleft()) #3 内部机制比列表快
  • 队列
    import queue
    q = queue.Queue() # 队列 先进先出
    q.put(1) #进
    print(q.get()) #出

hashlib模块

hashlib
登录验证 md5、sha - 动态加盐
文件的一致性校验 md5 - 不需要加盐

  • 算法不可逆
  • 不同的字符串通过这个算法的计算得到的密文总是不同的
  • 相同的算法 相同的字符串 获得的结果总是相同的
    • 不同的语言 不同的环境(操作系统、版本、时间)

hashlib 摘要算法
多种算法
md5算法 :32位16进制的数字字符组成的字符串
应用最广大的摘要算法
效率高,相对不复杂,如果只是传统摘要不安全 #撞库
sha算法 :40位的16进制的数字字符组成的字符串
sha算法要比md5算法更复杂
且shan n的数字越大算法越复杂,耗时越久,结果越长,越安全

转化密文函数

def get_md5(a):
    import hashlib
    md5_obj = hashlib.md5()
    md5_obj.update(a.encode('utf-8'))
    return md5_obj.hexdigest()
  • 加盐和动态加盐,安全性能提高
    • 动态加盐
      每一个用户创建一个盐 - 用户名
import hashlib
def get_md5(a,b):
    md5_obj = hashlib.md5(a.encode('utf-8'))
    md5_obj.update(b.encode('utf-8'))
    ret = md5_obj.hexdigest()
    return ret

def login(file_name):
    while 1:
        inp_name = input('请输入你的用户名:').strip()
        if inp_name == '':continue
        while 1:
            inp_pwd = input('请输入你的密码:').strip()
            if inp_pwd == '':continue
            else:break
        with open(file_name,encoding='utf-8') as f:
            for line in f:
                name,pwd = line.strip().split('|')
                if name == inp_name and pwd == get_md5(inp_name,inp_pwd):
                    print('登录成功')
                    return True
            else:print('登录失败!')
login('hqs.txt')
  • 登录验证 - hashlib
    • 两种算法 md5,sha
    • 常规验证 - 撞库
    • 加盐 - 固定的盐 会导致恶意注册的用户密码泄露
    • 动态加盐 - 每个用户都有一个固定的并且互不相同的盐
  • 文件的一致性校验
    • 给一个文件中的所有内容进行摘要算法得到一个md5的结果
import hashlib
md5_obj = hashlib.md5()
md5_obj.update('hello,world'.encode('utf-8'))
ret1 = md5_obj.hexdigest()
print(ret1)

md5_obj = hashlib.md5()
md5_obj.update('hello'.encode('utf-8'))
md5_obj.update(',world'.encode('utf-8'))
ret2 = md5_obj.hexdigest()
print(ret2)

# 结论:ret1 == ret2

文件的校验

# 一次性读取
import hashlib
def get_md5(file_name):
    with open(file_name,'rb') as f:
        md5_obj1 = hashlib.md5()
        md5_obj1.update(f.read())
    return md5_obj1.hexdigest()
#分段读取
import os
import hashlib
def get_file_md5(file_name,butter = 1024):
    md5_obj = hashlib.md5()
    file_size = os.path.getsize(file_name)
    with open(file_name,'rb') as f:
        while file_size:
            count = f.read(1024)
            md5_obj.update(count)
            file_size -= len(count)
        return md5_obj.hexdigest()
import hashlib
def get_file_md5(filename):
    md5_obj = hashlib.md5()
    with open(filename,'rb') as f:
        for line in f:
            md5_obj.update(line)
    return md5_obj.hexdigest()

configparser
处理配置文件的模块
1 开发环境
2 测试环境
3 生产环境

  • 创建文件
import configparser
config = configparser.ConfigParser()   #config相当于一个对象/字典
config["DEFAULT11111"] = {'ServerAliveInterval': '45',
                      'Compression': 'yes',
                     'CompressionLevel': '9',
                     'ForwardX11':'yes'
                     }
config['bitbucket.org'] = {'User':'hg'}
config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}
with open('example.ini', 'w') as configfile:
   config.write(configfile)

  • 查找文件
  • 增删改操作
logging 模块
  • 日志:
    无处不在的日志(显示和写入文件都属于日志)
    所有的程序都必须记录日志

logging
日志模块

import logging
logging.basicConfig(level=logging.INFO)
logging.debug('debug message')    # 计算或者工作的细节
logging.info('info message')      # 记录一些用户的增删改查的操作
logging.warning('input a string type') # 警告操作
logging.error('error message')     # 错误操作
logging.critical('critical message')  # 批判的 直接导致程序出错退出的
  • 简单配置,只能写或者显示
import logging
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%c',
                    filename='test.log')    #filename='test.log'  配置写入文件或者显示
logging.warning('input a string type') # 警告操作
logging.error('EOF ERROR ') # 警告操作
logging.info('小明买了三斤鱼') # 警告操作
  • 对象的配置
    解决中文问题
    同时向文件和屏幕输出内容
import logging
# 先创建一个log对象 logger
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) #改变默认的INFO  是输入输出都是DEBUG以下
# 还要创建一个控制文件输入的文件操作符
fh = logging.FileHandler('mylog.log')
# 还要创建一个控制屏幕输出的屏幕操作符
sh = logging.StreamHandler()
# 要创建一个格式
fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fmt2 = logging.Formatter('%(asctime)s - %(name)s[line:%(lineno)d] - %(levelname)s - %(message)s')

# 文件操作符 绑定一个 格式
fh.setFormatter(fmt)
# 屏幕操作符 绑定一个 格式
sh.setFormatter(fmt2)
sh.setLevel(logging.WARNING)  #屏蔽掉WARNING上的屏幕输出
# logger对象来绑定:文件操作符, 屏幕操作符
logger.addHandler(sh)
logger.addHandler(fh)


logger.debug('debug message')    # 计算或者工作的细节
logger.info('info message')      # 记录一些用户的增删改查的操作
logger.warning('input a string type') # 警告操作
logger.error('error message')     # 错误操作
logger.critical('critical message')  # 批判的 直接导致程序出错退出的

logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。另外,可以通过:logger.setLevel(logging.Debug)设置级别,当然,也可以通过----fh.setLevel(logging.Debug)单对文件流设置某个级别

模块和包

模块
import

  • 在import的过程中发生了哪些事情
  • 被导入的模块和本文件之间命名空间的关系
  • import 多个模块
  • 给导入的模块起别名 (as) --- > 给模块起别名 原名就不能用
  • 模块搜索路径
  • 模块和脚本

import

import一个模块相当于执行了这个模块

在import模块的时候发生的事情
1.寻找模块
2.如果找到了,就开辟一块儿空间,执行这个模块
3.把这个模块中用到的名字都收录到新开辟的空间中
4.创建一个变量来引用这个模块的空间

  • 1.模块不会被重复导入
  • 2.模块和文件之间的内存空间始终是隔离的
  • 3.模块的名字必须是符合变量命名规范的

模块搜索路径
所以总结模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
正常的sys.path中出了内置、扩展模块所在的路径之外
只有一个路径是永远不会出问题
你直接执行的这个文件所在的目录
一个模块是否能被导入,就看这个模块所在的目录在不在sys.path中

两种运行一个py文件的方式
直接运行它 : cmd python xx.py pycharm 脚本

__name__ == '__main__'

导入它 : 模块

__name__ == '模块名

from import
在from import的过程中发生了哪些事情
被导入的内容和本文件之间命名空间的关系
from import 多个内容
给导入的内容起别名
from ... import *

* 和 __all__

1.pyc文件、pyi文件
pyc只能提高程序的启动效率并不能提高程序的执行效率
2.模块的导入和修改
3.模块的循环引用 不能循环 只能单向
4.dir(模块名) dir(list) dir(str) iter
可以获取这个模块中的所有名字(列表你显示字符串,反射)


什么是包 package
含有一个init.py的文件夹就是一个包
包中通常含有一些py文件
从包中导入模块

import 包.包.模块
import 包.包.模块.属性/方法

1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法

  1. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含init.py文件的目录)

  2. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的init.py,导入包本质就是在导入该文件

强调:

1. 在python3中,即使包下没有init.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错

2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块

  • 创建目录代码
import os
os.makedirs('glance/api')
os.makedirs('glance/cmd')
os.makedirs('glance/db')
l = []
l.append(open('glance/__init__.py','w'))
l.append(open('glance/api/__init__.py','w'))
l.append(open('glance/api/policy.py','w'))
l.append(open('glance/api/versions.py','w'))
l.append(open('glance/cmd/__init__.py','w'))
l.append(open('glance/cmd/manage.py','w'))
l.append(open('glance/db/models.py','w'))
map(lambda f:f.close() ,l)

特别需要注意的是:可以用import导入内置或者第三方模块(已经在sys.path中),但是要绝对避免使用import来导入自定义包的子模块(没有在sys.path中),应该使用from... import ...的绝对或者相对导入,且包的相对导入只能用from的形式

直接导入包
绝对导入

glance/                   

├── __init__.py      from glance import api
                             from glance import cmd
                             from glance import db

├── api                  

│   ├── __init__.py  from glance.api import policy
                              from glance.api import versions

│   ├── policy.py

│   └── versions.py

├── cmd                 

│   ├── __init__.py     from glance.cmd import manage

│   └── manage.py

└── db                   

    ├── __init__.py         from glance.db import models

    └── models.py

glance2.api.policy.get()
导入包的过程中发生了什么事?
相当于执行了这个包的 init.py文件
sys.path中的内容 永远是当前你执行的文件
['D:\骑士计划PYTHON1期\day26']

相对导入

glance/                   

├── __init__.py      from . import api  #.表示当前目录
                            from . import cmd
                            from . import db

├── api                  

│   ├── __init__.py  from . import policy
                             from . import versions

│   ├── policy.py

│   └── versions.py

├── cmd              

│   ├── __init__.py     from . import manage

│   └── manage.py    from ..api import policy   
                     #..表示上一级目录,想再manage中使用policy中的方法就需要回到上一级glance目录往下找api包,从api导入policy

└── db               from . import models

    ├── __init__.py

    └── models.py

运用了相对导入的文件不能被直接执行
'.'表示当前目录
'..'表示上一级目录
import glance3

glance/                   

├── __init__.py     from .api import *
                            from .cmd import *
                            from .db import *    
├── api                  

│   ├── __init__.py   __all__ = ['policy','versions'] 

│   ├── policy.py

│   └── versions.py

├── cmd               

│   ├── __init__.py      __all__ = ['manage']   

│   └── manage.py    

└── db                             

    ├── __init__.py         __all__ = ['models'] 

    └── models.py


import glance
policy.get()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343