0.知识点预览

configparse、XML、zipfile、tarfile

面向对象基础

1.模块进阶

1. configparser

liukai@bogon:~/PycharmProjects/s13/day7$ cat testfile
[info1]
name=liukai
age1= 19[info2]
name=lk
age1= 22
importconfigparser
config=configparser.ConfigParser()
config.read("testfile",encoding="utf-8")
sec=config.sections()print("sec:",sec)
k= config.items("info1")print("k:",k)
v= config.options("info2")print("v:",v)
vv= config.get("info1",'name')print("vv:",vv)
if_suc= config.has_section("info1")
if_suc2= config.has_section("info4")print(if_suc,if_suc2)

执行结果如下:

sec: ['info1', 'info2']
k: [('name', 'liukai'), ('age1', '19')]
v: ['name', 'age1']
vv: liukai
True False

代码剖析:read()方法:选择读取哪个文件;sections()方法:选择配置文件中的主节点;items()方法:选择特定主节点的信息,参数是节点名;options()方法:得到某个主节点的某个key的值;has_section()方法,判断配置文件是否有某个主节点。

liukai@bogon:~/PycharmProjects/s13/day7$ cat testfile
[info1]
name=liukai
age= 19[info2]
name=lk
age1= 22
importconfigparser
config=configparser.ConfigParser()
config.read("testfile",encoding="utf-8")
config.add_section("info3")
config.write(open("testfile","w"))print(config.has_section("info3"))
config.remove_section("info2")
config.write(open("testfile","w"))print(config.has_section("info2"))
has_k= config.has_option("info1","name")print(has_k)
config.remove_option("info1","age")print(config.get("info1","name"))
config.set("info1","age1","39")
config.write(open("testfile","w"))

执行结果如下:

True
False
True
liukai
liukai@bogon:~/PycharmProjects/s13/day7$ cat testfile
[info1]
name=liukai
age1= 39[info3]

代码剖析:重复的方法上面有,configparser的操作都是在内存中操作的,假如想使其生效,需要把内存的数据刷到硬盘上。write()方法就是这个功能。remove_sections()方法是删除整个主节点,连带其下面的数据都会删除。get()方法:获取主节点的某个key的值。set()方法:设置某个主节点的某个key的值。PS:假如没用write()方法,文件是不会被修改的。

2.xml相关模块

1.解析XML

解析XML:

方法一:

from xml.etree importElementTree as ET
tree= ET.parse("testxml")
root=tree.getroot()print(root.tag)for child inroot:for grantchild inchild:print(grantchild.tag,grantchild.attrib,grantchild.text)

方法二:

from xml.etree importElementTree as ET
str_xml= open("testxml","r").read()
root=ET.XML(str_xml)print(root.tag)for child inroot:for grantchild inchild:print(grantchild.tag,grantchild.attrib,grantchild.text)
liukai@bogon:~/PycharmProjects/s13/day7$ cat testxml

2

2023

141100

5

2026

59900

69

2026

13600

执行结果如下:

/usr/bin/python3 /Users/liukai/PycharmProjects/s13/day7/test.py
data
rank {'updated': 'yes'} 2year {}2023gdppc {}141100neighbor {'direction': 'E', 'name': 'Austria'} None
neighbor {'direction': 'W', 'name': 'Switzerland'} None
rank {'updated': 'yes'} 5year {}2026gdppc {}59900neighbor {'direction': 'N', 'name': 'Malaysia'} None
rank {'updated': 'yes'} 69year {}2026gdppc {}13600neighbor {'direction': 'W', 'name': 'Costa Rica'} None
neighbor {'direction': 'E', 'name': 'Colombia'} None

代码分析:解析XML有两种方法,一是直接解析xml文件;二是解析字符串类型的xml。这两种方法有一点不同,解析文件的形式可以直接修改xml,而字符串的形式也需要利用解析文件的方法修改xml到文件。parse()方法是解析文件。XML()方法是解析字符串。getroot()方法:获取根节点。

2.修改XML

liukai@bogon:~/PycharmProjects/s13/day7$ cat testxmlnew2

2

2023

141105

5

2026

59905

69

2026

13605

from xml.etree importElementTree as ET

tree= ET.parse("testxml")

root=tree.getroot()print(root.tag)for i in root.iter("gdppc"):

new_gdppc= int(i.text) + 5i.text=str(new_gdppc)

i.set("name","fuck")

i.set("age","88")print(i.attrib,i.text,i.tag)

tree2=ET.ElementTree(root)

tree2.write("testxmlnew2",encoding="utf-8")

执行结果如下:

data
{'name': 'fuck', 'age': '88'} 141105gdppc
{'name': 'fuck', 'age': '88'} 59905gdppc
{'name': 'fuck', 'age': '88'} 13605 gdppc
liukai@bogon:~/PycharmProjects/s13/day7$ cat testxmlnew2

2

2023

141105

5

2026

59905

69

2026

13605

代码解析:iter()方法:在当前节点的子孙中根据节点名称寻找所有指定的节点,并返回一个迭代器,ElementTree(root):保存文件。在这之前的所有操作都是在内存中执行的,只有ElementTree后才保存到文件。

3.生成XML

from xml.etree importElementTree as ETfrom xml.dom importminidomdefprettify(elem):"""将节点转换成字符串,并添加缩进。"""rough_string= ET.tostring(elem, 'utf-8')

reparsed=minidom.parseString(rough_string)return reparsed.toprettyxml(indent="\t")
root= ET.Element("family")
son1= ET.Element('son1',{"name":"son11"})
son2= ET.Element('son2',{"nane":"son22"})
grandson1= ET.Element('grandson', {'name': '儿11'})
grandson2= ET.Element('grandson', {'name': '儿12'})
son1.append(grandson1)
son1.append(grandson2)
root.append(son1)
root.append(son1)
raw_str=prettify(root)
f= open("family.xml",'w',encoding='utf-8')
f.write(raw_str)
f.close()

执行结果如下:

liukai@bogon:~/PycharmProjects/s13/day7$ cat family.xml<?xml version="1.0" ?>

代码解析:prettify函数将节点转换成字符串,并添加缩进。在创建XML时,要把内层数据加到外层数据中,如:root.append(son1)这样。

3.zipfile、tarfile
1.zipfile
importzipfile#压缩
z = zipfile.ZipFile('lk.zip', 'w')
z.write('a.log')
z.write('b.txt')
z.close()#解压
z = zipfile.ZipFile('lk.zip', 'r')
z.extractall()
z.close()

执行结果如下:

liukai@bogon:~/PycharmProjects/s13/day7$ ls lk.zip

lk.zip

liukai@bogon:~/PycharmProjects/s13/day7$ unzip lk.zip

Archive: lk.zip

extracting: a.log

extracting: b.txt

代码解析:ZipFile():创建一个压缩包,write():添加文件到压缩包。extractall():解压所有包。

2.tarfile

importtarfile#压缩
tar = tarfile.open('lk.tar','w')
tar.add('a.log', arcname='aaaa.log')
tar.add('b.txt', arcname='bbbb.txt')
tar.close()#解压
tar = tarfile.open('lk.tar','r')
tar.extractall()#可设置解压地址
tar.close()

执行结果如下:

liukai@bogon:~/PycharmProjects/s13/day7$ tar xf lk.tar

liukai@bogon:~/PycharmProjects/s13/day7$ ls aaaa.log bbbb.txt

aaaa.log bbbb.txt

代码解析:tarfile.open(),创建一个压缩包,add():添加文件到压缩包,可以改名。extractall():解压。

4.初识面向对象

1.面向对象与函数式编程

defmail(content):print("利用函数,已发出邮件,内容为%s" %content)

mail("hello")classMail:defmail(self,content):print("利用类,已发出邮件,内容为%s" %content)

m=Mail()

m.mail("fuck")

执行结果如下:

利用函数,已发出邮件,内容为hello

利用类,已发出邮件,内容为fuck

代码解析:用函数式编程,直接调用函数即可,用面向对象编程,需要先实例化一个对象,用对象来调用类里的方法。

结论:什么时候用面向对象?当某一些函数具有相同参数时,可以使用面向对象的方式,将参数值一次性的封装到对象,以后去对象中取值即可。

2.面向对象基础

1.创建类和对象

classMail:defmail(self,content):print("利用类,已发出邮件,内容为%s" %content)

m=Mail()print(type(Mail))

执行结果如下:

代码解析:创建类的格式:class 类名;创建类中方法的格式:def 方法名(self,xxx);实例化对象的格式:对象名 = 类名(),利用对象执行方法:对象名.方法名(123)

2.__init__()
classMail:def __init__(self,name,addr):
self.name=name
self.addr=addrdefmail(self,content):print("[%s]利用类,已发出邮件,内容为%s,到[%s]" %(self.name,content,self.addr))
m= Mail("lk","SB")
m.mail("fuck")

执行结果如下:

[lk]利用类,已发出邮件,内容为fuck,到[SB]

