模块之序列化模块和包

一.序列化模块

1.序列化——将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化(把要传输的和要存储的内容 转换成 字符串)
反序列化--字符串 转换回 要传输和存储的内容

eval:可以将str类型转换为其不带“”的类型,但不推荐用eval方法来进行反序列化操作的原因:
如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。
而使用eval就要担这个风险。

2.序列化只有两种作用:

1.网络传输:能在网络上传输的只能是bytes和字符串

 2.数据持久化 - 写在文件里

不使用模块进行序列化和反序列化操作
dic={'name':'jerd','age':18}
a=str(dic)
print(a,type(a))   #序列化{'name': 'jerd', 'age': 18} <class 'str'>
print(eval(a),type(eval(a))) #反序列化{'name': 'jerd', 'age': 18} <class 'dict'>
View Code

3.Json模块提供了四个功能:dumps、dump、loads、load

3.1dumps和loads 进行网络传输
#3.1.1json转换完的字符串类型的字典中的字符串是由""表示的
import json
dic={'name':'jerd','age':18}
ret=json.dumps(dic)
print(ret,type(ret)) #{"name": "jerd", "age": 18} <class 'str'>
#3.1.2要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示
print(json.loads(ret),type(json.loads(ret))) #{'name': 'jerd', 'age': 18} <class 'dict'>
#字符串类型的字典中的字符串必须由''表示时
dic={'name':'jerd','age':18}
ret=str(dic)  #{'name': 'jerd', 'age': 18} <class 'dict'>
print(json.loads(ret),type(json.loads(ret))) #son.decoder.JSONDecodeError:
3.1.3处理嵌套的数据类型
import json
list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}]
str_dic = json.dumps(list_dic) #也可以处理嵌套的数据类型
print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}]
list_dic2 = json.loads(str_dic)
print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]
3.2dump load 用在文件操作数据类型的序列化与反序列化上
import json
dic={'name':'jerd','age':18}
with open("ban","w",encoding="utf-8") as f: #序列化
    json.dump(dic,f)
    #load 的参数为句柄
with open("ban", encoding="utf-8") as f:  # 反序列化
    a=json.load(f)
    print(a,type(a))  #{'name': 'jerd', 'age': 18} <class 'dict'>
#文件中有多行内容时,进行反序列化时 loads也只能一行一行的操作
import json
with open("ban", encoding="utf-8") as f:
#不可json.loads(f.read())
    for i in f:
        a=json.loads(i)
        print(a,type(a))  #{'name': 'jerd', 'age': 18} <class 'dict'> [18, 52, 'sdc'] <class 'list'>
3.3ensure_ascii关键字参数
import json
data = {'username':['李华','二愣子'],'sex':'male','age':16}
json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False)
print(json_dic2)
with open('ban','w',encoding='utf-8') as f:
    json.dump(data,f,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False)
with open('ban', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False)
with open('ban','r',encoding='utf-8') as f:
     print(json.load(f))
View Code

4.pickle,用于bytes 和 python的数据类型间进行转换

4.1 dumps 和loads
import pickle
data = {'username':['李华','二愣子'],'sex':'male','age':16}
ret = pickle.dumps(data)
print(ret)   #一串二进制内容
print(pickle.loads(ret)) #{'username': ['李华', '二愣子'], 'sex': 'male', 'age': 16}
4.2 dump 和load 对文件操作要用rb或wb
import pickle
data = {'username':['李华','二愣子'],'sex':'male','age':16}
with open('ban','wb') as f:
    pickle.dump(data,f)
    pickle.dump(data, f)
with open('ban','rb') as f:
    print(pickle.load(f))  #{'username': ['李华', '二愣子'], 'sex': 'male', 'age': 16}
    print(pickle.load(f))
4.3 pickle的特点
1.pickle模块 dumps之后是bytes
2.pickle模块 dump之后的内容在文件中是乱的
3.pickle模块可以连续dump数据进入文件,然后连续load出来
4.pickle可以任意的将python中的数据类型序列化  json只能对列表 字典 进行序列化
###json 和 pickle的不同##
json是一种所有的语言都可以识别的数据结构。
如果我们将一个字典或者列表序列化成了一个json存在文件里,那么java代码或者js代码也可以拿来用。
但是如果我们用pickle进行序列化,其他语言就不能读懂这是什么了~
所以,如果你序列化的内容是列表或者字典,推荐使用json模块
View Code

json 和 pickle的不同

json是一种所有的语言都可以识别的数据结构。
如果我们将一个字典或者列表序列化成了一个json存在文件里,那么java代码或者js代码也可以拿来用。
但是如果我们用pickle进行序列化,其他语言就不能读懂这是什么了~
所以,如果你序列化的内容是列表或者字典,推荐使用json模块

5.shelve只提供给我们一个open方法,是用key来访问的,使用起来和字典类似

往文件中写入内容
import shelve
f = shelve.open('ban') #会自动建三个文件。如果“ban”这个文件已经存在,则会报错.写进去后内容时是乱的
f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'}  #直接对文件句柄操作,就可以存入数据
f.close()
##读取内容
f=shelve.open("ban")
excting=f["key"]
f.close()
print(excting)  #{'int': 10, 'float': 9.5, 'string': 'Sample data'}
View Code

二.模块

1 什么是模块?

