面向过程与面向对象:
面向过程:核心是过程二字,过程即解决问题的步骤,就是先干什么在干什么,基于该思想写程序就好比设计一条流水线,是一种机械的思维模式
优点:复杂的过程流程化,进而简单化
缺点:扩展性差
面向对象:核心是对象二字,对象是特征和方法的结合体,基于该思想编写程序就好比在创建一个世界,世界是由一个个对象组成,是一种‘上帝式’的思维方式
优点:可扩展性强
缺点:编程复杂度高,容易出现过度设计的问题
类
对象是特征与技能的结合体,类就是一系列对象相似的特征与技能的结合体
在现实世界中:一定先有的一个个具体的存在对象,后总结出的类
在程序中:一定保证先定义类,后产生对象
定义一个类
类里边的代码在类定义阶段就会执行
class Student: school = 'oldboy' def learn(self): print('is learning') def choose_course(self): print('choose course') print(Student.__dict__) # 类下边的所有特征方法 print(Student.school) # 数据属性 print(Student.learn) # 函数属性 Student.country = 'China' # 向类中添加属性(特征) Student.school = 'Oldboy' # 修改属性 del Student.country # 删除属性
类的实例化
调用类的过程又称之为实例化
1 得到一个返回值,即对象,该对象是一个空对象stu1
2 Student.__init__(stu1,'李三炮','男','18')
class Student: school = 'oldboy' # stu1,'李三炮','男','18' def __init__(self,name,sex,age): # 在调用类的时候会自动触发执行 self.Name = name self.Sex = sex self.Age = age # stu1.Name = '李三炮' # stu1.Age = '男' # stu1.Sex = 18 def learn(self): print('is learning') def choose_course(self): print('choose course') stu1 = Student('李三炮','男','18') print(stu1.__dict__) print(stu1.Name) print(stu1.Sex) print(stu1.Age)
# __init__ 方法内部可以有逻辑语句
# __init__ 不能有返回值(实例化①调用类的时候会返回一个空对象(这个时候已经返回了),②调用__init__方法为这个空对象初始化属性(这个时候在返回值就与第一步冲突了))
属性查找
1 查找一个对象的属性顺序是:先查找自己的名称空间(__dict__),再找类的名称空间(__dict__)
2 类的数据属性是所有对象共享的,所有对象都指向同一个内存地址
3 类中定义的函数是绑定给对象使用,不同的对象有不同的绑定方法,绑定给谁,就应该由谁来调用,谁来调用就会把谁当做第一个参数传给对应的函数。
小练习
新建一个老师的类,实例化老男孩的老师,并且每一位老师都可以知道当前已经实例化老师的数量
class Teacher: school = 'oldboy' count = 0 def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex Teacher.count += 1 def teacher(self): print('我在教python') taibai = Teacher('快老师', '28', '纯爷们') egon = Teacher('瞎驴', '28', '钢铁直男') print(taibai.count) print(egon.count)
对象之间的交互
class Gailun: # 定义一个名叫盖伦的类,可以实例化出玩家的盖伦 camp = '德玛西亚' # 每一个实例化出来的角色都属于德玛西亚 def __init__(self, name, life, fight): # 根据每个玩家喜好实例化出个性的盖伦 self.name = name # 给盖伦起名字 self.life = life # 生命值 self.fight = fight # 攻击力 def attack(self, enemy): # 盖伦攻击敌人的方法,得到的是敌人剩余的血量 enemy.life -= self.fight gl = Gailun('草丛伦', 1000, 200) # 实例化一个草丛伦出来 class Ruiwen: camp = '诺克萨斯' def __init__(self, name, life, fight): self.name = name self.life = life self.fight = fight def attack(self, enemy): enemy.life -= self.fight rw = Ruiwen('猛男雯雯', 300, 500) gl.attack(rw) # 盖伦对瑞文发起攻击,瑞文血量减少 print(rw.life) # 瑞文剩余血量
面向对象的继承
是一种新建类的方式,新建的类成为子类,子类会遗传父类的属性,减少代码冗余
在python中,子类(派生类)可以继承一个或多个父类(基类,超类)
class Parent1: pass class Parent2: pass class Sub1(Parent1): # 加括号 里边可以写要继承的父类 pass class Sub2(Parent1, Parent2): pass print(Sub1.__bases__) # 查看继承了哪些父类 print(Sub2.__bases__) print(Parent1.__bases__) # 默认继承了object类
在python2中类分为两种:
经典类:没有继承object类的类,以及该类的子类
新式类:继承了object类的类以及该类的子类
在python3中统一都为新式类
class Oldboypeople: school = 'oldboy' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex class Oldboyteacher(Oldboypeople): def teach(self): print('%s is teaching' %self.name) t1 = Oldboyteacher('egon',18,'男') t1.teach() class Oldboystudent(Oldboypeople): def learn(self): print('%s is learing' %self.name) s1 = Oldboystudent('dw',22,'男') s1.learn()
继承之深度优先、广度优先
python中一个类可以同时继承多个父类,如A(B,C,D)
如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性
如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先
经典类:深度优先
新式类:广度优先