代码解析:__init__方法是类的构造方法,当执行类名()的时候,__init__方法会被自动执行。一般在初始数据的时候需要用到,类中的每个函数的第一个参数都是self,这是规定,这个self会被自动赋给对象本身。当代码执行到 m = Mail()的时候,会实例化一个对象,这个对象m 就被赋给所有的self,在__init__方法初识化后,以便其他方法比如mail()方法调用。

3.类的继承

1.类调用关系

classC1:def __init__(self, name, obj):
self.name=name
self.obj=objclassC2:def __init__(self, name, age):
self.name=name
self.age=agedefshow(self):print(self.name)classC3:def __init__(self, a1):
self.money= 123self.aaa=a1
c2= C2("liukai","22")
c1= C1("lk",c2)
c3=C3(c1)print(c1.obj.age)print(c1.obj.name)
c3.aaa.obj.show()

执行结果如下:

22liukai

liukai

代码解析:创建了三个类,C1、C2、C3;每个类都有构造方法,其中类C2有个show()方法。当执行到c2 = C2("liukai","22")时:实例化类C2的一个对象c2;c1 = C1("lk",c2)时:self.name = lk;self.obj = c2;c3 = C3(c1):self.aaa = c1;当执行到print(c1.obj.age)时,c1.obj = c2 ;c1.obj.age == c2.age,所以打印22,同理c1.obj.name 打印liukai,c3.aaa.obj.show():c3.aaa == c1,相当于c1.obj.show(),c1.obj == c2,故c2.show()打印的是c2.name == liukai

2.初识继承

classF1:defshow(self):print("show")deffoo(self):print(self.name)classF2(F1):def __init__(self,name):

self.name=namedefbar(self):print("bar")defshow(self):print("F2.show")

obj= F2("lk")

obj.foo()

执行结果如下:

lk

代码解析:F1为父类,子类继承父类的格式:class 子类名(父类名1,父类名2....),python支持多继承,这是和其他语言不同的地方。当执行obj = F2("lk")的时候,首先自动执行F2的__init__方法。obj.name = lk;当执行obj.foo()方法时,首先在F2类找,没有找到,便去其父类F1中找。找到foo()方法,因为self = obj,打印obj.name == lk

2.继承进阶

下面利用sockerserver源码来分析类继承的顺序。

importsocketserver

obj=socketserver.ThreadingTCPServer()

obj.serve_forever()

代码解析:导入socketserver模块,执行obj = sockerserver.ThreadingTCPServer(),假如ThreadingTCPServer()是个方法,就直接执行这个方法,假如这是个类,则就去找这个类的源码,要执行__init__()方法

class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

发现ThreadingTCPServer类无内容,继承了ThreadingMinIn类和TCPServer类,优先继承ThreadingMinIn。所以先去找ThreadingMinIn()源码

classThreadingMixIn:"""Mix-in class to handle each request in a new thread."""
#Decides how threads will act upon termination of the
#main process
daemon_threads =Falsedefprocess_request_thread(self, request, client_address):"""Same as in BaseServer but as a thread.
In addition, exception handling is done here."""
try:
self.finish_request(request, client_address)
self.shutdown_request(request)except:
self.handle_error(request, client_address)
self.shutdown_request(request)defprocess_request(self, request, client_address):"""Start a new thread to process the request."""t= threading.Thread(target =self.process_request_thread,
args=(request, client_address))
t.daemon=self.daemon_threads
t.start()

发现ThreadingMinIn类并无__init__()方法,则去找另一个父类TCPServer(),以下是TCPServer()的源码

classTCPServer(BaseServer):

address_family=socket.AF_INET

socket_type=socket.SOCK_STREAM

request_queue_size= 5allow_reuse_address=Falsedef __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):"""Constructor. May be extended, do not override."""BaseServer.__init__(self, server_address, RequestHandlerClass)

self.socket=socket.socket(self.address_family,

self.socket_type)

发现TCPServer有__init__方法,则执行这个方法。obj = sockerserver.ThreadingTCPServer() 这条语句执行完毕,执行下一条:obj.serve_forever();依旧去找

ThreadingTCPServer()的源码,去找serve_forever方法,发现没有该方法,去父类ThreadingMixIn找,也未找到,去父类TCPServer()类去找,也未找到,则去TCPServer()的父类BaseServer()去找,找到了serve_forever()方法。在该方法内,还执行了self._handle_request_noblock()。当执行self.xxxx方法时,这个self就等于obj,所以还要从最开始ThreadingTCPServer()找。按照刚才的方法找,从BaseServer()类中找到了该方法,在该方法内还要执行self.process_request()方法,虽然说这个类中有此方法,不过还要从头找。最后在ThreadingMixIn()类中就找到了,优先级高于BaseServer()类中的方法。

结束:这就是类的继承顺序。