Day7 Python模块(json, pickle, xml, config),迭代器生成器, 反射 - Wiesler

时间:2024-03-05 17:32:22

Day7 Python模块(json, pickle, xml, config),迭代器生成器, 反射

简介:本次内容,Python模块补充(json, pickle, xml, configparse, logging), 迭代器,生成器,反射

全局变量的补

每一个Python的.py文件都有一些默认的全局变量,可以在文件中直接调用

查看全局变量  print(vars())

__doc__ 注释内容。在一个.py文件的开头用三引号写了注释,那么这就是这个.py文件的注释,这个注释内容,默认写入__doc__这个全局变量中

__file__就是当前.py文件的完整路径。可以配合os模块中的dirname()和basename()来拿到路径和文件名,并用os.path.join拼接

import os
print(__file__)  # E:/python/demo.py

directory = os.path.dirname(__file__)
print(directory)  # E:/python

filename = os.path.basename(__file__)
print(filename)  # demo.py

path = os.path.join(directory, filename)
print(path)  # E:/python\demo.py   sys.path中都是\,那么这里/或\不影响的,如果想要统一,可以用path = path.replace("/", "\\")进行替换

所以os.path.dirname()  os.path.basename()  os.path.join()和__file__非常有用

sys.path中存放了一些路径地址,可以在这些地址中寻找并导入模块。 如果有一个模块需要导入,我们可以选择1 将模块移入到print(sys.path)返回的地址列表中的某个地址中去;2 该模块不动,将该模块的地址添加进入sys.path模块,这样python就可以在sys.path的地址列表中找到我们需要的模块

import os
import sys
print(sys.path)
p1 = os.path.dirname(__file__)
p2 = "bin"
sys.path.append(os.path.join(p1, p2))

其实我们完全可以不用os.path.dirname或者.join方法,可以自己把地址写入.append(),但是用上述方法灵活性更高,即使文件地址变动,依然可以捕捉并添加地址到列表

 

__package__当前.py所在的文件夹。如果在当前文件demo.py中执行print(__package__), 结果为None。

该语句需要放入到导入的包中。

# 在文件夹day2/new/hello.py 中写
print(__package__)
# 在demo.py文件中导入这个hello.py
from day2.new import hello
# day2.new
# 结果就是路径文件夹,并以. 来划分

如果某个包 from lib.xx import commons

print(__package__) 就可以显示该包的文件夹 lib.xx

(把print(__package__)放在包的.py文件中,import时可以自动执行)

 __cached__查看缓存

from day2.new import hello

print(hello.__cached__)  # E:\python\day2\new\__pycache__\hello.cpython-35.pyc

 

__name__  文件是否为程序主入口

只有直接执行的.py文件,print(__name__) 返回__main__   

如果demo.py中 import导入另一个文件,在该文件中写print(__name__),那么运行后显示的就是该包的名字

# 在文件夹day2/new/hello.py 中写
print(__name__)
# 在demo.py文件中导入这个hello.py
from day2.new import hello
# 显示day2.new.hello
# 表示导入的这个包并不是直接执行的文件,而是由于导入import,而间接执行的
# 在demo.py中写
print(__name__)  # __main__
# 表示demo.py才是直接执行的文件,程序的主入口

一个程序只有一个主程序main,也就是入口,其他文件都是作为功能性的函数

所以以后主函数执行的时候,都要做一下判断:

if __name__ == "__main__":
  index()

 

如果我们直接run这个主程序,那么就可以运行,如果别的程序import了主程序,那么__name__就不是__main__了,就不可以执行程序

这样就限制了程序只能有一个入口

__loader__和__spec__在python3.5中新出现

__builtins__里面存放了内置函数

导入模块的方法

import module
from module.xx.xx import xx
from module.xx.xx import xx as rename 
from module.xx.xx import *

urllib模块:专门用来发送http请求

from urllib import request

f = request.urlopen("https://www.youtube.com/")
result = f.read().decode("utf-8")
print(result)  # 打印出网页的html结构

 

