Python学习笔记DAY12(常用模块_shutil、json、pickle、shelve、xml、configparser)

这是我个人的学习笔记,都赖于(egon老师)的分享,以下是老师博客的原地址:
https://www.cnblogs.com/xiaoyuanqujing/articles/11640888.html

python常用模块

五、shutil模块:是高级的文件,文件夹,压缩包处理模块

import shutil

shutil.copyfileobj(open("old.txt","r",encoding="utf-8"),open("new.txt","w"))
# 将某一个文件的 内容 快速复制到目标文件中

shutil.copyfile("f1.log","f2.log")
# 复制一个文件

shutil.copymode("f1.log","f2.log") # 目标文件必须存在
# 仅拷贝权限,内容,组,用户均不变

shutil.copystat("f1.log","f2.log") # 目标文件必须存在
# 仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

#shutil.copy('f1.log', 'f2.log')
# 拷贝文件和权限

#shutil.copy2('f1.log', 'f2.log')
# 拷贝文件和状态信息


shutil.copytree('folder1', 'folder2',ignore=shutil.
ignore_patterns('*.pyc', 'tmp*'))
# 目标目录不能存在,注意对folder2目录父级目录要有可写权限,
# ignore的意思是排除


shutil.copytree('f1', 'f2', symlinks=True,
ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
# 通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件

shutil.rmtree('folder1')
# 递归的去删除文件

shutil.move('folder1', 'folder3')
# 递归的去移动文件,它类似mv命令,其实就是重命名。

shutil.make_archive(base_name, format,...)
# 创建压缩包并返回路径
# base_name: 压缩包的文件名,也可以是压缩包的路径。
# 只是文件名时,则保存至当前目录,否则保存至指定路径,
# 如 data_bak                       =>保存至当前路径
# 如:/tmp/data_bak =>保存至/tmp/
# format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
# root_dir: 要压缩的文件夹路径(默认当前目录)
# owner: 用户,默认当前用户
# group: 组,默认当前组
# logger: 用于记录日志,通常是logging.Logger对象

# 压缩实例
shutil.make_archive("f1.log","tar",root_dir = r"module_01/data/f1.log.tar")
# 将指定路径的文件压缩后放置在当前目录

shutil.make_archive("module_01/data/f1.log.tar","tar")
# 将压缩文件放置到指定路径

# shutil对压缩包的处理是调用zipfile 和 tarfile 两个模块来进行的:
import zipfile

# zip压缩步骤
z = zipfile.ZipFile("f1.zip","w")
z.write("f2.log")
z.write("data")
z.close
# 将文件f2.log压缩成f1.zip 放到data文件夹下

# zip解压步骤
z = zipfile.ZipFile("f1.zip","r")
z.extractall(path="..")
z.close()
# 解压 f1.zip到指定位置

import tarfile
# tar压缩
t=tarfile.open('/tmp/egon.tar','w')
t.add('/test1/a.py',arcname='a.bak')
t.add('/test1/b.py',arcname='b.bak')
t.close()

# tar解压
t=tarfile.open('/tmp/egon.tar','r')
t.extractall('/egon')
t.close()

六、json模块 and pickle模块

  • 序列化:是指把内存的数据类型转换成一个特定格式的内容。该格式化内容可用于存储或者传输给其他平台使用。

  • 作用:

    1. 用于存档(可以是一种专用的格式 pickle 内存--存到-->硬盘)
    2. 跨平台数据交互,比如(Python列表--转-->特定格式json--转-->java数组)

    备注:json是所有语言都可以识别的格式

  • 内存数据类型=>序列化=>特定格式(json/pickle)

  • 内存数据类型<=序列化<=特定格式(json/pickle)

为什么需要序列化??

  1. 保存状态

    ​ 一个程序的执行就是在处理一系列状态的变化,在编程语言中,“状态”会以各种各样有结构的数据类型的形式保存在内存中。内存是无法永久保存数据的,断电或重启,内存中关于程序的数据就被清空了,那么 把之前运行在内存的程序保存起来,到文件中,方便下次启动能够把程序加载到之前运行的状态,然后继续有运行,这就是序列化

  2. 跨平台数据交互

    ​ 序列化之后,不仅可以把序列化后的数据写入磁盘,还可以通过网络传输到别的机器上如果收发双方约定好使用一种序列化格式,那么便打破了平台/语言差异带来的限制,实现跨平台数据交互

# 如何序列化之json和pickle
# json
# 如果我们要在不同编程语言之间传递对象,就必须把对象序列化为标准格式,比如
# json,json表示出来就是一个字符串,可以被所有语言读取
# json表示的对象就是标准的JavaScript语言的对象:
       json
 {}    []   "string"  12.32     true/false    null
       Python
dice  lise     str   int/float   True/Flase   Nore

import json

# res = json.dump(True) # 序列化 (res可以存入硬盘,可传输)
# json.loads(res) # 反序列化

dic = {'name':'nida','age':18,'hight':12.32}
j = json.dumps(dic)  # <class 'str'> {"name": "nida", "age": 18, "hight": 12.32}
#
# 序列化对象
with open("test.json",mode="wt",encoding="utf-8")as f:
     f.write(j)

# 反序列化
with open("test.json",mode="rt",encoding="utf-8")as f:
    res = f.read()
    json.loads(res)

# 序列化/反序列化(简写)
with open("test.json",mode="wt",encoding="utf-8")as f:
   json.dump([1,'aa',True],f)  # 序列化
with open("test.json",mode="rt",encoding="utf-8")as f:
    json.load(f)

# 以上,load 与 loads 完全适用于pickle
# 注意:
# json字符串都是双引号
# 在python解释器2.7与3.6之后都可以json.loads(bytes类型),但唯独3.5不可以

## 猴子补丁
## 一、什么是猴子补丁?
# 属性在运行时的动态替换,叫做猴子补丁
# 猴子补丁的核心就是用自己的代码替换所有模块的源代码
# 二、猴子补丁的功能(一切皆对象)
# 1.在拥有模块运行时替换的功能,例如:一个函数对象复制给另一个函数对象
#(把函数原本的执行的功能替换了)
class Monkey:
    def hello(self):
        print("hello")
    def world(self):
        print("world")

def other_func():
    print("form other_func")

monkey = Monkey()
monkey.hello = monkey.world #把world方法的地址 赋值给hello方法
monkey.hello()  # 此时其实调用的是world方法
monkey.world = other_func #把ther_func方法的地址 赋值给world方法
monkey.world()  # 其实就是调用了other_func方法

# 三、monkey patch 的应用场景
# 如果我们的程序中已经基于json模块编写了大量代码了,发现有一个模块ujson比
# 它性能更高,但用法不一样,我们肯定不会想所有的代码都换成ujson。
# 此时我们就可以用到猴子补丁了
# 只需要在入口处加上:
import json
import ujson

def monkey_patch_json():
    json.__name__ = "ujson"
    json.dumps = ujson.dumps
    json.loads = ujson.loads
    
# monkey_patch_json() # 之所以要在入口处加,是因为模块在导入一次后,后续导入便
# 直接引用第一次的成果
# 其实这种场景也比较多,比如我们引用团队通用库里的一个模块,又想丰富模块的功能,
# 除了继承之外也可以考虑用monkey patch

pickle模块

​ pickle 的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,所以,只能用pickle只能用于保存些不重要的证据,不能成功的反序列化也没关系

import pickle

dic = {'name':'nida','age':18,'hight':12.32}
p = pickle.dumps(dic)  # <class 'bytes'>

# 序列化对象

with open("test.json",mode="wb",encoding="utf-8") as f:
    f.write(p) # wb 是写入的bytes数据,相当于 pickle.dump(dic,f)

# 反序列化对象

with open("test.json",mode="rb",encoding="utf-8") as f:
    data = pickle.loads(f.read()) # 等价于data= pickle.load(f)

七、shelve模块

​ shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写,key必须为字符串,而值可以是Python所支持的数据类型

import shelve

f=shelve.open(r'sheve.txt')
f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}
f['stu2_info']={'name':'gangdan','age':53}
f['school_info']={'website':'http://www.pypy.org','city':'beijing'}

