一、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))