JSON序列化

给网站发送请求,网站返回的是字符串文件 json

json.loads(data)用于将字典,列表,元组形成的字符串,转换成相应的字典,列表,并不能转换元祖和集合,因为其他语言中没有,这是python中特有的,而json是对其他语言也支持的

str1 = (11, 22, 33, "Hello")
print(json.dumps(str1))  # [11, 22, 33, "Hello"]
str2 = \'(11, 22, 33, "Hello")\'
print(json.loads(str2))  # 报错

 

为什么这个例子中json.loads()会报错呢?因为元祖解释为字符串时,这个元祖类型仅仅是Python内部才有的数据类型。而[] 和{} 是通用的符号,在其他语言中也是存在的

json字符串规范性的问题:

str1 = \'[1, 2, 3, {"name": "Lee"}]\'
print(json.loads(str1))  # [1, 2, 3, {\'name\': \'Lee\'}]
str2 = "[1, 2, 3, {\'name\': \'Lee\'}]"
print(json.loads(str2))  # 报错

json.loads(字符串)时,如果字符串是我们自己写的,需要注意一下,字符串内部需要用到表示字典键值对时必须用双引号,字符串外部用单引号。

json是一个诸多语言均可以交互的字符串,在python里面单引号双引号均表示字符串,可在别的语言里单引号就不一定是字符串了,可以是单个字符,但是双引号始终是字符串。所以,json.loads(string)时,如果string内部有键值对,需要用双引号,这样才可以顺利解析。或者外部是三引号也可以

str1 = """[1, 2, 3, {"name": "Lee"}]"""
print(json.loads(str1))  # [1, 2, 3, {\'name\': \'Lee\'}]

 

当然如果字符串是别的网站发过来的信息,或者是你用json.dumps()生成的json字符串是不会有上述问题的。

json字符串=json.dumps(data)将各种数据,字符串,列表,元组,字典转换成json字符串

原数据=json.loads(json字符串)将字符串,列表,元组,字典形成的json字符串转换成原数据

一定注意json.loads()规范性的问题

 

json.dump(dic, open(“db”, “w”))将字符串写入文件,json.load(open(“db”, r))将字符串读入文件

一般我们不使用dump和load方法,我们一般只会使用loads和dumps

 

安装第三方模块:

两种方法:1软件管理工具pip安装 2 源码安装

对于1 软件管理工具pip安装:

1 查看python安装目录下的script文件夹中有没有pip文件,如果没有下载并安装setuptools和pip。如果有忽略这步

2 将python里的Script文件路径添加到环境变量

3 在cmd中执行 python35 -m pip install requests 就可以安装requests模块了

或者安装django时,使用python35 -m pip install django

对于2源码安装

搜索requests python, 下载文件之后,用setup.exe来安装

在cmd中使用python setup.py install来安装

 

requests模块: 和urllib作用差不多,发送http请求,也就是用python来模拟浏览网页

通过python代码就可以登录其他的网页 

import requests

response = requests.get("https://www.google.com/?gws_rd=ssl")
response.encoding = "utf-8"
result = response.text
print(result)

通过response.text拿到结果

XML 模块

没有json之前,XML是比较流行的,也是一种格式化的存储数据的类型

类似于HTML那样的元素标签,但是标签名字可以自己定义。也是一种网页返回数据的结构,有html,XML和json三种形式构成的字符串。

python中有专伺处理XML的模块from xml.etree import ElementTree 

该模块配合requests模块产生效果,requests模块提交http请求,并接受了返回的数据,其中XML类的数据由该模块来处理

# XML格式的数据
<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2023</year>
        <gdppc>141100</gdppc>
        <neighbor direction="E" name="Austria" />
        <neighbor direction="W" name="Switzerland" />
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2026</year>
        <gdppc>59900</gdppc>
        <neighbor direction="N" name="Malaysia" />
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2026</year>
        <gdppc>13600</gdppc>
        <neighbor direction="W" name="Costa Rica" />
        <neighbor direction="E" name="Colombia" />
    </country>
