python全栈开发笔记第三模块
第一部分
第一章 :面向对象(类)
一、面向过程编程
1、面向过程编程:主要是过程二字,所谓过程,就是指解决问题的步骤,也可以说是设计一套流水线(机械式的思维方式)
机械式的思维方式就是:把一个大的问题细分成子问题,再把子问题不断的细分成各个微小、详细、简单、可控范围内进行解决操作,
最后再把所有的细微程序按照规定的顺序连串执行至最终完成所有问题
(1)它的优点:复杂的问题流程化,进而简单化,难度不大
(2)它的缺点:扩展性不好,牵一发而动全身
二、面向对象编程
1、面向对象编程:和面向过程一样,它的核心就是对象二字,所谓对象,就是特征与技能的结合体,和面向过程的不同点是:
面向过程是把问题流程化(机械式的思维方式)
而对象就是一种上帝的视角模拟出的世界,为其他人注入思维,使所有事情都在可控范围内
(1)它的优点:可扩展性强,但是在一个软件质量属性内,可扩展性是其中的一个方面,但是它的占比非常高
(2)它的缺点:复杂度高,相对于面向过程,它的思维更加复杂
(3)它的应用场景:复杂的用户需求或经常变化的用户需求,互联网应用,游戏,企业内部应用
三、定义类 与 实例化编写对象
1、类的讲解:在面向对象内有一个非常重要的概念就是类。类:就是一系列对象相似的技能与特征的结合体
***强调:站在不同的角度,得到的分类概念是不一样的。
*在路飞学院角度:
(1)在现实中:类与对象的区分
对象1:郭毅龙
特征:
学校:路飞,name:guoyilong, 性别:男, age:25
技能:
学习,工作,吃,睡觉
对象2:Alex
特征:
学校:路飞, name: alex, 性别:男 , age:26
技能:
讲课,吃饭,学习,睡觉,泡妞
对象3:shanshan
特征:
学校:路飞, name:shanshan, 性别:女, age:18
技能:
眼模, 吃饭, 工作, 睡觉
总结现实中路飞学院类
相似特征:学习, 吃饭, 睡觉
(2)python中类的语法与格式
先定义类
class LuffyStudent: # 先定义类的名称 class 就像是函数的 def 是类的名,后面是类的总汇名 school = "luffycity" def luffy(self): print("学习!!!") def luffy_city(self): print("吃饭!!!") def Luffy___(self): print("睡觉!!!") # 再产生对象 stu1 = LuffyStudent() stu2 = LuffyStudent() stu3 = LuffyStudent() # 2、类的使用及方法(详见类的使用)
2、类的使用及方法
①、类 与函数不同,在定义阶段,它的内部代码已经执行,
在类内部,大多是函数的定义和变量的定义的组合,实际上也可以写其他的代码,没有限制
class LuffyStudent: # 先定义类的名称 class 就像是函数的 def 是类的名,后面是类的总汇名 school = "luffycity" def luffy(self): # 类内定义的函数加括号自带一个“self”属性,而这个属性,就是谁调用,就是谁 print("学习!!!") def luffy_city(self): print("吃饭!!!") def luffy_pro(self): # 在定义类的空间内,存在的代码称之为 ——> 类体 print("睡觉!!!") 2、查看类的名称空间,一个新的语法:打印类名+.__dict__ print(LuffyStudent.__dict__) # 可以看到类的名称空间,而类的名称空间,内部定义的函数被称作数据属性
3、调用类的方法
3.1查 res = LuffyStudent.school print(res) res1 = LuffyStudent.luffy res2 = LuffyStudent.luffy_city res3 = LuffyStudent.luffy_pro print(res1, res2, res3) 3.2增加 LuffyStudent.county = "China" print(LuffyStudent.__dict__) print(LuffyStudent.county) 3.3删除 del LuffyStudent.county print(LuffyStudent.__dict__) 3.4更改 LuffyStudent.school = "LUFFYCITY" print(LuffyStudent.school)
总结:类的函数体调用加括号,再赋值,就会产生新的子体(又称为分支)
4、类属性中,怎么展现不同的(独有的)特征,实现个性化定制
这里就要涉及到__init__文件方法
__init__方法用来为对象自己定制独有的特征 class LuffyStudent: school = "luffycity" # 定义一个函数调用自己同时定义位置参数(形参) def __init__(self, name, sex, age): # 需要在类内定义一个 __init__的函数用来使函数自己调用自己 self.Name = name self.Sex = sex self.Age = age def luffy(self): print("学习!!!") def luffy_city(self): print("吃饭!!!") def Luffy___(self): print("睡觉!!!") stu1 = LuffyStudent("郭毅龙", "男", 26) # 此方法相当于:LuffyStudent.__init__(stu1, "郭毅龙", "男", 26) 加上__init__方法后,实例化步骤 先产生一个空对象 LuffyStudent.__init__(stu1, "郭毅龙", "男", 26) # 再往属性内传递位置参数(实参) 1 、查看属性 print(stu1.Name, stu1.Sex, stu1.Age) 2、更改属性 stu1.Name ="Guoyilong" stu1.Sex = "man" stu1.Age = 27 print(stu1.Name, stu1.Sex, stu1.Age) 3、删除属性 del stu1.Name print(stu1.__dict__) 4、增加属性 stu1.class_name = "python" print(stu1.__dict__) 总结:同样方法,增加多个定制化属性 stu2 = LuffyStudent("alex", "man", 28) # 相当于: LuffyStudent.__init__(stu2, "alex", "man", 28)
5、类的属性查找详见
# 5、属性查找 """ (1)在现实中:类与对象的区分 对象1:郭毅龙 特征: 学校:路飞,name:guoyilong, 性别:男, age:25 技能: 学习,工作,吃,睡觉 对象2:Alex 特征: 学校:路飞, name: alex, 性别:男 , age:26 技能: 讲课,吃饭,学习,睡觉,泡妞 对象3:shanshan 特征: 学校:路飞, name:shanshan, 性别:女, age:18 技能: 眼模, 吃饭, 工作, 睡觉 """ class LuffyStudent: school = "luffycity" def __init__(self, name, sex, age): self.Name = name self.Sex = sex self.Age = age def luffy(self): print("%s学习!!!" % self.Name) def luffy_city(self): print("%s吃饭!!!" % self.Name) def Luffy___(self): print("%s睡觉!!!" % self.Name) stu1 = LuffyStudent("郭毅龙", "男", 26) stu2 = LuffyStudent("alex", "man", 23) stu3 = LuffyStudent("shanshan", "woman", 20) print(stu1.__dict__) print(stu2.__dict__) print(stu3.__dict__)
对象:特征与技能的结合体
类:一系列对象相似的特征与相似的技能的结合体 类中有数据属性:是所有对象共有的 print(id(LuffyStudent.school)) print(id(stu1.school)) print(id(stu2.school)) print(id(stu3.school)) 内存地址是相同的 类中有函数属性:是绑定给不同对象使用的,不同的函数属性绑定给不同的对象,对象调用绑定方法时,会把对象本身当做第一个参数传入给self print(id(LuffyStudent.luffy)) print(id(stu1.luffy)) print(id(stu2.luffy)) print(id(stu3.luffy)) 内存地址是hi不同的 5.1、类绑定函数属性 LuffyStudent.luffy(stu1) LuffyStudent.luffy(stu2) LuffyStudent.luffy(stu3) 5.2、类的调用方法 print(stu2.luffy_city) stu1.luffy_city() stu2.luffy() stu3.Luffy___() 类中定义的函数,实际上是给对象使用的,绑定的特殊之处是谁来掉函数,就把对象当做第一个参数传入 5.4、类的局部变量查找空间 stu1.xx = "is digit, stu1" LuffyStudent.xx = "is digit, luffy" print(stu1.xx)
6、python中一切皆对象
6.1在对象这个层面,由于角度与高度的不同,定义出的类也是截然不同的 6.2现实中的类并不完全等于程序中的类,比如现实中的公司类,在程序中要拆分成部门类,业务类等等 6.3python中,一切皆对象,在python3中统一了类(面对对象的类)与类型(数据类型)的概念 print(list) # 得到的也是个 class类型 ——><class 'list'> print(LuffyStudent) # 得到的也是一个class类型——><class '__main__.LuffyStudent'> 所以说,在我们调用某个模块加括号执行时,其实后台都是有类模块的调用执行的, 所以, 在 python 中,一切皆对象 lfd = [1, 2, 3, 5, 6, 6] # 定义一个列表 lfd.append(55) # 在使用内置方法时,其实就是用__init__调用了自己并绑定了自己
7、面向对象的可扩展性总结
7.1、定义类产生三个对象 class Chain: county = "China" def __init__(self, user, peo, dic): self.name = user self.sex = peo self.age = dic def rec(self): print("%s is digit!" % self.name) c1 = Chain("will", "man", 27) c2 = Chain("alex", "man", 28) c3 = Chain("shanshan", "woman", 18) print(c1.county) c1.rec()
8、小作业:
8.1、编写一个学生类,产生一堆学生对象。要求:有一个计数器属性,统计总共实例了多少个对象
class luffy: school = "luufy" count = 0 # 想要被所有人调用,必须写在公共区域(数据属性) def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age luffy.count += 1 # 想让每次调用都 +1 ,就必须在全局调用的 count 属性, 而不能只在函数内写 count += 1 def lenss(self): print("%s is tiger" % self.name) c1 = luffy("alex", "man", 18) c2 = luffy("will", "man", 22) c3 = luffy("loong", "woman", 18) print(c1.count)
8.2、模仿LOL,定义2个英雄类。
要求:
① 昵称要有名称、攻击力、生命值属性。
② 实例化出2个英雄对象。
③ 2个英雄之间可以互殴,一方血量为零时代表英雄死亡
class gilun: camp = "China" def __init__(self, name, blood, power): self.name = name self.blood = blood self.power = power def attack(self, enemy): enemy.blood -= self.power class revven: camp = "Noxus" def __init__(self, name, blood, power): self.name = name self.blood = blood self.power = power def attack(self, enemy): enemy.blood -= self.power G1 = gilun("will", 195, 37) R1 = revven("alex", 188, 42) print(R1.blood) G1.attack(R1) print(R1.blood) css2 = R1.attack(G1)
四、类的继承与重用
1、继承:继承是指类与类之间的关系是是一种什么“是”什么的关系(父类与子类),继承的功能之一就是解决代码重用问题,
继承是一种创建类的方式,在python中新建的类可以继承一个或多个父类, 父类又可以成为基类或超类,新建的类称为派生类或子类
class parentClass1: # 定义类 pass class parenClass2: pass class SubClass1(parentClass1): # 派生类/子类(基类/父类/超类) """派生类/子类(基类/父类/超类)""" pass class SubClass2(parenClass2, parentClass1): pass print(SubClass1.__bases__) # 查找继承关系方法 print(SubClass2.__bases__)
2、继承可以解决代码重用问题, (解决代码重用,需先找到继承关系)
class gilun: # 盖伦的英雄角色 camp = "China" def __init__(self, name, blood, power): self.name = name self.blood = blood self.power = power def attack(self, enemy): enemy.blood -= self.power class revven: # 瑞文的英雄角色 camp = "Noxus" def __init__(self, name, blood, power): self.name = name self.blood = blood self.power = power def attack(self, enemy): enemy.blood -= self.power G1 = gilun("will", 195, 37) R1 = revven("alex", 188, 42)它们的代码重用地方太多且它们都是英雄类,所以可以创建一个英雄类,解决代码重用问题 class Hero: # 把每个英雄相同的部分归为父类/基类/超类 count = 1 def __init__(self, name, blood, power): self.name = name self.blood = blood self.power = power def attack(self, enemy): enemy.blood -= self.power class revven(Hero): # 派生类/子类 pass class gilun(Hero): # count = 3 pass G1 = gilun("will", 195, 37) # G1.count = 5 R1 = revven("alex", 188, 42) print(G1.name, G1.blood, G1.power, G1.count) # 已解决代码重用的问题
# 属性查找小练习 class Foo: # 父类/基类/超类 def f1(self): print("from Foo.f1") def f2(self): print("from Foo.f2") self.f1() # 谁调用,self 就代表谁 class Bar(Foo): # 子类/派生类 def f1(self): print("from Bar.f2") b = Bar() b.f2() # 调用的是谁(去子类内查找 --> 去父类内查找,self:谁调用,self就是谁) print(b.__dict__, Bar.__bases__, )
五、派生类
class Hero: # 把每个英雄相同的部分归为父类/基类/超类 count = 1 def __init__(self, name, blood, power): self.name = name self.blood = blood self.power = power def attack(self, enemy): enemy.blood -= self.power class Revven(Hero): # 派生类/子类 camp = "Noxus" def attack(self, pde): # 派生类新的属性,如果自己有,就会用自己的,如果没有,就会用父类 print("from is pde") class Gilun(Hero): camp = "Demcia" pass G1 = Gilun("will", 195, 37) R1 = Revven("alex", 122, 40) G1.attack(R1) print(R1.blood) R1.attack(G1) # 对象的查找顺序, 先从自己找, 找不到去类找, 再没有去父类找
六、继承的实现原理
1、在python如何继承:python会计算出一个方法分析顺序列表,(类名.mro()),
有三条原则:① 对象会优先于自己的类内查找
② 子类会优先于父类被检
③ 多个父类会根据它们所在列表中的顺序被检查
④ 如果对下一个类存在2个合法的选择,会选择第一个父类
2、在python3中,所有类都一样都是【新式类】,但在python2中,类又分【经典类】和【新式类】
2.1、在python2中:
经典类:没有继承 object 的类(裸类),【父类/基类/超类】,以及它的子类【派生类】,都称之为经典类
class Foo: pass class Bar(Foo): pass # 这一个整体称之为【经典类】
# 新式类:继承了 object 的类,【父类/基类/超类】,以及它的子类【派生类】,都称之为经典类 class Sat(object): pass class Tds(Sat): pass # 这个整体称为新式类
2.2、在python3中,所有类都是新式类 ,如果不写(object), 系统会默认为填写了此项
class Addr: """此处不写(object), 系统会默认按照写了执行 也就是说,class Addr == class Addr() == class Addr(object) 三者关系相同""" pass class Bar1(): pass class Ppdf(object): pass print(Addr.__bases__) print(Bar1.__bases__) print(Ppdf.__bases__) # 打印结果发现三者都继承了【object】这个基类/超类/父类
3、Java 和 C# 一个派生类只能继承一个父类,但是在 python 中,一个【派生类/子类】 可继承多个 【父类/基类/超类】,所以类要有查找顺序,
在 python2 版本中,有【经典类】和【新式类】2种,
- 经典类多继承情况(查找属性不存在时)查找顺序:会按照深度优先查找,一条道走到底的方式 【参照图片】
- 新式类多继承情况(查找属性不存在时)查找顺序:会按照广度优先查找,探路方式【参照图片】
设置一个查找顺序的方法:
class A(object): def test(self): print("from is A") # pass class B(A): def test(self): print("from is B") # pass class C(A): def test(self): print("from is C") # pass class D(B): def test(self): print("from is D") # pass class E(C): def test(self): print("from is E") # pass class F(D, E): def test(self): print("from is F") pass f = F() f.test() # 事实证明图片内下面的(广度优先)方法是正确的【详见图例(8.1)】 # 验证新式类查找方法有个新的语法(F.mro()) print(F.mro()) # python2 中的经典类会继承深度优先的原则,一条道走到黑
七、在子类中重用父类的方法与属性
1、在子类派生出新的方法中重用父类的方法有2种:
① 方法一: 指名道姓方法(不依赖于继承,就算父类没有,也可在派生类内重新建立)
# 方法一: 指名道姓方法(不依赖于继承,就算父类没有,也可在派生类内重新建立) class Hero: count = 1 def __init__(self, name, blood, power): self.name = name self.blood = blood self.power = power def attack(self, enemy): enemy.blood -= self.power class revven(Hero): """在本类内调用其他类的属性""" def attack(self, pde): Hero.attack(self, pde) # 这种方法就叫指名道姓 print("from is pde") pass class gilun(Hero): count = 3 pass G1 = gilun("will", 195, 37) R1 = revven("alex", 122, 40) print(R1.blood) G1.attack(R1) print(R1.blood) G1.attack(R1) print(R1.blood) ####、指名道姓的另一个用法示例 class Hero: count = 1 def __init__(self, name, blood, power): self.name = name self.blood = blood self.power = power def attack(self, enemy): enemy.blood -= self.power class revven(Hero): """在本类内调用其他类的属性""" def __init__(self, name, blood, power, addc): # self.name = name # self.blood = blood # self.power = power Hero.__init__(self, name, blood, power) # 这种方法就叫指名道姓 self.addc = addc def attack(self, pde): Hero.attack(self, pde) # 指名道姓方法 print("from is pde") pass R1 = revven("alex", 122, 40, "宝剑") print(R1.blood) print(R1.__dict__)
② 方法二: super()这个方法是专门引用父类属性(依赖于继承)
# 方法二: super()这个方法是专门引用父类属性(依赖于继承) class Hero: count = 1 def __init__(self, name, blood, power): self.name = name self.blood = blood self.power = power def attack(self, enemy): enemy.blood -= self.power pass class revven(Hero): """在本类内调用其他类的属性""" def attack(self, pde): super().attack(pde) # python 3 的语法(super()括号内容可以省略) super(revven, self).attack(pde) # python 2 的写法(super()括号内容必须写) print("from is pde") pass class gilun(Hero): pass G1 = gilun("will", 195, 37) R1 = revven("alex", 122, 40) print(R1.blood) G1.attack(R1) print(R1.blood) G1.attack(R1) print(R1.blood) ** 另一个例子super() class Hero: count = 1 def __init__(self, name, blood, power): self.name = name self.blood = blood self.power = power def attack(self, enemy): enemy.blood -= self.power class revven(Hero): """在本类内调用其他类的属性""" def __init__(self, name, blood, power, addc): super(revven, self).__init__(name, blood, power) # super()方法的使用 self.addc = addc def attack(self, pde): Hero.attack(self, pde) print("from is pde") pass R1 = revven("alex", 122, 40, "宝剑") print(R1.blood) print(R1.__dict__)
2、super()与 MRO 的关系解析
#super()与 MRO 的关系解析 class A: def f1(self): print("from is A") super().f1() pass class B: def f1(self): print("from is B") pass class C(A, B): # super()跟MRO挂钩,C调用了属性, 就从C的 MRO 列表内查找,谁执行了就会按照谁的 MRO 列表顺序查找 pass print(C.mro()) c = C() c.f1() # 小结:指名道姓就是在子类中重新派生属性,不依赖于继承 # super()方法依赖于继承,实现方法跟类的 MRO属性挂钩
小结:指名道姓就是在子类中重新派生属性,不依赖于继承 super()方法依赖于继承,实现方法跟类的 MRO属性挂钩
八、组合
组合:是指在没有继承关系的两个类的互相调用(不能成立什么“是”什么的关系),而是会出现(什么“有”什么的关系或其他关系)
class Human: # 定义人类 school = "luffycity" def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex class Teacher(Human): # 定义老师类 def __init__(self, name, age, sex, level, salary): super().__init__(name, age, sex) self.level = level self.salary = salary def teach(self): print("%s is teacher!!" % self.name) class Student(Human): # 定义学生类 def __init__(self,name, age, sex, class_time): super().__init__(name, age, sex) self.class_time = class_time def learn(self): print("%s is learning!!" % self.name) print("%h-%m-%s") # 以上三个类都有继承关系
# 以上三个类都有继承关系,但是,下面这个类跟以上三个类 ,没有任何继承关系,也成立不了什么“是“什么的关系
class Course: # 定义一个课程类 def __init__(self, name, price, period): self.name = name self.price = price self.period = period def tell_info(self): """为了方便调用,设置一个打印方法,来打印课程信息""" print("course_name<%s>, course_price<%s>, course_period<%a>" % (self.name, self.price, self.period)) class Date: # 定义一个日期类 def __init__(self, year, mon, day): self.year = year self.mon = mon self.day = day def tell_format(self): print("%s-%s-%s" % (self.year, self.mon, self.day)) # 为了方便,提前写好格式便于调用 student1 = Student("will", "man", 26, "08-30-00") student2 = Student("loon", "man", 14, "08-30-00") # 把学生类实例化 teacher1 = Teacher("alex", "man", 18, 1, 3000) teacher2 = Teacher("egon", "man", 28, 5, 5000) # 把老师类实例化 python = Course("python", 50000, "3mons") linux = Course("linus", 6000, "4mons") # 把课程类实例化 time = Date(2000, 5, 18) time1 = Date(1999, 10, 18) # 以上执行都没问题,但是他们互不相干,怎么让他们绑在一块,下面就应用到组合(什么“有”什么)的关系
## 以上执行都没问题,但是他们互不相干,怎么让他们绑在一块,下面就应用到组合(什么“有”什么)的关系
teacher1.course = python teacher2.course = linux # 组合的调用(把老师类和课程类组合在一起)让老师能用到课类属性 student1.course = python student1.course2 = linux student2.course = linux # 组合的调用(把学生类和课程类组合在一起)让学生能用到课类属性 print(student2.course.name) # 通过学生实例化点点的方式查看组合属性内的值 student1.course.tell_info() # 直接通过点点的方式就能打印课程信息, student1.course2.tell_info() student1.course = [] student1.course.append(python) student1.course.append(linux) # 组合和类的扩展性 student2.course = {} student2.course["python"] = python student2.course["linux"] = linux # 组合类的可扩展性很强 student1.course.append(time) student2.course["time1"] = time1 print(student1.course) student2.course["time1"].tell_format() student1.course[-1].tell_format() student1.cdds = time student1.cdds.tell_format() # 学生和时间没有继承关系,但是通过组合依然可以调用实现代码不重用的目的 student1.course = python student1.course.tell_info() # 学生和课程没有继承关系,但是通过组合依然可以调用实现代码不重用的目的
九、抽象类与归一化
抽象类:不存在实物的类,抽象类只能被继承,不能被实例化。归一化,就是把这个抽象类以统一的形式规范化,便于好调用和维护
class People: # 定义人类,实现走的方法 def walk(self): print("is walking!") class Pig: # 定义人类,实现走的方法 def run(self): print("is running!") class Dog: # 定义人类,实现走的方法 def zou(self): print("is zouing!") peo = People() pig = Pig() dog = Dog() # 把他们实例化 # 调用走的方法 peo.walk() pig.run() dog.zou() # 发现他们虽然都是实现走路,但是调用方法太杂,
发现他们虽然都是实现走路,但是调用方法太杂,
******下面,有一种新的统一方法学习******
引入第三方模块:abc
import abc # 引入第三方模块:abc, class Animal(metaclass=abc.ABCMeta): # 先定义一个动物类,实现所有动物走和吃的 动作,******硬性规范, 不可更改****** @abc.abstractmethod # 想要实规定格式,必须安装装饰器 def run(self): pass @abc.abstractmethod def ent(self): pass class People: def walk(self): print("is walking!") class Pig: def run(self): print("is running!") class Dog: def zou(self): print("is zouing!") peo = People() pig = Pig() dog = Dog() peo.walk() pig.run() dog.zou() # 小结:以上所有内容,就是与继承相关的所有类型
小结:以上所有内容,就是与继承相关的所有类型