一、概述
1、面向过程编程
核心是“过程”二字,过程指的是做事的步骤
基于该思想编写程序就好比在设计一条条的流水线
优点:复杂的问题流程化、进而简单化
缺点:扩展性差
2、面向对象编程
核心是“对象”二字,对象是一个的容器(盛放相关的数据与功能)
基于该思想编写程序就是造一个个对象/容器
优点:扩展性强
缺点:比起面向过程来说,加重了编程的复杂度
大白话:面向对象编程的核心就是造对象/容器盛东西,该容器就是一个内存空间
def choose(self): print('<%s:%s:%s>正在选课' %(self["stu1_name"],self["stu1_age"],self["stu1_gender"])) Student_dic={ "school":"oldboy", "choose":choose } stu1_dic={ "stu1_name":"egon", "stu1_age":18, "stu1_gender":"male", } stu2_dic={ "stu1_name":"jack", "stu1_age":19, "stu1_gender":"female", }
二、类与对象
# 什么是类?
# 类就是一个容器(一个内存空间),存放的是对象之间相同的数据与功能
# 为何要有类?
# 为了节省内存空间
学生对象1 数据 学校="oldboy" 名字="张三" 年龄=18 性别="male" 功能 选课功能 学生对象2 数据 学校="oldboy" 名字="李四" 年龄=19 性别="female" 功能 选课功能 学生对象3 数据 学校="oldboy" 名字="王五" 年龄=23 性别="male" 功能 选课功能 学生类 相同数据 学校="oldboy" 相同功能 选课功能
语法规定:先定义类,后调用类产生对象
class Student: # 相同数据 school ="oldboy" # 相同功能 def choose(self): print('is choosing course') # print("====>")
1.定义类=》把存有所有学生对象相同的数据与功能的内存空间准备好
类体代码会在类定义阶段立即运行,所以会产生一个类的名称空间,将类体代码运行过程中
产生的名字都丢到类的名称空间中,然后类名指向的就是类的名称空间
print(Student.__dict__)
print(Student.school) # Student.__dict__["school"]
2.调用类=》产生对象
# 调用类做的事情
# (1)造一个对象的内存空间,并将给内存空间与类的内存空间绑定
stu_obj1 = Student()
stu_obj2 = Student()
stu_obj3 = Student()
print(stu_obj1)
print(stu_obj2)
print(stu_obj3)
print(stu_obj1.__dict__)
print(stu_obj2.__dict__)
print(stu_obj3.__dict__)
print(stu_obj1.school)
3.为对象初始化自己独有的属性
stu_obj1.name = "张三" # stu_obj1.__dict__["name"]="张三" stu_obj1.age = 18 # stu_obj1.__dict__["age"]=18 stu_obj1.gender = "male" # stu_obj1.__dict__["gender"]="male" # print(stu_obj1.__dict__) stu_obj2.name = "李四" stu_obj2.age = 19 stu_obj2.gender = "female" stu_obj3.name = "王五" stu_obj3.age = 23 stu_obj3.gender = "male"
三、__int__方法
class Student: school ="oldboy" def choose(self): print('is choosing course') stu_obj1 = Student() stu_obj2 = Student() stu_obj3 = Student() # 为对象初始化自己独有的属性 stu_obj1.name = "张三" # stu_obj1.__dict__["name"]="张三" stu_obj1.age = 18 # stu_obj1.__dict__["age"]=18 stu_obj1.gender = "male" # stu_obj1.__dict__["gender"]="male" stu_obj2.name = "李四" stu_obj2.age = 19 stu_obj2.gender = "female" stu_obj3.name = "王五" stu_obj3.age = 23 stu_obj3.gender = "male" # 优化方案1: def init(obj,name,age,gender): obj.name = name obj.age = age obj.gender = gender init(stu_obj1, "张三" ,18,"male") init(stu_obj2, "李四" ,19,"female") init(stu_obj3, "王五" ,23,"male") print(stu_obj1.__dict__) print(stu_obj2.__dict__) print(stu_obj3.__dict__) # 终极解决方案: class Student: school ="oldboy" # 空对象,"张三",18,"male" def __init__(obj, name, age, gender): obj.name = name # 空对象.name = "张三" obj.age = age # 空对象.age = 18 obj.gender = gender # 空对象.gender = "male" # return None # 注意!!!:不能有返回值 def choose(self): print('is choosing course')
1.调用类发生的事情
# 1、先造一个空对象(空对象的本质就是一个与类的内存空间相关联的、对象的内存空间)
# 2、触发类中的__init__函数的运行,会将(空对象"张三" ,18,"male")一起传给__init__函数,完成为对象初始化属性的操作
# 3、将初始化好属性的对象的内存地址赋值给等号左侧的变量名stu_obj1
stu_obj1=Student("张三" ,18,"male") stu_obj2=Student("李四" ,19,"female") stu_obj3=Student("王五" ,23,"male") print(stu_obj1.__dict__) print(stu_obj2.__dict__) print(stu_obj3.__dict__)
四、类与对象的属性操作
class Student: school ="oldboy" n=0 def __init__(obj, name, age, gender): Student.n+=1 obj.name = name # 空对象.name = "张三" obj.age = age # 空对象.age = 18 obj.gender = gender # 空对象.gender = "male" def choose(self): print('is choosing course') stu_obj1=Student("张三" ,18,"male") stu_obj2=Student("李四" ,19,"female") stu_obj3=Student("王五" ,23,"male") print(Student.n) print(stu_obj1.n) print(stu_obj2.n) print(stu_obj3.n)
1.对象属性操作
1.对象的属性操作 (1) 访问 print(stu_obj1.name) print(stu_obj1.school) (2) 删除(只能清楚对象自己名称空间内的) del stu_obj1.name print(stu_obj1.__dict__) (3)新增与修改 stu_obj1.x = 111 print(stu_obj1.__dict__) stu_obj1.x = 222 print(stu_obj1.x)
2.类的属性操作
(1) 访问 print(Student.school) print(Student.choose) (2) 删除(只能清楚类自己名称空间内的) del Student.school print(Student.__dict__) (3)新增与修改 Student.xxx=111 Student.xxx=222 print(Student.__dict__)
3.总结
# 1、对象.属性:先从对象自己的内存空间找,没有则去类中查找 # 类.属性:直接去类中查找 stu_obj1.school = "xxx" print(stu_obj1.school) print(stu_obj2.school) print(stu_obj3.school) # 2、类中定义的属性类可以使用,但其实是为对象准备的 # 类的数据属性是所有对象共享的 print(Student.school,id(Student.school)) Student.school="OLDBOY" print(stu_obj1.school,id(stu_obj1.school)) print(stu_obj2.school,id(stu_obj2.school)) print(stu_obj3.school,id(stu_obj3.school)) # 类的函数属性 print(Student.choose) print(stu_obj1.choose) print(stu_obj2.choose) print(stu_obj3.choose)
五、绑定方法
class Student: school ="oldboy" def __init__(self, name, age, gender): self.name = name # 空对象.name = "张三" self.age = age # 空对象.age = 18 self.gender = gender # 空对象.gender = "male" def choose(self): print('%s is choosing course' %self.name) def tell_info(self): print('<%s:%s:%s>' %(self.name,self.age,self.gender)) stu_obj1=Student("张三" ,18,"male") stu_obj2=Student("李四" ,19,"female") stu_obj3=Student("王五" ,23,"male") stu_obj1.tell_info() stu_obj2.tell_info() stu_obj3.tell_info() # 类中定义的函数类可以访问,但是类来访问的时候就是一个普通函数,必须按照普通函数的玩法来 print(Student.choose) Student.choose(stu_obj1) print(stu_obj1.choose) print(stu_obj2.choose) print(stu_obj3.choose) # 类中定义的函数其实是给对象准备的,对象来用,称之为调用绑定方法 # 绑定方法的特殊之处在于自动传参:会将调用者当作第一个参数自动传入 stu_obj1.choose() # choose(stu_obj1) stu_obj2.choose() # choose(stu_obj2) stu_obj3.choose() # choose(stu_obj2) # 在python3里统一了类与类型的概念 l1=[1,2,3] # l1=list([1,2,3]) print(type(l1)) print(type(stu_obj1)) l2=[11,22] # l1=list([1,2,3]) l1.append(333) print(l1) l2.append(444) print(l2) list.append(l1,333) print(l1) list.append(l2,444) print(l2)
六、三大特性之封装
1 什么是封装
封装=》整合
2 为何要封装
为了让程序的整合程度更高,进而提升程序的解耦合程度
3 如何封装
3.1 把装到类或对象里的属性藏起来
(1)藏起来就是:把装进去的属性隐藏起来不让类外部访问到
(2)为何要将属性藏起来???
1、把数据属性藏器里的目的是:严格控制类外部使用者对属性的操作
不想让外部直接操作属性,通过开放接口的方式外部间接操作属性,
我们可以在接口之上附加任意控制逻辑,从而严格控制类外部使用者对属性的操作
2、把功能属性藏起来的目的是:为了隔离复杂度
(3)如何藏起来
在属性前加__开头,就会将该属性隐藏起来
注意:
(1) 这种不是真正意义上的隐藏,仅仅只是一种变形操作
(2) 该变形操作只在类定义阶段检查语法的时候变形一次,在此之后,新增的__开头的属性
都不会发生变形
(3) 该变形操作对外不内
4.应用
class People: def __init__(self,name,age,gender): self.__name=name self.age=age self.gender=gender def get_name(self): print("名字:%s" %self.__name) def set_name(self,val): if type(val) is not str: print("名字必须是str类型") return self.__name = val def del_name(self): print('不让删除') p=People('egon',18,'male') # p.__name=123123123 # print(p.name) # p.get_name() # p.set_name("EGON") p.del_name()
5.示例
class Foo: __x = 111 # _Foo__x = 111 def __init__(self, m, n): self.__m = m # self._Foo__m = m self.__n = n # self._Foo__n = n def __f1(self): # _Foo__f1 print('from f1') def f2(self): # self._Foo__m,self._Foo__n,self._Foo__x print(self.__m,self.__n,self.__x) print(Foo.__x) print(Foo.__f1) print(Foo.__dict__) print(Foo._Foo__x) print(Foo._Foo__f1) obj1=Foo(666,777) print(obj1._Foo__x) print(obj1._Foo__f1) print(obj1.__dict__) print(obj1._Foo__m) print(obj1._Foo__n) Foo.__zzz=1111 print(Foo.__dict__) print(Foo.__zzz) obj1=Foo(666,777) obj1.__yyy=222 print(obj1.__dict__) obj1.f2()
七、property装饰器
1.property基本使用
class People: def __init__(self, name, height, weight): self.name = name self.height = height self.weight = weight @property def bmi(self): return self.weight / (self.height ** 2) p = People('egon', 1.8, 70) # print(p.bmi()) # p.height=1.90 # print(p.bmi)
2.升级应用
class People: def __init__(self,name): self.__name=name @property def name(self): # get return "名字:%s" %self.__name @name.setter def name(self,val): # set if type(val) is not str: print("名字必须是str类型") return self.__name = val @name.deleter def name(self): # del print('不让删除') p=People('egon') print(p.name) p.name=123 del p.name print(p.name)
3.示例
class People: def __init__(self,name): self.__name=name def get_name(self): # get return "名字:%s" %self.__name def set_name(self,val): # set if type(val) is not str: print("名字必须是str类型") return self.__name = val def del_name(self): # del print('不让删除') name = property(get_name,set_name,del_name) p=People('egon')
八、三大特性之继承
1 什么是继承?
继承是一种新建子类的方式,新建的类称之为子类,被继承的类称之为父类、基类、超类
继承的特点:子类会遗传父类的所有属性
2 为何要继承
类存在的意义是为了解决对象与对象之间的冗余问题
而继承的意义是为了解决类与类之间冗余问题
继承体现的一种耦合思想,于扩展性的增强无益
3 如何继承
语法:python支持单继承与多继承
单继承: 一个子类只能继承一个父类
多继承: 一个子类可以同时继承多个父类
ps:继承表达的是一个is-a的关系
单继承符合is-a的关系,可以让继承结构相对简单一点
而多继承不符合is-a的关系,盲目使用多继承会加大继承结构的复杂度,所以继承的正确打开方式是Mixins机制
class Parent1: pass class Parent2: pass class Sub1(Parent1): pass class Sub2(Parent1,Parent2): pass print(Sub1.__bases__) print(Sub2.__bases__)
class Student: school = "oldboy" def __init__(self, name, age, gender,stu_id): self.name = name self.age = age self.gender = gender self.stu_id = stu_id def choose(self): print('is choosing course') class Teacher: school = "oldboy" def __init__(self, name, age, gender,level,salary): self.name = name self.age = age self.gender = gender self.level = level self.salary = salary def set_score(self, stu_obj, num): stu_obj.score = num print("老师<%s>给学生<%s>打了 %s 分" %(self.name,stu_obj.name,num)) stu_obj1=Student("tom",18,'male',3536) tea_obj1=Teacher("egon",18,'male',10,3000) # tea_obj1.set_score(stu_obj1,60) # print(stu_obj1.score)
# 如何在子类派生的新方法中重父类的功能 # 方案一:指名道姓地调用某一个类的函数,不依赖于继承 class People: school = "oldboy" # 空对象,"tom",18,'male' def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender class Student(People): # 空对象,"tom",18,'male',3536 def __init__(self,name,age,gender,stu_id): People.__init__(self,name,age,gender) self.stu_id=stu_id def choose(self): print('is choosing course') class Teacher(People): def __init__(self, name, age, gender,level,salary): People.__init__(self,name,age,gender) self.level = level self.salary = salary def set_score(self, stu_obj, num): stu_obj.score = num print("老师<%s>给学生<%s>打了 %s 分" %(self.name,stu_obj.name,num)) stu_obj1=Student("tom",18,'male',3536) tea_obj1=Teacher("egon",18,'male',10,3000) print(stu_obj1.__dict__) print(tea_obj1.__dict__)
九、多继承
coding:utf-8
在python中,针对每一个类python解释器都会基于c3算法为其计算出一个MRO列表
ps: 在python中有新式类与经典类之分
新式类:但凡是继承了object类的子类,以及该子类的子子孙孙类都是新式类
经典类:没有继承object类的子类,以及该子类的子子孙孙类都是经典类
注意:在python3中,如果一个子类没有继承任何类,那么python会让其默认继承object类
所以说,只有在python2中才存在经典类
1.由谁引发的属性查找,就参照谁的MRO列表
class E: def test(self): print('from E') class F: def test(self): print('from F') class B(E): def test(self): print('from B') class C(F): def test(self): print('from C') class D: def test(self): print('from D') class A(B, C, D): # def test(self): # print('from A') pass print(A.mro()) ''' [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>] '''
2.菱形继承:一个子类继承的多个父类汇聚到一个非object类
新式类与经典类关于属性的查找不一样
(1)新式类:广度优先
(2)经典类:深度优先
class G: # 在python2中,未继承object的类及其子类,都是经典类 # def test(self): # print('from G') pass class E(G): # def test(self): # print('from E') pass class F(G): def test(self): print('from F') class B(E): # def test(self): # print('from B') pass class C(F): def test(self): print('from C') class D(G): def test(self): print('from D') # print(D.mro()) class A(B,C,D): # def test(self): # print('from A') pass obj = A() # print(A.mro()) obj.test()
十、属性的查找
在单继承背景下的属性查找:
1、obj.x
对象=》对象的类=》父类=》父父类。。。
2、类名.x
当前类=》父类=》父父类。。。
class Foo: def f1(self): print("Foo.f1") def f2(self): print('Foo.f2') self.f1() # obj.f1() class Sub(Foo): def f1(self): print("Sub.f1") obj=Sub() obj.f2() """ Foo.f2 Sub.f1
class Foo: def __f1(self): # _Foo__f1 print("Foo.f1") def f2(self): print('Foo.f2') self.__f1() # self._Foo__f1 class Sub(Foo): def __f1(self): # _Sub__f1 print("Sub.f1") obj=Sub() obj.f2() """ Foo.f2 Sub.f1 """
十一、supper方法
如何在子类派生的新方法中重父类的功能
方案一:指名道姓地调用某一个类的函数,不依赖于继承
方案二:super()会返回一个特殊的对象,super().x该对象会参照当前类的mro列表去父类里找,严格依赖继承
class People: school = "oldboy" # 空对象,"tom",18,'male' def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def tell_info(self): print("名字:%s" %self.name) print("年龄:%s" %self.age) print("性别:%s" %self.gender) class Student(People): # 空对象,"tom",18,'male',3536 def __init__(self,name,age,gender,stu_id): # People.__init__(self,name,age,gender) # super(Student,self).__init__(name,age,gender) # 在python2中 super().__init__(name,age,gender) # 在python2中 self.stu_id=stu_id def choose(self): print('is choosing course') def tell_info(self): print("学号:%s" %self.stu_id) super().tell_info() class Teacher(People): def __init__(self, name, age, gender,level,salary): # People.__init__(self,name,age,gender) super().__init__(name,age,gender) # 在python2中 self.level = level self.salary = salary def set_score(self, stu_obj, num): stu_obj.score = num print("老师<%s>给学生<%s>打了 %s 分" %(self.name,stu_obj.name,num)) stu_obj1=Student("tom",18,'male',3536) tea_obj1=Teacher("egon",18,'male',10,3000) # print(stu_obj1.__dict__) # print(tea_obj1.__dict__) # stu_obj1.tell_info() # tea_obj1.tell_info() class A: def test(self): super().test() # 参照属性发起者的mro,去父类里找属性 class B: def test(self): print('from B') class C(A,B): pass # obj=C() # obj.test() # print(C.mro()) obj=A() print(A.mro()) obj.test()