</data>

 

解析XML,两种方法:1 解析XML字符串  2解析.xml文件

1解析XML字符串:从文件中读入的XML字符串,或者是 网页响应http请求,返回的字符串. 使用ElementTree.XML()方法

# 网页响应http请求,返回的字符串
import
requests response = requests.get("https://www.google.com/?gws_rd=ssl") # 应该是一个返回xml的网页 response.encoding = "utf-8" result = response.text print(result) from xml.etree import ElementTree as ET # 解析XML root = ET.XML(result) # 解析后的XML,得到一个节点标签 if root.text == "Y": # node.text是xml标签中的内容 print("success")

 

# 解析文件中的XML字符串
from xml.etree import ElementTree as ET

# 打开文件,读取XML内容
str_xml = open(\'xo.xml\', \'r\').read()  # 这里不要忘了open()是创建了一个文件操作句柄,相当于f,还需要f.read()读数据

# 将字符串解析成xml特殊对象,root代指xml文件的根节点
root = ET.XML(str_xml)

 

2解析.xml文件 利用 ElementTree.parse()方法

from xml.etree import ElementTree as ET

# 直接解析xml文件
tree = ET.parse("xo.xml")

# 获取xml文件的根节点
root = tree.getroot()

 

 

 

 

在www.webxml.com.cn上有很多返回xml标签的网页可以做测试

操作XML:

XML的内容遍历:

from xml.etree import ElementTree as ET
#两种解析方式得到根节点root
############ 解析方式一 ############
"""
# 打开文件,读取XML内容
str_xml = open(\'xo.xml\', \'r\').read()

# 将字符串解析成xml特殊对象,root代指xml文件的根节点
root = ET.XML(str_xml)
"""
############ 解析方式二 ############

# 直接解析xml文件
tree = ET.parse("xo.xml")

# 获取xml文件的根节点
root = tree.getroot()

### 操作

# 顶层标签
print(root.tag)

# 遍历XML文档的第二层
for child in root:
    # 第二层节点的标签名称和标签属性
    print(child.tag, child.attrib)
    # 遍历XML文档的第三层
    for i in child:
        # 第二层节点的标签名称和内容
        print(i.tag,i.text)

 

XML的节点遍历:

# 遍历XML中所有的year节点
for node in root.iter(\'year\'):  # 一层一层地循环子元素标签
    # 节点的标签名称和内容
    print(node.tag, node.text)

 

XML节点操作:修改仅仅是在内存中进行的,要想文件被改动需要最后再写入文件

print(dir(root)) 得到根节点root后,print(dir(root))能打印出所有root的方法

root或其他节点.tag 标签名

.text  内部文本内容

.attrib["name"]  获取name属性内容

.makeelement(tag, {"key": "value"}) 创建标签,tag标签名,属性用键值对的字典传入,任何节点都可以makeelement

本质是ET.Element(tag, {"key": "value"})      python中一切皆对象,所以标签element,也可以由类创建. ET也就是ElementTree. 

ET.SubElement((root, “tag”, {“key”: “value”}))  创建标签,结合了.append()方法,将标签附在root元素内部末尾

.append(subelement)  将一个标签添加在已有标签的内部后方

# 仅创建节点
son = root.makeelement("data", {"key": "value"})
# 添加节点
root.append(son)

tree.write("aaa.xml", short_empty_elements=False)

 

tree.write("aaa.xml", encoding="utf-8") 如果想要修改生效,就要最后写入文件,有中文的话,需要加上encoding="utf-8"

如上例创建了标签,但是并没有设置标签的文本,也就是说标签为空,那么默认只添加单闭合标签<...  />

如果想要添加双闭合标签需要在tree.write("aaa.xml", short_empty_elements=False) 成对标签<div></div>一般保持默认,节省空间

.extend(elements) 追加n个元素

.insert(index, subelement) 向当前节点指定位置插入子节点

.remove()   root.remove(root.find(xxx))父节点删除子节点

.findtext() 找内容   .find().text

.findall()  获取所有子节点

.iterfind() 获取所有指定节点,并创建迭代器,用for循环获取

.clear() 清空节点

.get(key) 获取当前节点属性值

.set(key, value) 设置属性值

.keys()获取当前节点的所有属性的key

.items()获取当前节点的所有属性值,每个属性都是一个键值对

.iter(self, tag=None)  比如root.iter("div")循环找出root下所有的<div>元素,创建迭代器,用for循环获取

.itertext() 在当前节点的子孙中根据节点名称寻找所有指定的节点的内容,并返回一个迭代器(可以被for循环)

XML中的对象关系:

Python中一切皆是对象,对象所有方法都在相关的类中

tree对象的知识点:

1 ElementTree对象创建,可以通过tree = ET.ElementTree(root)来创建,之前我们通过ET.parse("aaa.xml")来创建

2 tree.getroot()获取根节点root

3 tree.write(文件)将内存中的xml写入文件中

节点对象:

1 root根节点和其他节点都是节点对象

2 根节点由root = tree.getroot()获取 或者 root = ET.XML(string) 来获取

3 其他节点可以有 任何节点/root .makeelement() 或 ET.Element() 或 ET.SubElement() 来创建

from xml.etree import ElementTree as ET 表示该模块在python35的Lib/xml/etree文件夹下,叫ElementTree.py, 别名为ET.py

里面有两个类,ElementTree类和Element类,不要混淆

保存修改后的内容

操作文件时

# 操作文件时,已经由tree = ET.parse("aaa.xml")创建了tree对象
tree.write("aaa.xml")
# 或者需要编码
tree.write("aaa.xml", encoding="utf-8")
# 如果强制成对标签,可再加short_empty_elements=False

字符串操作时

# 字符串操作时, root = ET.XML(open(...).read())直接得到了文件字符串内容,并没有创建tree对象,所以要先创建tree对象
tree = ET.ElementTree(root)
tree.write("newnew.xml", encoding=\'utf-8\')

 

XML的缩进:默认我们修改后的XML是无缩进的,需要导入另一个模块xml.dom

from xml.dom import minidom

def prettify(elem):
   """将节点转换成字符串,并添加缩进。
   """
   rough_string = ET.tostring(elem, \'utf-8\')
   reparsed = minidom.parseString(rough_string)
   return reparsed.toprettyxml(indent="\t")

然后对root操作结束之后,调用prettify()函数,重新将文件写入

raw_str = prettify(root)

f = open("xxxoo.xml",\'w\',encoding=\'utf-8\')
f.write(raw_str)
f.close()

 

创建XML:

方式1:ET.Element()创建节点

from xml.etree import ElementTree as ET

# 创建根节点
root = ET.Element("famliy")

# 创建节点大儿子
son1 = ET.Element(\'son\', {\'name\': \'儿1\'})
# 创建小儿子
son2 = ET.Element(\'son\', {"name": \'儿2\'})

# 在大儿子中创建两个孙子
grandson1 = ET.Element(\'grandson\', {\'name\': \'儿11\'})
grandson2 = ET.Element(\'grandson\', {\'name\': \'儿12\'})
son1.append(grandson1)
son1.append(grandson2)

# 把儿子添加到根节点中
root.append(son1)
root.append(son1)

tree = ET.ElementTree(root)
tree.write(\'oooo.xml\',encoding=\'utf-8\', short_empty_elements=False)
View Code

 

方式2:.makeelement()创建节点

from xml.etree import ElementTree as ET

# 创建根节点
root = ET.Element("famliy")

# 创建大儿子
# son1 = ET.Element(\'son\', {\'name\': \'儿1\'})
son1 = root.makeelement(\'son\', {\'name\': \'儿1\'})
# 创建小儿子
# son2 = ET.Element(\'son\', {"name": \'儿2\'})
son2 = root.makeelement(\'son\', {"name": \'儿2\'})

# 在大儿子中创建两个孙子
# grandson1 = ET.Element(\'grandson\', {\'name\': \'儿11\'})
grandson1 = son1.makeelement(\'grandson\', {\'name\': \'儿11\'})
# grandson2 = ET.Element(\'grandson\', {\'name\': \'儿12\'})
grandson2 = son1.makeelement(\'grandson\', {\'name\': \'儿12\'})

son1.append(grandson1)
son1.append(grandson2)

# 把儿子添加到根节点中
root.append(son1)
root.append(son1)

tree = ET.ElementTree(root)
tree.write(\'oooo.xml\',encoding=\'utf-8\', short_empty_elements=False)
View Code

 

方式3:ET.SubElement()创建节点

from xml.etree import ElementTree as ET

# 创建根节点
root = ET.Element("famliy")

# 创建节点大儿子
son1 = ET.SubElement(root, "son", attrib={\'name\': \'儿1\'})
# 创建小儿子
son2 = ET.SubElement(root, "son", attrib={"name": "儿2"})

# 在大儿子中创建一个孙子
grandson1 = ET.SubElement(son1, "age", attrib={\'name\': \'儿11\'})
grandson1.text = \'孙子\'

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

三种方式最后都需要tree = ET.ElementTree(root)  然后用tree.write()写入文件

XML文件头:

xml也有相应的文件头tree.write(“aaa.xml”, encoding=”utf-8”, xml_declaration=True), 这个文件头虽然也是标签<>,但是相当于注释内容,不会影响节点选取的判断

在tree.write()里加上xml_declaration=True会使文件出现<?xml version="1.0" encoding="UTF-8"?>文件头

命名空间:

如果标签同名,会带来使用和查找的不便, 比如有两个<table></table>标签同名

一个命名为<h: table></h: table>另一个命名为<g: table></g: table>

ET.register_namespace("aaa", "haha")  # 这样就定义了一个命名空间aaa表示haha

root = ET.Element("{haha}div")  # 生成了根元素 <aaa:div></aaa:div>

之后创建元素只要将元素名命名为{haha}abc  就可以生成带<aaa:abc></aaa:abc>的标签

from xml.etree import ElementTree as ET

ET.register_namespace(\'com\', "http://www.company.com")  # 定义命名空间name space
# 在xml中,com就表示http://www.company.com   体现在根节点中xmlns:com="http://www.company.com"
# build a tree structure
root = ET.Element("{http://www.company.com}STUFF")  # 根节点就叫<http://www.company.com:STUFF>简写为<com:STUFF>, 
body = ET.SubElement(root, "{http://www.company.com}MORE_STUFF", {"{http://www.company.com}hhh": "123"})
# 给root添加一个子元素,<com:MORE_STUFF> 属性为 com:hhh="123" body.text
= "STUFF EVERYWHERE!" # wrap it in an ElementTree instance, and save as XML tree = ET.ElementTree(root) tree.write("page.xml", xml_declaration=True, # 有文件头<?xml version=\'1.0\' encoding=\'utf-8\'?> encoding=\'utf-8\', method="xml")

 

生成的xml文件显示为

<?xml version=\'1.0\' encoding=\'utf-8\'?>
<com:STUFF xmlns:com="http://www.company.com">
    <com:MORE_STUFF com:hhh="123">
        STUFF EVERYWHERE!
    </com:MORE_STUFF>
</com:STUFF>

 

configparser模块

用于处理配置文件,本质上是用open来操作文件

# 注释1
;  注释2
 
[section1] # 节点
k1 = v1    #
k2:v2       #
 
[section2] # 节点
k1 = v1    #

1、获取所有节点

import configparser
 
config = configparser.ConfigParser()
config.read(\'xxxooo\', encoding=\'utf-8\')
ret = config.sections()
print(ret)

2、获取指定节点下所有的键值对

import configparser
 
config = configparser.ConfigParser()
config.read(\'xxxooo\', encoding=\'utf-8\')
ret = config.items(\'section1\')
print(ret)

3、获取指定节点下所有的建

import configparser
 
config = configparser.ConfigParser()
config.read(\'xxxooo\', encoding=\'utf-8\')
ret = config.options(\'section1\')
print(ret)

4、获取指定节点下指定key的值

import configparser
 
config = configparser.ConfigParser()
config.read(\'xxxooo\', encoding=\'utf-8\')
 
v = config.get(\'section1\', \'k1\')
# v = config.getint(\'section1\', \'k1\')
# v = config.getfloat(\'section1\', \'k1\')
# v = config.getboolean(\'section1\', \'k1\')
 
print(v)

5、检查、删除、添加节点

import configparser
 
config = configparser.ConfigParser()
config.read(\'xxxooo\', encoding=\'utf-8\')
 
# 检查
has_sec = config.has_section(\'section1\')
print(has_sec)
 
# 添加节点
config.add_section("SEC_1")
config.write(open(\'xxxooo\', \'w\'))
 
# 删除节点
config.remove_section("SEC_1")
config.write(open(\'xxxooo\', \'w\'))

6、检查、删除、设置指定组内的键值对

import configparser
 
config = configparser.ConfigParser()
config.read(\'xxxooo\', encoding=\'utf-8\')
 
# 检查
has_opt = config.has_option(\'section1\', \'k1\')
print(has_opt)
 
# 删除
config.remove_option(\'section1\', \'k1\')
config.write(open(\'xxxooo\', \'w\'))
 
# 设置
config.set(\'section1\', \'k10\', "123")
config.write(open(\'xxxooo\', \'w\'))

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.copystat(src, dst)
仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

shutil.copystat(\'f1.log\', \'f2.log\')

shutil.copy(src, dst)
拷贝文件和权限

import shutil
 
shutil.copy(\'f1.log\', \'f2.log\')

shutil.copy2(src, dst)
拷贝文件和状态信息

import shutil
 
shutil.copy2(\'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*\'))

shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件

import shutil
 
shutil.rmtree(\'folder1\')

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

import shutil
 
shutil.move(\'folder1\', \'folder3\')

shutil.make_archive(base_name, format,...)

创建压缩包并返回文件路径,例如:zip、tar

创建压缩包并返回文件路径,例如:zip、tar

  • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
  • 如:www                        =>保存至当前路径,文件名叫www
  • 如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/
  • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
  • root_dir: 要压缩的文件夹路径(默认当前目录)
  • owner: 用户,默认当前用户
  • group: 组,默认当前组
  • logger: 用于记录日志,通常是logging.Logger对象
#将 /Users/wupeiqi/Downloads/test 下的文件打包放置当前程序目录
import shutil
ret = shutil.make_archive("wwwwwwwwww", \'gztar\', root_dir=\'/Users/wupeiqi/Downloads/test\')
  
#将 /Users/wupeiqi/Downloads/test 下的文件打包放置 /Users/wupeiqi/目录
import shutil
ret = shutil.make_archive("/Users/wupeiqi/wwwwwwwwww", \'gztar\', root_dir=\'/Users/wupeiqi/Downloads/test\')

shutil对压缩包的处理是调用ZipFile和TarFile两个模块来处理的

import zipfile

# 压缩
z = zipfile.ZipFile(\'laxi.zip\', \'w\')  # a模式可以将文件添加至已有的压缩包
z.write(\'a.log\')
z.write(\'data.data\')
z.close()

# 解压
z = zipfile.ZipFile(\'laxi.zip\', \'r\')
z.extractall()  # .namelist()获取压缩包内所有文件, 列表形式 .extract(member)可以只解压出来一个特定文件
z.close(
zipfile
import tarfile

# 压缩
tar = tarfile.open(\'your.tar\',\'w\')
tar.add(\'/Users/wupeiqi/PycharmProjects/bbs2.log\', arcname=\'bbs2.log\')  # arcname是进入压缩包后,文件的名字
tar.add(\'/Users/wupeiqi/PycharmProjects/cmdb.log\', arcname=\'cmdb.log\')
tar.close()

# 解压
tar = tarfile.open(\'your.tar\',\'r\')
# tar.getmembers()查看压缩包内所有文件
tar.extractall()  # 可设置解压地址
#tar.extractfile(member) 解压某个特定的文件
tar.close()
tarfile

 

z.namelist()得到压缩包内的所有文件, 列表形式    z.extract(member)解压特定的文件

tar.getmembers()得到压缩包内所有文件, 列表形式  tar.extractfile(member)解压特定的文件

模块subprocess与系统命令

专门用于给python执行系统命令,比如dos的cmd命令流,Linux的命令流

call 

执行命令,返回状态码,shell=True就是像在cmd中正常书写,shell=False分开写命令

ret = subprocess.call(["ls", "-l"], shell=False)
ret = subprocess.call("ls -l", shell=True)

check_call

执行命令,如果执行状态码是 0 ,则返回0,否则抛异常

subprocess.check_call(["ls", "-l"])
subprocess.check_call("exit 1", shell=True)

check_output

执行命令,如果状态码是 0表示成功 ,则返回执行结果,否则抛异常

subprocess.check_output(["echo", "Hello World!"])
subprocess.check_output("exit 1", shell=True)

subprocess.Popen(...)即可执行简单命令也可执行复杂命令

用于执行复杂的系统命令

参数:

  • args:shell命令,可以是字符串或者序列类型(如:list,元组)
  • bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲
  • stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
  • preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
  • close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道。所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误(stdin, stdout, stderr)。
  • shell:同上
  • cwd:用于设置子进程的当前目录
  • env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
  • universal_newlines:不同系统的换行符不同,True -> 同意使用 \n     同时还有一个现象是,加了universal_newlines=True就可以显示字符串效果,不加或者为False就是字节类型
  • startupinfo与createionflags只在windows下有效将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等 

执行简单命令

import subprocess
ret1 = subprocess.Popen(["mkdir","t1"])
ret2 = subprocess.Popen("mkdir t2", shell=True)

终端输入的命令分为两种:

  • 输入即可得到输出,如:ifconfig
  • 输入进入某环境,再输入命令,如:python
import subprocess

obj = subprocess.Popen("mkdir t3", shell=True, cwd=\'/home/dev\',)  # 进入cwd路径再执行

最基本复杂的方法,如果你的python.exe的名字被改动的话,这里就应该是相应改动后的名字比如["python35"]

import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
# 先进入python解释器,stdin是写通道,stdout是输出通道,stderr是报错的通道,universal_newlines就是换行符 obj.stdin.write(
"print(1)\n") # 输入信息 obj.stdin.write("print(2)") obj.stdin.close() cmd_out = obj.stdout.read() # 接收输出信息 .read()就是按字符接收 .readlines()按行接收,之后可以用for line in obj.stdout.readlines():取出 obj.stdout.close() cmd_error = obj.stderr.read() # 接收异常信息 obj.stderr.close() print(cmd_out) print(cmd_error)

简化了读取和接收异常的作用

import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")

out_error_list = obj.communicate()  # 如果有输出就输出,有异常就报错
print(out_error_list)

更加简化,适用于单条命令

import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
out_error_list = obj.communicate(\'print("hello")\')
print(out_error_list)

执行系统命令

ret = subprocess.getoutput(“ipconfig”)  # 可以得到系统命令运行的结果. 可以直接运行windows的系统命令
print(ret)

或者使用.Popen()

obj = subprocess.Popen(["ipconfig"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
out_error_list = obj.communicate()
for line in out_error_list:
    print(line)

subprocess.Popen(["ipconfig"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

注意这里的["ipconfig"] 括号内就是直接用来输入控制台的命令,这是输入可以立即得到结果的命令

对于需要进入某种环境再输入命令的,比如要进入python环境,就需要先["python"] 进入python环境,之后再用obj.stdin.write(系统命令)

obj = subprocess.Popen(["python35"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
obj.stdin.write("print(\'hello\')")
out_error_list = obj.communicate()
print(out_error_list)  # 只能在一行内显示
# for line in out_error_list:  # 可以分多行显示
#     print(line)

 

logging模块

用于便捷记录日志且线程安全的模块. 多线程:同时多个人执行操作某个文件

不允许同时多人操作,排队

本质上就是一个便捷的写文件模块 

import logging

logging.basicConfig(filename=\'log.log\',
                    format=\'%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s\',
                    datefmt=\'%Y-%m-%d %H:%M:%S %p\',  # 时间格式
                    level=10)  # 日志等级,信息级别>=10的才会被记录。这里最好用logging.DEBUG表示10

logging.debug(\'debug\')  # level: 10   
logging.info(\'info\')  # level: 20
logging.warning(\'warning\')  # level: 30
logging.error(\'error\')  # level: 40
logging.critical(\'critical\')  # level: 50
logging.log(10, \'log\')  # 自定义一个level: 10 的信息

 

日志等级:只有【当前写等级】大于【日志等级】时,日志文件才被记录。

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0

 

多文件日志

同时向多个文件中写,先配置多个文件的格式

# 定义文件
file_1_1 = logging.FileHandler(\'l1_1.log\', \'a\')  # 创建文件
fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s")  # 创建l1_1.log的格式
file_1_1.setFormatter(fmt)  # 文件应用格式

file_1_2 = logging.FileHandler(\'l1_2.log\', \'a\')  # 创建l1_2.log的格式
fmt = logging.Formatter()
file_1_2.setFormatter(fmt)

# 定义日志
logger1 = logging.Logger(\'s1\', level=logging.ERROR)
logger1.addHandler(file_1_1)
logger1.addHandler(file_1_2)

# 写日志
logger1.critical(\'1111\')  # 满足条件就写文件,同时写入file_1_1和file_1_2

 

 

# 定义文件
file_2_1 = logging.FileHandler(\'l2_1.log\', \'a\')
fmt = logging.Formatter()
file_2_1.setFormatter(fmt)

# 定义日志
logger2 = logging.Logger(\'s2\', level=logging.INFO)
logger2.addHandler(file_2_1)

 

 

生成器

只要函数中出现了yield,就叫生成器函数

def xrange():
   yield 1
   yield 2
   yield 3
print(xrange())  # 直接打印获取不到数据
ret = xrange()
for i in ret:
   print(i)  # 分行打印出1,2,3

执行生成器函数,获取到的结果ret=xrange()就叫生成器,必须用循环来获取生成的数据

执行生成器函数时,内部是不执行的,只有循环的时候,内部才开始执行

执行生成器的方法r=xrange()然后r.__next__()时会执行一个yield和之前所有值,第二次执行.__next__()时会执行下一个yield和上一个yield间所有代码

 

下一次执行.__next__()会从上一次执行的位置开始

但是如果你一直使用xrange().__next__(),然后又用xrange().__next__()永远执行第一个yield,因为永远都在创建新的生成器,而不是用之前的生成器来操作

函数里一旦遇到return就立马退出了

 

自定义一个xrange()函数

def xrange(n):
   start = 0
   while start <= n:
       yield start
       start += 1
# for i in xrange(10):
#     print(i)
r = xrange(10)
print(r.__next__())  # 0
print(r.__next__())  # 1
print(r.__next__())  # 2
print(r.__next__())  # 3

 

迭代器:具有访问生成器能力

迭代器只能向前访问,不能后退。

执行方式

1 for循环:

for i in xrange(10):
    print(i)

 

2 生成器结果.__next__()方法

r = xrange(10)
print(r.__next__())  # 0
print(r.__next__())  # 1
print(r.__next__())  # 2
print(r.__next__())  # 3

 

3 next(生成器结果)

print(next(r))  # 0
print(next(r))  # 1
print(next(r))  # 2
print(next(r))  # 3

 

 

 

 

 

 

 

 

 

 

 

 

。。。。。。反射  内容还未看到,未完待续。。。。。。