print(f['stu1_info']['hobby'])
f.close()

八、xml模块

​ xml是实现不同语言程序之间进行数据交换的协议,跟json差不多,但是json用起来更简单不过在json还没有诞生的年代,只能用xml,所以至今很多传统公司,比如金融行业很多系统的接口还主要是xml

  • xml的格式如下(就是通过<>节点来区别数据结构的)
<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>

## xml协议在各个语言里都是支持的,在Python中可以用以下模块中操作xml:
print(root.iter('year')) #全文搜索
print(root.find('country')) #在root的子节点找,只找一个
print(root.findall('country')) #在root的子节点找,找所有

import xml.etree.ElementTree as ET

tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)

# 遍历xml文档
for child in root:
    print('========>', child.tag, child.attrib, child.attrib['name'])
    for i in child:
        print(i.tag, i.attrib, i.text)

# 只遍历year 节点
for node in root.iter('year'):
    print(node.tag, node.text)
# ---------------------------------------

import xml.etree.ElementTree as ET

tree = ET.parse("xmltest.xml")
root = tree.getroot()

# 修改
for node in root.iter('year'):
    new_year = int(node.text) + 1
    node.text = str(new_year)
    node.set('updated', 'yes')
    node.set('version', '1.0')
tree.write('test.xml')

