本节大纲:
一:在python中,有两种编程思想。1:函数式编程。2:oop。无论是函数式编程还是oop都是相辅相成。并不是说oop比函数式编程就好。各有各的优缺点。
在其他语言中java等只能以面向对象进行编程。
函数放在类中叫做方法。
只有对象才能调用类中的方法,也就是说需要创建该类的对象然后调用该类的方法。
而函数调用直接进行调用。
类需要创建对象,通过对象调用执行类中的方法。而函数可以直接进行调用,无需创建对象。
1:创建对象:和函数式调用雷同:类名()
obj=coo()
2:通过对象执行类中的方法.对象和属性用圆句点(.)进行连接。
obj.co()
二:定义类的语法:
a:class 类名:
def 方法名(self,x)
passs
关键字:class ,然后跟着类名。任何函数在类中都叫方法。方法的第一个参数必须是self。在构造对象的时候,会自动把对象名字传给self。类中的方法只能是对象来调用。
b:对象创建:
对象名=类名()
c:通过对象来执行类中的方法。
三:类和对象的关系
在创建对象的时候,在对象的内部有一个类对象指针指向自己的类。当对象执行check()方法的时候,根据类指针找到自己的类sql中的方法check进行执行。并把对象obj当做实参传给方法check的self形参。
并不是对象有该方法。
四:在什么情况下使用面向对象?
需求:对数据库的增删改查操作
a:函数式编程
1 #!/usr/bin/env python 2 def check(host,user,pwd,sql): 3 pass 4 def add(host,user,pwd,sql): 5 pass 6 def delete(host,user,pwd,sql): 7 pass 8 def update(host,user,pwd,sql): 9 pass 10 check('1.1.1.1','evil','123','....') 11 add('1.1.1.1','evil','123','....') 12 delete('1.1.1.1','evil','123','....') 13 update('1.1.1.1','evil','123','....')
没调用都需要传入,host、user、pwd、sql参数。如果操作数据库的动作较多,会反复传入多次。
面向对象编程:
1 class sql: 2 def check(self,sql): 3 print(self.host) 4 print(self.user) 5 print(self.password) 6 def crate(self,sql): 7 pass 8 def update(self,sql): 9 pass 10 def delete(self,sql): 11 pass 12 13 obj=sql() 14 obj.host='1,1,1,1' 15 obj.user='evil' 16 obj.password='123' 17 obj.check("select * from A") 18 1,1,1,1 19 evil 20 123
当我们执行相关操作的时候,我们只需要把数据封装到对象里,在调用类的方法的时候,自动获取对象的属性值,即可连接到数据库。而不需要每次都需要把账号、主机、密码都传入方法中进行操作。
什么时候用面向对象呢?
当某一些函数中有相同的参数的时候,可以用面向对象的封装特性,将参数值一次性的封装到对象,之后执行该对象的类的方法的时候不需要每次传入对应的参数。每次执行类的方法的时候,只需要从对象中取值即可。
五:self参数。
self 是python自动传值的形式参数。
当对象调用类的方法的时候,会自动把对象的赋值给self形式参数。
当obj调用类的方法check时候,self会自动赋值为obj,当obj1调用类sql的方法check时候,self会自动赋值obj1。
也就是说可以通过创建不通的对象来实现连接不通的数据库。
六:构造方法__init__
当执行类名()时候会自动执行类中的方法:__init__方法。
1 class sql: 2 def __init__(self): 3 print('__init__') 4 def check(self,sql): 5 print(self.host) 6 print(self.user) 7 print(self.password) 8 def crate(self,sql): 9 pass 10 def update(self,sql): 11 pass 12 def delete(self,sql): 13 pass 14 15 obj=sql() 16 __init__
也就是说当执行对象创建的时候,也就是执行sql()的时候,会自动执行__init__方法。
根据这个特性,我们以后将对象封装的数据,方法__init__方法中。
1 class sql: 2 def __init__(self,a,b,c): 3 self.host=a 4 self.user=b 5 self.password=c 6 def check(self,sql): 7 print(self.host) 8 print(self.user) 9 print(self.password) 10 def crate(self,sql): 11 pass 12 def update(self,sql): 13 pass 14 def delete(self,sql): 15 pass 16 17 obj=sql('1.1.1.1','evil','123') 18 obj.check('selec.....') 19 20 1.1.1.1 21 evil 22 123
通过对象创建的时候,对__init__方法的参数进行实参的传入。
__init__方法叫做构造方法。构造对象的方法。
七:调用顺序
函数调用的时候,需要先声明函数,才能进行调用,而在类中,没有这个上下顺序,可以在方法声明前进行调用。
1 class sql: 2 def __init__(self,a,b,c,d): 3 self.host=a 4 self.user=b 5 self.password=c 6 self.check(d) 7 def check(self,sql): 8 print(self.host) 9 print(self.user) 10 print(self.password) 11 print(sql) 12 def crate(self,sql): 13 pass 14 def update(self,sql): 15 pass 16 def delete(self,sql): 17 pass 18 19 obj=sql('1.1.1.1','evil','123','check') 20 1.1.1.1 21 evil 22 123 23 check
其中self.check(d)相当于obj.check('check')只不过是在构造方法执行的时候调用这个函数。
八:封装
1 class game_life: 2 def __init__(self,name,age,fight): 3 self.name=name 4 self.age=age 5 self.fight=fight 6 def battle_row(self): 7 self.fight=self.fight-200 8 def study(self): 9 self.fight=self.fight+100 10 def person_game(self): 11 self.fight=self.fight-500 12 13 14 obj=game_life('苍井井','18',1000) 15 obj.battle_row() 16 print(obj.fight) 17 800
也就说 可以通过类的方法对类的对象的值进行修改。
面向对象三大特性:封装、继承、多太。
封装:将数据通过__init__方法封装到对象中。供方法进行调用和操作。
九:封装的对象可以数据,也可以是对象,可以任意东西。
1 class a: 2 def __init__(self,name,age): 3 self.name=name 4 self.age=age 5 def show(self): 6 print(self.name) 7 class b: 8 def __init__(self,name,obj): 9 self.name=name 10 self.obj=obj 11 12 obj_a=a('evil',18) 13 obj_b=b('tom',obj_a) 14 print(obj_b.obj.name) 15 print(obj_b.obj.age) 16 evil 17 18
也就是对象ojb封装的是name和对象obj_a.也就是说封装可以是数据,也可以是对象,也可以是任意事物。
1 class a: 2 def __init__(self,name,age): 3 self.name=name 4 self.age=age 5 def show(self): 6 print(self.name) 7 class b: 8 def __init__(self,name,obj): 9 self.name=name 10 self.obj=obj 11 class c: 12 def __init__(self,name,a): 13 self.name=name 14 self.a=a 15 16 obj_a=a('evil',18) 17 obj_b=b('tom',obj_a) 18 obj_c=c('jack',obj_b) 19 print(obj_c.a.obj.name) 20 obj_c.a.obj.show() 21 22 evil 23 evil
res=obj_c.a.obj.show()
print(res)
注意show方法没有返回值,所以res值是None.
也就是通过obj_c怎么访问obj_a.show()或者obj_a.name?
如上图所示obj_c.a是obj_b对象,而obj_b.obj对象是obj_a对象,obj_a.name obj_a.show()是我们想要的结果。
所以:obj_c.a.obj.name obj_c.a.obj.show()
十:继承
在其他语言里java里只有单继承,而在python 中可以有多继承。语法:
1 class a: 2 def show(self): 3 print('show') 4 class b(a): 5 def co(self): 6 print('co') 7 obj=b() 8 obj.show() 9 show
也就是在类名后面加个(继承类的类名)即可。也就是说a相当于与b是父类,b相对于a是子类,或者说a是基类,b是派生类。注意说法,各自对应。谁是父类,谁是子类只是相对而言。子类可以继承父类的方法。父类不可以继承子类的方法。
如上,当对象obj调用方法show的时候,优先看自己类中是否有该方法,如果有就执行,不去父类找该方法。如果该方法没有的话去找他的父类是否有该方法。如果有就执行。
1 class a: 2 def show(self): 3 print('show') 4 class b(a): 5 def co(self): 6 print('co') 7 def show(self): 8 print('b') 9 obj=b() 10 obj.show() 11 b
继承的本质:子类没有的方法,方法在父类里,在对象调用该方法的时候,相当于父类的方法拿到子类的中。如下:
1 class a: 2 def __init__(self,name): 3 self.name=name 4 def show(self): 5 print(self.name) 6 class b(a): 7 def __init__(self,name): 8 self.name=name 9 def co(self): 10 print('co') 11 obj=b('tom') 12 obj1=a('evil') 13 obj.show() 14 tom
也就是说子类对象obj在调用父类show方法的时候,传入的self.name是子类的self.name。也就是说相当于把父类的方法show拿到子类中。
如上所示:对象obj在执行方法show时候优先去子类b中找show方法,如果子类没有show方法的话,去父类的a中找show方法,并执行show方法,show方法
相当于拿到子类b中,因为子类b在构造对象obj的时候,已经封装数据self.name=name,所以获取的是子类的b的对象数据,也就是tom。而不是父类a的self.name属性。
1 class a: 2 def s1(self): 3 print(a) 4 def s2(self): 5 self.s1() 6 class b(a): 7 def s1(self): 8 print('b') 9 def s3(self): 10 self.s2() 11 12 obj=b() 13 obj.s3() 14 b
继承优先级:如果子类继承父类,对象在调用方法的时候,优先子类中找,如果有该方法执行该方法,如果没有在去父类找该方法。本质是:把父类的该方法拿到子类中,进行调用执行。
继承优先执行子类的中方法,如果子类中有该方法执行子类方法。
另一个思路:在执行self.xx的时候需要注意self是指执行对象,需要去执行对象的类型中去找,如果没有,再去父类找。
十一:多继承(python3中)
1 class a: 2 def f2(self): 3 print('class a') 4 class b: 5 def f2(self): 6 print('class b') 7 class c(a,b): 8 def f3(self): 9 pass 10 obj=c() 11 obj.f2() 12 class a
多继承的时候,优先从左有到右。如上classc(a,b)子类c中没有方法f2,在去父类a,b中找,优先顺序 a 然后是b。从左到右顺序。
没有父类交叉的情况:
1 class s1: 2 def f1(self): 3 print('s1') 4 class s2(s1): 5 def f2(self): 6 print('s2') 7 class s3: 8 def f1(self): 9 print('s3') 10 class s4(s2,s3): 11 def f2(self): 12 print('s4') 13 obj=s4() 14 obj.f1() 15 s1
当有纵向和横向的多继承时候,顺序:首先按继承顺序,从左到右优先级,先从对象的类中找,如果没有按对象类型的父类(从左右)中找,如果没有,去他的父类的父类中找,如果最后
没有的话,在找下一个对象的类父类平行的中父类中找,按照之前如果没有在去父类的父类找。。 如果没有在回到对象的类的平行父类中。。
父类有交叉的情况:
1 class s_1: 2 def f2(self): 3 print('s_1') 4 class s0(s_1): 5 def f2(self): 6 print('s0') 7 class s1(s_1): 8 def f1(self): 9 print('s1') 10 class s2(s1): 11 def f1(self): 12 print('s2') 13 class s3(s0): 14 def f1(self): 15 print('s3') 16 class s4(s2,s3): 17 def f1(self): 18 print('s4') 19 obj=s4() 20 obj.f2() 21 22 s0
优先没交集的父类,当这个2个都遍历照完之后在找交集部分,在去平行的父类找也就是第7步。代码如下:
1 class s_1: 2 def f1(self): 3 print('s_1') 4 class s0(s_1): 5 def f1(self): 6 print('s0') 7 class s1(s_1): 8 def f1(self): 9 print('s1') 10 class s2(s1): 11 def f1(self): 12 print('s2') 13 class s3(s0): 14 def f1(self): 15 print('s3') 16 class s5: 17 def f2(self): 18 print('s5') 19 class s4(s2,s3,s5): 20 def f1(self): 21 print('s4') 22 obj=s4() 23 obj.f2() 24 s5
关于__init__构造方法:当对象创建的时候,会自动去自己类中找__init__构造方法,如果没有去父类找。如果有的话执行__init__方法。如果都没有就不执行该方法。
1 class s1: 2 def __init__(self,name): 3 self.name=name 4 def show(self): 5 pass 6 class s2(s1): 7 def look(self): 8 pass 9 10 11 obj=s2('evil') 12 print(obj.name) 13 evil
查找顺序和 多继承顺序是一样的。
模块:configparser 针对特殊配置文件进行操作。其本事是对文件的open()操作。
如下:
1 [section1] # 节点 2 k1 = v1 # 值 3 k2:v2 # 值 4 5 [section2] # 节点 6 k1 = v1 # 值
操作:获取所有节点
1 import configparser 2 3 con=configparser.ConfigParser() 4 con.read('1.txt',encoding='utf-8') 5 res=con.sections() 6 print(res)
['section1', 'section2']
获取指定节点下的key和值
1 import configparser 2 3 con=configparser.ConfigParser() 4 con.read('1.txt',encoding='utf-8') 5 res=con.items('section1') 6 print(res) 7 [('k1', 'v1'), ('k2', 'v2')]
获取指定节点下的键值
1 import configparser 2 3 con=configparser.ConfigParser() 4 con.read('1.txt',encoding='utf-8') 5 res=con.options('section1') 6 print(res) 7 ['k1', 'k2']
获取指定节点指定值
1 import configparser 2 3 con=configparser.ConfigParser() 4 con.read('1.txt',encoding='utf-8') 5 res=con.get('section1','k1') 6 print(res) 7 v1
1 import configparser 2 3 con=configparser.ConfigParser() 4 con.read('1.txt',encoding='utf-8') 5 has_sec = con.has_section('section1') 6 print(has_sec) 7 8 # 添加节点 9 con.add_section("sec_1") 10 con.write(open('1.txt', 'w')) 11 12 # 删除节点 13 con.remove_section("sec_1") 14 con.write(open('1.txt', 'w'))
XML模块
xml是实现不同语言或程序之间进行数据交换的协议
格式如下:
1 <data> 2 <country name="Liechtenstein"> 3 <rank updated="yes">2</rank> 4 <year>2023</year> 5 <gdppc>141100</gdppc> 6 <neighbor direction="E" name="Austria" /> 7 <neighbor direction="W" name="Switzerland" /> 8 </country> 9 <country name="Singapore"> 10 <rank updated="yes">5</rank> 11 <year>2026</year> 12 <gdppc>59900</gdppc> 13 <neighbor direction="N" name="Malaysia" /> 14 </country> 15 <country name="Panama"> 16 <rank updated="yes">69</rank> 17 <year>2026</year> 18 <gdppc>13600</gdppc> 19 <neighbor direction="W" name="Costa Rica" /> 20 <neighbor direction="E" name="Colombia" /> 21 </country> 22 </data>
解析xml文件
1 from xml.etree import ElementTree as E 2 str_xml = open('1.xml', 'r').read()# 打开文件,读取包含xml文件内容 3 root = E.XML(str_xml)# 将字符串解析成xml特殊对象,root代指xml文件的根节点
1 from xml.etree import ElementTree as E 2 tree = E.parse("1.xml")# 直接解析1.xml文件 3 root = tree.getroot()# 获取xml文件的根节点
遍历xml文件的所有内容
1 from xml.etree import ElementTree as E 2 3 #第一种解析 4 """ 5 str_xml = open('1.xml', 'r').read()#打开文件读取1.xml文件 6 root = ET.XML(str_xml)#将字符串解析成xml特殊对象,root代指xml的根节点。 7 """ 8 # 第二种解析 9 # 直接解析xml文件 10 tree = E.parse("1.xml") 11 root = tree.getroot()#获取xml文件的根节点 12 # operation 13 print(root.tag)#最外层标签 14 15 for child in root:# 遍历1.xml的第二层 16 print(child.tag, child.attrib) # 第二层节点的标签名称和标签属性 17 for i in child:# 遍历XML文档的第三层 18 print(i.tag,i.text)# 第二层节点的标签名称和内容
因为修改的节点内容是修改在内存中的内容,需要把内存中内容写入文件中。
1 from xml.etree import ElementTree as E 2 3 # 直接解析xml文件 4 tree = E.parse("1.xml") 5 6 # 获取xml文件的根节点 7 root = tree.getroot() 8 9 #operation 10 11 # 顶层标签 12 print(root.tag) 13 for i in root.iter('year'):# 循环year节点 14 15 new_year = int(i.text) + 1# 将year节点中的内容自增一 16 i.text = str(new_year) 17 18 19 i.set('name', 'alex') # 设置属性 20 i.set('age', '18') 21 del i.attrib['name']# 删除属性 22 23 24 #保存到文件中 25 tree.write("3.xml", encoding='utf-8')
删除节点操作:
1 from xml.etree import ElementTree as E 2 3 # 解析文件方式 4 5 # 直接解析xml文件 6 tree = E.parse("1.xml") 7 8 root = tree.getroot()# 获取xml文件的根节点 9 10 #operation 11 12 13 print(root.tag)#输出顶层标签 14 for country in root.findall('country'):# 遍历data下的所有country节点 15 rank = int(country.find('rank').text)# 获取每一个country节点下rank节点的内容 16 if rank > 50: 17 18 root.remove(country)# 删除指定country节点 19 tree.write("2.xml", encoding='utf-8')# 保存文件