class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): # def test(self): # print('from F') pass f1=F() f1.test() print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性 #新式类继承顺序:F->D->B->E->C->A #经典类继承顺序:F->D->B->A->E->C #python3中统一都是新式类 #pyhon2中才分新式类与经典类 继承顺序
子类重用父类的功能 super
子类调用父类的方法有两种
方法一:指名道姓,即父类名.父类方法() 这种方式不依赖与继承
#_*_coding:utf-8_*_ __author__ = 'Linhaifeng' class Vehicle: #定义交通工具类 Country='China' def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print('开动啦...') class Subway(Vehicle): #地铁 def __init__(self,name,speed,load,power,line): Vehicle.__init__(self,name,speed,load,power) self.line=line def run(self): print('地铁%s号线欢迎您' %self.line) Vehicle.run(self) line13=Subway('中国地铁','180m/s','1000人/箱','电',13) line13.run()
方法二:super() 这种方式必须依赖于继承
class Vehicle: #定义交通工具类 Country='China' def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print('开动啦...') class Subway(Vehicle): #地铁 def __init__(self,name,speed,load,power,line): #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self) super().__init__(name,speed,load,power) self.line=line def run(self): print('地铁%s号线欢迎您' %self.line) super(Subway,self).run() class Mobike(Vehicle):#摩拜单车 pass line13=Subway('中国地铁','180m/s','1000人/箱','电',13) line13.run()
多态和多态性
多态:同一种事物的多种形态
多态性:在不考虑对象的具体类型的情况下直接使用对象
组合
一种减少代码冗余的方式,可以实现对象之间的交互
class OldboyPeople: school = 'Oldboy' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def tell_info(self): print('<名字:{} 年龄:{} 性别{}>'.format(self.name,self.age,self.sex)) class OldboyStutent(OldboyPeople): def __init__(self,name,age,sex,course,stu_id,year,mon,day): OldboyPeople.__init__(self,name,age,sex) self.course = course self.stu_id = stu_id self.year = year self.mon = mon self.day = day def tell_info(self): print('我是学生 ') OldboyPeople.tell_info(self) def tell_birth(self): print("出生日期是{}年{}月{}日".format(self.year,self.mon,self.day)) class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,course,stu_id,year,mon,day): OldboyPeople.__init__(self,name,age,sex) self.course = course self.stu_id = stu_id self.year = year self.mon = mon self.day = day def tell_info(self): print('我是老师') OldboyPeople.tell_info(self) def tell_birth(self): print("出生日期是{}年{}月{}日".format(self.year,self.mon,self.day)) stu1 = OldboyStutent('田建宇',18,'男','linux',10,1994,10,10) stu1.tell_info() stu1.tell_birth() tea1 = OldboyTeacher('老白',20,'男','python',10,1988,12,20) tea1.tell_info() tea1.tell_birth() # 上述代码 可以查看每个学生和老师的生日,每个对象都有自己的生日,但是这样会造成代码冗余 # 采用组合的方法可以减少代码冗余
class OldboyPeople: school = 'Oldboy' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def tell_info(self): print('<名字:{} 年龄:{} 性别{}>'.format(self.name,self.age,self.sex)) class OldboyStutent(OldboyPeople): def __init__(self,name,age,sex,course,stu_id): OldboyPeople.__init__(self,name,age,sex) self.course = course self.stu_id = stu_id def tell_info(self): print('我是学生 ') OldboyPeople.tell_info(self) class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,course,stu_id): OldboyPeople.__init__(self,name,age,sex) self.course = course self.stu_id = stu_id def tell_info(self): print('我是老师') OldboyPeople.tell_info(self) class Birth: def __init__(self,year,mon,day): self.year = year self.mon = mon self.day = day def tell_birth(self): print('出生日期是:{}年{}月{}日'.format(self.year,self.mon,self.day)) stu1_birth = Birth(1994,8,8) tea1_birth = Birth(1988,7,9) # stu1_birth.tell_birth() # tea1_birth.tell_birth() stu1 = OldboyStutent('田建宇',18,'男','linux',10) stu1.birth = stu1_birth stu1.tell_info() stu1.birth.tell_birth() tea1 = OldboyTeacher('老白',20,'男','python',10) tea1.tell_info() tea1.birth = tea1_birth tea1.birth.tell_birth() # 因为出生日期年月日是冗余的代码,并且后边的对象都用的到,所以定义一个年月日类,查看生日 # 已经实例化的学生和老师的对象与生日类实例出来的对象绑定,就可以使用生日类里边的方法
# 对象的组合 实现对象之间的关联(学生选择课程) class OldboyPeople: school = 'Oldboy' def __init__(self, name, age, sex, date_obj): self.name = name self.age = age self.sex = sex self.birth = date_obj def tell_info(self): print('<名字:%s 年龄:%s 性别:%s>' % (self.name, self.age, self.sex)) class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, stu_id, date_obj): OldboyPeople.__init__(self, name, age, sex, date_obj) self.courses = [] self.stu_id = stu_id def learn(self): print('%s is learning' % self.name) def tell_info(self): print('我是学生:', end='') OldboyPeople.tell_info(self) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level, salary, date_obj): OldboyPeople.__init__(self, name, age, sex, date_obj) self.level = level self.salary = salary self.courses = [] def teach(self): print('%s is teaching' % self.name) def tell_info(self): print('我是老师:', end='') OldboyPeople.tell_info(self) class OldboySale(OldboyPeople): def __init__(self, name, age, sex, kpi, date_obj): OldboyPeople.__init__(self, name, age, sex, date_obj) self.kpi = kpi def tell_info(self): print('我是销售: ', end='') OldboyPeople.tell_info(self) class Date: def __init__(self, year, mon, day): self.year = year self.mon = mon self.day = day def tell_birth(self): print('出生日期是:<%s-%s-%s>' % (self.year, self.mon, self.day)) class Course: def __init__(self, name, price, period): self.name = name self.price = price self.period = period def tell_info(self): print('课程详细信息:<%s,%s,%s>' % (self.name, self.price, self.period)) Python = Course('python自动化养猪', 3000, '3mon') Linux = Course('大数据分析-linux', 3000, '3mon') date_obj = Date(1993, 3, 13) stu1 = OldboyStudent('田建宇', 28, 'female', 1, date_obj) stu1.courses.append(Python) stu1.courses.append(Linux) for course in stu1.courses: print(course.name)
抽象类
1 什么是抽象类
与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
2 为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案
3. 在python中实现抽象类
#_*_coding:utf-8_*_ __author__ = 'Linhaifeng' #一切皆文件 import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type='file' @abc.abstractmethod #定义抽象方法,无需实现功能 def read(self): '子类必须定义读功能' pass @abc.abstractmethod #定义抽象方法,无需实现功能 def write(self): '子类必须定义写功能' pass # class Txt(All_file): # pass # # t1=Txt() #报错,子类没有定义抽象方法 class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print('文本数据的读取方法') def write(self): print('文本数据的读取方法') class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print('硬盘数据的读取方法') def write(self): print('硬盘数据的读取方法') class Process(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print('进程数据的读取方法') def write(self): print('进程数据的读取方法') wenbenwenjian=Txt() yingpanwenjian=Sata() jinchengwenjian=Process() #这样大家都是被归一化了,也就是一切皆文件的思想 wenbenwenjian.read() yingpanwenjian.write() jinchengwenjian.read() print(wenbenwenjian.all_type) print(yingpanwenjian.all_type) print(jinchengwenjian.all_type)
4. 抽象类与接口
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
isinstance 和 issubclass
isinstance(obj,cls) 检查obj是否是cls的对象
issubcass(sub,super)检查sub是否是super的派生类
反射:用字符串类型的名字去操作变量
name = 1
eval(print(name))# 用eval会产生安全隐患
用反射的话没有安全问题,