# 删除node
for country in root.findall('country'):
    rank = int(country.find('rank').text)
    if rank > 50:
        root.remove(country)

tree.write('output.xml')

## 自己创建 xml文档:
import xml.etree.ElementTree as ET

new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})
age = ET.SubElement(name, "age", attrib={"checked": "no"})
sex = ET.SubElement(name, "sex")
sex.text = '33'
name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"})
age = ET.SubElement(name2, "age")
age.text = '19'

et = ET.ElementTree(new_xml)  # 生成文档对象
et.write("test.xml", encoding="utf-8", xml_declaration=True)

ET.dump(new_xml)  # 打印生成的格式

九、configparser模块(加载一种特定格式的配置文件)

配置文件test.ini 内容如下:
[section1]
k1 = v1
k2:v2

[section2]
user = nida
age = 18
# 读取配置文件
import configparser
config = configparser.ConfigParser()
config.read("test.int")

# 获取配置文件下的所有sections
config.sections()   # 结果:['section1', 'section2']

# 获取某一个section下的所有options(获取一个section下的所有key )
config.options("section2") # 结果:['user', 'age']
# 获取items(section2下所有key=value的(key,value)格式)
config.items("section2") # [('user', 'nida'), ('age', '18')]

# 获取(section2下"age"的值-->整数格式)
config.getint("section2","age")

# 获取(section2下"age"的值-->字符串格式)
config.get("section2","age")

#查看标题section1下is_admin的值=>布尔值格式
val2=config.getboolean('section1','is_admin')

#查看标题section1下salary的值=>浮点型格式
val3=config.getfloat('section1','salary')

## 改写配置文件test.int
import configparser
config = configparser.ConfigParser()
config.read("test.int",encoding="utf-8")
# 删除整个标题section2
config.remove_section("section2")
# 删除标题section1下的某个值
config.remove_option("section1","k1")
# 判断是否存在某个标题
 print(config.has_section("section1"))
# 判断section1中是否有user
print(config.has_option("section1","user"))
# 添加一个标题
config.add_section("nida")
# 在标题nida 下添加name = nida age = 18 的配置
config.set("nida","name","nida")
config.set("nida","age","18") # 往配置文件里添加数据必须是字符串
# 最后将修改的内容写入文件,完成最终的修改
config.write(open("test.int","w"))

# 基于上述学习的方法添加一个ini文档
import configparser

config = configparser.ConfigParser()
config["DEFAULT"] = {"ServerAliveInterval":"45",
                     "Compression":"yes",
                     "CompressionLevel":"9"}
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022'     # mutates the parser
topsecret['ForwardX11'] = 'no'  # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini', 'w') as configfile:
   config.write(configfile)
posted @ 2021-05-17 21:38  nida  阅读(101)  评论(0)    收藏  举报