模块 是一个py文件
一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀

2 为何要使用模块?

如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,
需要时就通过python test.py方式去执行,此时test.py被称为脚本script。我们不仅仅可以把这些文件当做脚本去执行,
还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用,
View Code

3.import

自定义模块my_module.py,文件名my_module.py,模块名my_module
在my_module.py中写入
print(666)
money=100
def func1():
print("the money is:",money)
print(777)

3.1导入模块之后解释器做的事情:

1.找到这个模块,判断这个模块是否被导入过,如果没有被导入过,就导入
2.创建属于这个模块的命名空间
3.执行这个模块中的代码,将模块中的名字加载到命名空间中
对于模块来说 并不会重复导入   模块间的命名空间是独立的
View Code

3.2模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块

它们只在模块名第一次遇到导入import语句时才执行。如print(666) print(777)就是可执行语句

python的优化手段是:
第一次导入后将模块名加载到内存,后续的import语句仅是对已经加载到内存中的模块增加了一次引用,不会再执行模块内的语句)
import my_moudle 只在第一次导入时才执行my_module.py内代码,显示666 777
import my_moudle 不再显示666 777
#如果在my_moudle中加入func1()
import my_moudle
print(my_moudle.func1())
#666 the money is: 100 777
#the money is: 100 None

3.2 import ... as .. 临时重命名

对文件进行操作
if file == 'txt':
import txt as file
elif file == 'doc':
import doc as file
f = file.open()
f.close()

3.3 import m1,m2,m3 导入多个模块,但提倡分开用import分别导入

4. form *** import ***


4.1 my_moudle里面的内容都执行,只是需要谁把谁放到内存中
from my_moudle import func1 #666 777
from my_moudle import func1  
money=10
print(func1())  #100 None
#如果用import  my_moudle 调用func1
import  my_moudle
print(my_moudle.func1())
4.2 导入多个模块,用逗号分开
4.3改名 form my_moudle import func1 as func
4.4 from my_moudle import *  #将模块my_module不是以下划线(_)开头的所有的名字都导入到当前名称空间。不建议使用
from my_moudle import *
print(money)
print(func1())
###与import my_moudle区别是:在用func1时前者直接func1() 后者my_moudle.func1()
4.5*和__all__配合使用 :my_moudle中加上__all__=['money']
这样在另外一个文件中用from my_module import *就这能导入列表中money名字
print(func1())  #NameError: name 'func1' is not defined
View Code

5.其他

1.不允许循环导入 即两个模块a,b在a模块中import b ,再在b模块中import a
2.模块一旦导入 发生改变也不会影响已经导入的内容
import time, importlib
import my_moudle
time.sleep(20)
#importlib.reload( my_moudle)
my_moudle.func1() # 666 777 "the money is:",money 修改不会变
3.我们可以通过模块的全局变量__name__来查看模块名:
当做脚本运行:
__name__ 等于'__main__'
当做模块导入:
__name__= 模块名 当moudle中只有print(__name__)时在moudle中执行显示main 用其他文件导入moudle时显示模块名moudle
作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
if __name__ == '__main__':
在my-moudle中执行
print(666)
money=100
def func1():
print("the money is:",money)
print(777)
if __name__ == '__main__':
print(__name__)
func1() #会执行func1()
在另一py中执行import my--moudle 不会执行func1()
4.模块搜索路径
模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
import sys
print(sys.path) #显示路径 第一个是本文件所在的路径 #['D:\\lianxi\\python\\数据类型和函数', 'D:\\lianxi', 'D:\\python3.6\\anzhaunghou\\python36.zip',
print(sys.path.pop(0)) #删除第一个路径
print(sys.path.pop(0)) #再将路径删除
print(sys.path) #['D:\\python3.6\\anzhaunghou\\python36.zip'
import my_moudle #ModuleNotFoundError 报错 module模块
4.文件当做模块被执行后会编译成pyc文件,在以后使用模块后,会节省模块启动的时间 并没有缩减运行代码的时间
不当模块用,就不会编译成pyc文件

 

 

三.包

1.包的基本知识:

1.1凡是在导入语句中(而不是在使用时)遇到带点的,这是关于包才有的导入语法
1.2包的本质就是一个包含__init__.py文件的目录。导入包本质就是在导入该文件
1.3 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
1.4创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块

 

2.导入包时注意:

2.1凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则
2.2.对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类

3.从包中导入:


3.1 import 
import glance.db.models
glance.db.models.register_models('mysql')
3.2 from ... import ...
from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法
from glance.db import models
models.register_models('mysql')
from glance.db.models import register_models
register_models('mysql')
3.3__init__.py文件
不管是哪种方式,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件这个文件可以为空,
但是也可以存放一些初始化包的代码

4.绝对导入和相对导入


绝对导入:以glance作为起始
相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)
在glance/api/version.py
#绝对导入
from glance.cmd import manage
manage.main()
#相对导入
from ..cmd import manage
manage.main()

5.软件开发规范:一个包下一般含多个文件夹

1.bin文件夹(里面有个start.py)
2.conf(里面有个setting.py)
3.core(里面放核心代码)
4.db(普通文件)
5.lib库
6.log

 

 

 

 

 
 

 

 
 
 
posted @ 2018-03-10 17:54  JERD  阅读(302)  评论(0编辑  收藏  举报