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()类中的方法。
结束:这就是类的继承顺序。