一、xml
xml同Jason意义一样,不过较为过去式
示例m.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>
搜索说明:
import xml.etree.ElementTree as ET tree = ET.parse('m.xml') root = tree.getroot() print(root.tag) #根标签 print(root.attrib) #根属性 print(root.text) #根内容 print(root.iter('year')) #全文搜索 print(root.find('country')) #在root的子节点查找,只查找一个 print(root.findall('country')) #在root的子节点找,找所有
结果:
遍历xml内容
import xml.etree.ElementTree as ET tree = ET.parse('m.xml') root = tree.getroot() for child in root: print(child.tag,child.attrib,child.text) for i in child: print(i.tag,i.attrib,i.text)
显示结果:
遍历year节点:
import xml.etree.ElementTree as ET tree = ET.parse('m.xml') root = tree.getroot() for node in root.iter('year'): print(node.tag,node.text)
结果:
修改文件内容,给year内容加1:
import xml.etree.ElementTree as ET tree = ET.parse('m.xml') root = tree.getroot() for node in root.iter('year'): n_year=int(node.text)+1 node.text=str(n_year) node.set('updated','yes') #新增更新属性 node.set('version','2.0') #新增版本号属性 tree.write('n.xml')
结果:
删除等级大于20的节点:
import xml.etree.ElementTree as ET tree = ET.parse('m.xml') root = tree.getroot() for country in root.findall('country'): # for rank in country.findall('rank'): #print(rank.tag,rank.attrib,rank.text) if int(rank.text) > 20: # country.remove(rank) #删除country的子节点 root.remove(country) #删除当前country节点 tree.write('b.xml')
结果:
新增节点:
等于大于20的新增节点coincidence
import xml.etree.ElementTree as ET tree = ET.parse('m.xml') root = tree.getroot() for country in root.findall('country'): for rank in country.findall('rank'): if int(rank.text) > 20: kk=ET.Element('coincidence') #添加节点 kk.text='windfall' #添加节点内容 kk.attrib={'lottery':'22000000'} #添加节点属性 country.append(kk) tree.write('c.xml')
结果:
二、configparser
configparser修改类似于my.ini配置文件的内容,有自成的规律
示例文件:
[info1] name = 'ckl' age = 21 hoppy = 'lang' is_young = True income = 99999.22 [info2] name = 'zld' age = 19 hoppy = 'eat' is_young = True income = 88888.33
获取操作
import configparser #导入模块,加载文件 config = configparser.ConfigParser() config.read('ckl.ini') #打印所有标题 res = config.sections() print(res) # ['info1', 'info2'] #打印某个标题的所有key ops = config.options(config.sections()[0]) print(ops) # ['name', 'age', 'hoppy', 'is_young', 'income'] #打印某个标题的所有key ops1 = config.options('info2') print(ops1) # ['name', 'age', 'hoppy', 'is_young', 'income'] #打印某个标题的所有key和value item_list = config.items('info1') for k,v in item_list: print(k,v) # name 'ckl' # age 21 # hoppy 'lang' # is_young True # income 99999.22 #获取section的name的值,字符串格式 v1 = config.get('info1','name') print(v1) # 'ckl' #获取section的age的值,int格式 v2 = config.getint('info1','age') print(type(v2)) print(v2) # <class 'int'> # 21 #获取section的is_young的值,布尔格式 v3 = config.getboolean('info2','is_young') print(v3) # True #获取section的income的值,浮点格式 v4 = config.getfloat('info1','income') print(v4) # 99999.22
删除操作
删除section
import configparser config = configparser.ConfigParser() config.read('ckl.ini') #删除section2 config.remove_section('info2') config.write(open('ckl.ini','w')) #写入文件
结果:
删除info1的age
import configparser config = configparser.ConfigParser() config.read('ckl.ini') #删除info1的age config.remove_option('info1','age') config.write(open('ckl.ini','w'))
结果:
判断存在section及option
import configparser config = configparser.ConfigParser() config.read('ckl.ini') #判断是否存在section print(config.has_section('info1')) #True #判断是否存在某个key print(config.has_option('info1','age')) # False
添加一个section
import configparser config = configparser.ConfigParser() config.read('ckl.ini') #添加一个section及option config.add_section('info3') config.set('info3','name','wukaka') config.set('info3','age','18') config.write(open('ckl.ini','w'))
#添加内容必须是字符串格式
结果:
三、hashlib
1.hash是一种算法在python3以后,代替了MD5和sha模块,主要是:SHA1,SHA224,SHA256,SHA512,MD5等,传入内容,得到一串hash值
2.hash特点:
传入内容一样,得到值一样;不能又hash值反解内容;hash算法不变情况下,值一样。
import hashlib m5 = hashlib.md5() m5.update('nihao'.encode('utf8')) print(m5.hexdigest()) # 194ce5d0b89c47ff6b30bfb491f9dc26 m6 = hashlib.md5() m6.update('ni'.encode('utf8')) m6.update('hao'.encode('utf8')) print(m6.hexdigest()) # 194ce5d0b89c47ff6b30bfb491f9dc26 #使用md5算法,无论update多少次,内容一样,结果就一样
如何校验文件?
import hashlib m5 = hashlib.md5() with open('b.xml','r') as fread: for line in fread: m5.update(line.encode('utf8')) print(m5.hexdigest()) # 8cb5a607e7803fd931112588e20e1f46 #不推荐如此使用,耗费内存 m6 = hashlib.md5() with open('b.xml','r') as fread: m6.update(fread.read().encode('utf8')) print(m6.hexdigest()) # 8cb5a607e7803fd931112588e20e1f46
hashlib好用,但是可以撞库来反解,这个时候就需要加盐了salt
import hashlib h8 = hashlib.sha256('zthhk'.encode('utf8')) #add salt h8.update('nihao'.encode('utf8')) print(h8.hexdigest()) # 6eab55b060e7bc08c849a0b1405f4e7720271f10b8832b82a4c76ac47470c27c
hmac用法根其它类似,但是起始必须加盐
import hmac h6 = hmac.new('bakayaro'.encode('utf8')) #类似加盐 h6.update('nihao'.encode('utf8')) print(h6.hexdigest()) # 6850656a1a3705600568152ff13e1195 h7 = hmac.new('bakayaroni'.encode('utf8')) h7.update('hao'.encode('utf8')) print(h7.hexdigest()) # d4891513a12338b58618516014ac9b25 ''' 虽然两次的总的字符串内容一致,但结果却不一样。这是因为,生成值的时候,先匹配加盐的部分, 再匹配update内容的部分,第一部分不一致,结果当然不一样 '''
四、subprocess
运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。
subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。
subprocess.call()
父进程等待子进程完成
返回退出信息(returncode,相当于Linux exit code)
subprocess.check_call()
父进程等待子进程完成
返回0
检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性,可用try…except…来检查
subprocess.check_output()
父进程等待子进程完成
返回子进程向标准输出的输出结果
检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性和output属性,output属性为标准输出的输出结果,可用try…except…来检查。
import subprocess res1 = subprocess.Popen('ls /Users/kindle/Desktop/',shell=True,stdout=subprocess.PIPE) res2 = subprocess.Popen('grep txt$',shell=True,stdin=res1.stdout,stdout=subprocess.PIPE) print(res2.stdout.read()) #这样做的好处是,第一个数据流可以和第二个数据流交互,并且交给grep
结果:
https://docs.python.org/2/library/subprocess.html
五、面向对象
对象是特征与功能的结合体;类是一系列对象相似特征与功能的结合体。
class WaterStaff: company = 'WaterLand' #类的数据属性(静态属性) def work(self): #类的函数属性(动态属性) print('we are working') def sleep(self): print('go home and sleep') #从本质上查看类的所有属性, print(WaterStaff.__dict__) #访问类的属性 print(WaterStaff.company) print(WaterStaff.sleep) # WaterLand # <function WaterStaff.sleep at 0x10149c378> #新增类的属性 WaterStaff.company = 'CKL' print(WaterStaff.company) # CKL #修改类的属性 WaterStaff.tech = 'niux' print(WaterStaff.tech) # niux #删除类的某个属性 del WaterStaff.tech
对象
#产生程序中的对象:类名加括号,调用类,产生一个该类的实际存在的对象,该调用过程称为实例化,产生的结果又可以称为实例。 obj1 = WaterStaff()
对象实例化
class WaterStaff: company = 'WaterLand' def __init__(self,name,age,gender): #在实例化时,产生对象后执行 self.name = name self.age = age self.gender = gender #上面实际就是如下: # obj1.name = '雪山人' # obj1.age = 25 # obj1.gender = 'male' def work(self): print('we are working') def sleep(self): print('go home and sleep') obj1 = WaterStaff('雪山人',25,'male') #执行两步 #1.先产生空对象obj1 #2.WaterStaff.__init__(obj1,'雪山人',25,'male'),这里self就是对象本身 print(obj1.__dict__) # {'name': '雪山人', 'age': 25, 'gender': 'male'}
对象属性操作
#修改属性 obj1.name = '森林人' print(obj1.name) # 森林人 #新增属性 obj1.car = 'horse' print(obj1.car) # horse #当然也可以如下修改 obj1.__dict__['age'] = 22 print(obj1.age) # 22 print(obj1.__dict__) # {'name': '森林人', 'age': 22, 'gender': 'male', 'car': 'horse'}
__init__不仅可以为对象初始化属性,还可以定时任何方法
class WaterStaff: company = 'WaterLand' def __init__(self,name,age,gender): #如果name不是字符串,就抛出异常 if not isinstance(name,str): raise TypeError('name must be a tye of string') self.name = name self.age = age self.gender = gender def work(self): print('we are working') def sleep(self): print('go home and sleep') obj1 = WaterStaff(889,25,'male')
__init__()函数return None
类的数据属性(静态属性)
class WaterStaff: company = 'WaterLand' def __init__(self,name,age,gender): #如果name不是字符串,就抛出异常 if not isinstance(name,str): raise TypeError('name must be a tye of string') self.name = name self.age = age self.gender = gender def work(self): print('we are working') def sleep(self): print('go home and sleep') obj1 = WaterStaff('雪山人',25,'male') obj2 = WaterStaff('森林人',33,'male') obj3 = WaterStaff('原野人',22,'female') #对象可以访问类的数据属性(静态属性);结论:类的数据属性共享给所有对象使用,id一样 print(obj1.company,id(obj1.company)) print(obj2.company,id(obj2.company)) print(obj3.company,id(obj3.company)) print(WaterStaff.company,id(WaterStaff.company)) # WaterLand 4368851632 # WaterLand 4368851632 # WaterLand 4368851632 # WaterLand 4368851632
类的函数属性(动态属性)
class WaterStaff: company = 'WaterLand' def __init__(self,name,age,gender): #如果name不是字符串,就抛出异常 if not isinstance(name,str): raise TypeError('name must be a tye of string') self.name = name self.age = age self.gender = gender def work(self): print('%s are working' %self.name) #objx.name def sleep(self): print('go home and sleep') obj1 = WaterStaff('雪山人',25,'male') obj2 = WaterStaff('森林人',33,'male') obj3 = WaterStaff('原野人',22,'female') WaterStaff.work(obj1) WaterStaff.work(obj2) WaterStaff.work(obj3) # 雪山人 are working # 森林人 are working # 原野人 are working
绑定方法
class WaterStaff: company = 'WaterLand' def __init__(self,name,age,gender): #如果name不是字符串,就抛出异常 if not isinstance(name,str): raise TypeError('name must be a tye of string') self.name = name self.age = age self.gender = gender def work(self): print('%s are working' %self.name) #objx.name def sleep(self): print('go home and sleep') obj1 = WaterStaff('雪山人',25,'male') obj2 = WaterStaff('森林人',33,'male') obj3 = WaterStaff('原野人',22,'female') print(obj1.work) print(obj2.work) print(obj3.work) print(WaterStaff.work) #除了类本身,其它对象的函数属性,都是绑定给其本身,绑定方法 # <bound method WaterStaff.work of <__main__.WaterStaff object at 0x104f83ba8>> # <bound method WaterStaff.work of <__main__.WaterStaff object at 0x104f83be0>> # <bound method WaterStaff.work of <__main__.WaterStaff object at 0x104f83c18>> # <function WaterStaff.work at 0x104f87378> #绑定方法:绑定给谁,就由谁来调用,谁来调用就把"谁"本身当做第一个参数传入 obj1.work() #WaterStaff.work(obj1) # 雪山人 are working
python3的类型
#python3 类型就是类 l1 = list() l2 = list() l1.append(3) #list.append(l1,3) print(l1) # [3] print(l2) # []
属性访问顺序
class WaterStaff: company = 'WaterLand' def __init__(self,name,age,gender): #如果name不是字符串,就抛出异常 if not isinstance(name,str): raise TypeError('name must be a tye of string') self.name = name self.age = age self.gender = gender def work(self): print('%s are working' %self.name) #objx.name def sleep(self): print('go home and sleep') obj1 = WaterStaff('雪山人',25,'male') obj2 = WaterStaff('森林人',33,'male') obj3 = WaterStaff('原野人',22,'female') #访问实例属性 print(obj1.__dict__) #{'name': '雪山人', 'age': 25, 'gender': 'male'} print(obj1.company) # WaterLand #修改obj1的数据属性 obj1.company = 'LandW' print(obj1.company) #LandW print(obj2.company) #WaterLand #修改类本身的数据属性 WaterStaff.company = 'wukaka' print(obj1.company) #LandW #obj1已经修改了自己的数据属性 print(obj2.company) #wukaka
类交互:
#怪物牛 class BullEv: # 怪物牛名称、血量、攻击力 def __init__(self,nickname,blvom=100,aggressivity=80): self.nickname = nickname self.blvom = blvom self.aggressivity = aggressivity #攻击技能,血量等于自己攻击力减去对方血量 def attack(self,rival): rival.blvom-=self.aggressivity #怪物蜘蛛 class SpiderEv: #怪物蜘蛛名称、血量、攻击力 def __init__(self,nickname,blvom=80,aggressivity=100): self.nickname = nickname self.blvom = blvom self.aggressivity = aggressivity # 攻击技能,血量等于自己攻击力减去对方血量 def attack(self,rival): rival.blvom -= self.aggressivity B1=BullEv('wukaka') S1=SpiderEv('Bengde') #攻击前血量 print('attack before ------>',S1.blvom) B1.attack(S1) #攻击后血量 print('after attack------->',S1.blvom)
结果:
上面类有重复代码,如何解决?那么久看看类的继承
类的继承
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass
继承:
#继承一个父类 print(SubClass1.__bases__) #(<class '__main__.ParentClass1'>,) #继承两个父类 print(SubClass2.__bases__) #(<class
继承与重用
人、鸟、兔子,都有吃、叫、睡觉的功能创建三个类
class Mankind: def eat(self): print("eat something") def talk(self): print("talk something") class Bird: def eat(self): print("eat something") def talk(self): print("talk something") class Rabbit: def eat(self): print("eat something") def talk(self): print("talk something") M1 = Mankind() M1.eat() B1 = Bird() B1.eat()
运行结果:
继承父类
问题:吃、说的功能重复代码,是否可以继承?改写如下:
class Animal: def eat(self): print("eat something") def talk(self): print("talk something") class Mankind(Animal): pass class Bird(Animal): pass class Rabbit(Animal): pass M1 = Mankind() M1.eat() B1 = Bird() B1.eat()
结果:
问题二、每个子类应该有自己的名字年龄等信息,修改如下:
class Animal: def eat(self): print("%s eat something" %self.name) def talk(self): print("talk something") class Mankind(Animal): def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender class Bird(Animal): def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender class Rabbit(Animal): def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender M1 = Mankind('wukaka',33,'male') M1.eat() B1 = Bird('flygo',3,'female') B1.eat()
运行结果:
问题三、这三个子类有共同的属性名字、年龄,性别等,重写如下:
class Animal: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def eat(self): print("%s eat something" %self.name) def talk(self): print("talk something") class Mankind(Animal): pass class Bird(Animal): pass class Rabbit(Animal): pass M1 = Mankind('wukaka',33,'male') M1.eat() B1 = Bird('flygo',3,'female') B1.eat()
结果相同:
重用
人类还有国籍,所以定义如下:
class Animal: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def eat(self): print("%s eat something" %self.name) def talk(self): print("talk something") class Mankind(Animal): def __init__(self,name,age,gender,native): self.name = name self.age = age self.gender = gender self.native = native class Bird(Animal): pass class Rabbit(Animal): pass M1 = Mankind('wukaka',33,'male','china') print(M1.__dict__) #{'name': 'wukaka', 'age': 33, 'gender': 'male', 'native': 'china'} M1.eat() B1 = Bird('flygo',3,'female') B1.eat()
这样,如下部分就与父类重复:
self.name = name self.age = age self.gender = gender
改写如下:
class Animal: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def eat(self): print("%s eat something" %self.name) def talk(self): print("talk something") class Mankind(Animal): def __init__(self,name,age,gender,native): Animal.__init__(self,name,age,gender) #改写部分 self.native = native class Bird(Animal): pass class Rabbit(Animal): pass M1 = Mankind('wukaka',33,'male','china') print(M1.__dict__) #{'name': 'wukaka', 'age': 33, 'gender': 'male', 'native': 'china'} M1.eat() B1 = Bird('flygo',3,'female') B1.eat()
这样实际上指明父类调用,根继承无关,结果:
派生新的属性
人有一个自己说的方法,如下:
class Animal: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def eat(self): print("%s eat something" %self.name) def talk(self): print("talk something") class Mankind(Animal): def __init__(self,name,age,gender,native): Animal.__init__(self,name,age,gender) #改写部分 self.native = native def takl(self): print('*** a chinese man is saying') class Bird(Animal): pass class Rabbit(Animal): pass M1 = Mankind('wukaka',33,'male','china') print(M1.__dict__) #{'name': 'wukaka', 'age': 33, 'gender': 'male', 'native': 'china'} M1.eat() M1.takl() B1 = Bird('flygo',3,'female') B1.eat()
结果:
如果人talk的方法也想用父类的talk呢?
class Animal: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def eat(self): print("%s eat something" %self.name) def talk(self): print("talk something") class Mankind(Animal): def __init__(self,name,age,gender,native): Animal.__init__(self,name,age,gender) #改写部分 self.native = native def takl(self): Animal.talk(self) #调用父类的 print('*** a chinese man is saying') class Bird(Animal): pass class Rabbit(Animal): pass M1 = Mankind('wukaka',33,'male','china') print(M1.__dict__) #{'name': 'wukaka', 'age': 33, 'gender': 'male', 'native': 'china'} M1.eat() M1.takl() B1 = Bird('flygo',3,'female') B1.eat()
结果:
组合
一个人可以有多个房子,房子有地址、面积、价格,一个鸟也可以有多个窝,窝也有地址、面积、价格等,如下:
class Animal: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def eat(self): print("%s eat something" %self.name) def talk(self): print("talk something") class Mankind(Animal): def __init__(self,name,age,gender,native,house_addr,house_area,house_price): Animal.__init__(self,name,age,gender) self.native = native self.house_addr = house_addr self.house_area = house_area self.house_price = house_price def takl(self): Animal.talk(self) print('*** a chinese man is saying') class Bird(Animal): def __init__(self,name,age,gender,house_addr,house_area,house_price): Animal.__init__(self,name,age,gender) self.house_addr = house_addr self.house_area = house_area self.house_price = house_price class Rabbit(Animal): pass M1 = Mankind('wukaka',33,'male','china','pudong','120','12000000') print(M1.__dict__) B1 = Bird('flygo',3,'female','nanhui','0.01','10') print(B1.__dict__)
运行:
{'name': 'wukaka', 'age': 33, 'gender': 'male', 'native': 'china', 'house_addr': 'pudong', 'house_area': '120', 'house_price': '12000000'} {'name': 'flygo', 'age': 3, 'gender': 'female', 'house_addr': 'nanhui', 'house_area': '0.01', 'house_price': '10'}
这里人的房子和鸟的窝就出现重复代码,如果人有多个房子,鸟有多个窝呢?如何实现?
class Animal: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def eat(self): print("%s eat something" %self.name) def talk(self): print("talk something") class Mankind(Animal): def __init__(self,name,age,gender,native): Animal.__init__(self,name,age,gender) self.native = native #定义house列表 self.house = [] def takl(self): Animal.talk(self) print('*** a chinese man is saying') class Bird(Animal): def __init__(self,name,age,gender,): Animal.__init__(self,name,age,gender) #定义house列表 self.house = [] #定义house类 class House: #定义house_addr,house_area,house_price def __init__(self,house_addr,house_area,house_price): self.house_addr = house_addr self.house_area = house_area self.house_price = house_price #定义个函数属性,来显示house相关信息 def show_info(self): print("house address: %s house area: %s house price %s" %(self.house_addr,self.house_area,self.house_price)) class Rabbit(Animal): pass #实例化第一个house house1 = House('pudong','109','11000000') #实例化第二个house house2 = House('putuo','98','9900000') M1 = Mankind('wukaka',33,'male','china') #为人类添加两个house M1.house.append(house1) M1.house.append(house2) print(M1.__dict__) # {'name': 'wukaka', 'age': 33, 'gender': 'male', 'native': 'china', 'house': [<__main__.House object at 0x109dfa048>, <__main__.House object at 0x109dfa080>]} #循环人类house,也就是对象house1和house2 for obj in M1.house: obj.show_info() #调用对象函数
结果:
组合实现了不同类有相同的属性,但不需要从父类继承的操作。
继承原理
单继承说明
class A: def f1(self): print("A.f1") def f2(self): self.f1() class B(A): def f1(self): print("B.f1") obj_b = B() obj_b.f2()
结果:
B.f1
分析:1.初始化类B。2.调用B类的实例化对象,运行方法f2()。3.找B类f2(),没有找到,则找继承的父类A。4.A类有方法f2(),调用方法f2,f2()则调用self.f1()。self本身就是B类,所以查找B的方法f1()有找到,则执行,结果就是B.f1
super 调用父类
super 调用父类静态属性
class Animal: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def eat(self): print("%s eat something" %self.name) def talk(self): print("talk something") class Mankind(Animal): def __init__(self,name,age,gender,native): # Animal.__init__(self,name,age,gender) #这是直接调用父类的,不是继承 # super() 是父类对象的实例 # print(super().__init__) #实例化父类,绑定方法,绑定其本身,所以调用父类的新写法 super().__init__(name,age,gender) #其本身已经是绑定方法,所以不需要self self.native = native def takl(self): Animal.talk(self) #调用父类的 print('*** a chinese man is saying') M1 = Mankind('wukaka',33,'male','china') M1.eat()
结果:
wukaka eat something
super 调用父类动态属性
class Animal: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def eat(self): print("%s eat something" %self.name) def talk(self): print("talk something") class Mankind(Animal): def __init__(self,name,age,gender,native): # Animal.__init__(self,name,age,gender) #这是直接调用父类的,不是继承 # super() 是父类对象的实例 # print(super().__init__) #实例化父类,绑定方法,绑定其本身,所以调用父类的新写法 super().__init__(name,age,gender) #其本身已经是绑定方法,所以不需要self self.native = native def takl(self): # Animal.talk(self) #调用父类的动态属性,不是继承 super().eat() #super 调用父类动态属性的写法 print('*** a chinese man is saying') M1 = Mankind('wukaka',33,'male','china') M1.eat()
结果:
wukaka eat something
区别:super()依赖于继承,而直接调用不依赖继承
Animal.talk(self) #不依赖父类继承 super().eat() #super 依赖父类继承
super() 查找的是MRO列表:
[<class '__main__.Mankind'>, <class '__main__.Animal'>, <class 'object'>]
关于MRO列表查找疑惑
class A: def test(self): super().test() class B: def test(self): print("B") class C(A,B): def test(self): print("C") obj_a = A() obj_a.test()
运行:
分析:1.实例化A类。2.A类对象调用动态属性test()。3.A类的test调用super().test(),也就是父类的test(),而A类没有父类,所以报错。
如果这样运行:
class A: def test(self): super().test() class B: def test(self): print("B") class C(A,B): pass obj_c = C() obj_c.test()
会不会报错?答案是不会,而且结果是
B
是不是迷惑了?分析如下:
1.实例化C类。2.实例化对象调用test。3.C类没有test,找父类A,父类A有test。4.A类调用test的时候调用的是super().test(),这时候,super()就不是找父类了,而是查找MRO列表的顺序,接下来查找B类,B类有方法test(),所以运行B类的test
print(C.mro()) # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
classmethod
classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。
看一个示例:
class Mysql: def __init__(self,host,port): self.host = host self.port = port conn1=Mysql('127.0.0.1',3306) print(conn1.port,conn1.host)
运行结果:
如果每次都需要传入地址、端口等参数,很麻烦,有没有办法可以从配置文件中读取?
配置文件内容:
HOST='10.2.3.4' PORT=8898
代码:
import settings class Mysql: def __init__(self,host,port): self.host = host self.port = port @classmethod def from_conf(cls): #这个方法绑定给类 return cls(settings.HOST,settings.PORT) conn1=Mysql('127.0.0.1',3306) print(conn1.port,conn1.host) conn2=Mysql.from_conf() #Mysql.from_conf是绑定方法,绑定给谁就给谁用,给谁用就把自己当做第一个参数 print(conn2.host,conn2.port)
运行结果:
方法绑定说明
import settings class Mysql: def __init__(self,host,port): self.host = host self.port = port @classmethod def from_conf(cls): #绑定给类的方法 return cls(settings.HOST,settings.PORT) def func1(self): #绑定给对象的方法 pass conn1=Mysql('127.0.0.1',3306) # print(conn1.port,conn1.host) # conn2=Mysql.from_conf() # #Mysql.from_conf是绑定方法,绑定给谁就给谁用,给谁用就把自己当做第一个参数 # print(conn2.host,conn2.port) print(conn1.from_conf) print(conn1.func1)
结果说明:
staticmethod
import settings import uuid class Mysql: def __init__(self,host,port): self.host = host self.port = port self.id = self.create_id() @staticmethod def create_id(): #普通方法,既不绑定给对象,也不绑定给类 return uuid.uuid1() conn1=Mysql('127.0.0.1',3306) conn2=Mysql('127.0.0.1',3306) conn3=Mysql('127.0.0.1',3306) print(conn1.id,conn2.id,conn3.id) print(Mysql.create_id) #普通函数 print(conn1.create_id) #普通函数
结果:
class School: def __init__(self,school_name,school_address): self.school_name = school_name self.school_address = school_address class Course(School): def __init__(self,course_name,course_period,couse_price,course_outline): self.course_name = course_name self.course_period = course_period self.course_price = couse_price self.course_outline = course_outline def get_school(self,school): return school.__dict__ class ClassG(Course): def __init__(self,class_name): self.class_name = class_name def get_course(self,course): return (course.__dict__,self.class_name) class Student(ClassG): def __init__(self,student_name): self.student_name = student_name class Teacher(ClassG): def __init__(self,teacher_name,): self.teacher_name = teacher_name class TeachRecord: pass class StudyRecord: pass s1=School('mazhu','pudong') c1=Course('python',120,8990,[4,6,7,8]) g1=ClassG('19s') st1=Student('whb') print(st1.get_course(g1))