OOP将对象作为程序基本单元,一个对象包含了数据和操作数据的函数
面向过程把函数切分为子函数,把大块函数切割为小块函数降低系统复杂度
面向对象的程序设计把计算机程序视为一组对象的集合,每个对象可以接收其他对象发过来的消息并进行处理,计算机程序的执行就是一系列消息在各个对象之间传递。设计思想为抽象出class,根据class创建instance(实例、对象)。三大特点:封装、继承、多态
python中自定义的对象数据类型就是面向对象中的类的概念
一 面向对象三大特性
封装:将属性和方法书写到类的里面的操作;封装可以为属性和方法添加私有权限
继承:子类默认继承父类的所有属性和方法;子类可以重写父类的属性和方法
多态:传入不同的对象,产生不同的结果
二 类class和实例(对象)instance
类是创建实例(对象)的抽象的模板,实例是根据类创建出来的一个个具体对象,各个实例拥有的数据相互独立
类是对一系列具有相同特征和行为的事物的统称,是一个抽象的概念,不是真实存在的事物,特征即属性,行为即方法
类用来创建对象,对象是类创建出来的真实存在的事物,先有类,再有对象
1、定义类
语法:class 类名(要继承的类名):,类名遵循大驼峰命名习惯
class Student1(object): # 默认继承所有类的顶级类object def __init__(self,name,score): self.name=name self.score=score
class后是类名,通常大写开头。括号中表示从哪个类继承下来,如果没有则写object类
2、创建实例(对象)
语法:对象名 = 类名()
bart=Student1()
方法是与实例绑定的函数,可以直接访问实例的数据
2.1 定义类中的特殊方法
class Student1(object): def __init__(self,name,score): self.name=name self.score=score
特殊方法名init前后有两个 ‘_’ 下划线,类中函数的第一个参数永远是self,表示创建实例的本身,在方法内部就可以将各种属性绑定到self,有了__init__方法后则不能传入空值,要传入与方法匹配的参数,但不用传self
bart=Student1('Bart',34) # 为实例变量绑定属性
2.2 调用实例方法
即在实例中的函数,语法为对象名.函数名()
class WashMashin(): # 默认继承所有类的顶级类object def wash(self): print("Washing") haier=WashMashin() haier.wash() # 调用实例方法
2.3 self
self指调用该函数的对象
class WashMashin(): def wash(self): print("Washing") print(self) # <__main__.WashMashin object at 0x0000023682DFC940> —— 内存地址相同,self指代haier haier=WashMashin() print(haier) # <__main__.WashMashin object at 0x0000023682DFC940> haier.wash()
3、数据封装
在类的内部定义访问数据的函数,把数据封装起来,无需知道方法内部的细节
class Student1(object): def __init__(self,name,score): self.name=name self.score=score def print_score(self): print('%s: %s' % (self.name,self.score))
定义的方法print_score也是第一个参数为self,调用时就不用传参了
bart.print_score() # Bart: 34
三 访问限制/私有权限
在继承关系中,某些属性或者方法不想继承给子类,则将这些属性和方法设置为私有,即在属性名或方法名前加__
在类中,若内部属性是公有的,则可以被外部访问并进行修改
bart.score=89 bart.print_score() # Bart: 89
在属性名称前加两个__则将其变为私有变量,外部不能访问,只能在类里面访问和修改
class Student1(object): def __init__(self,name,score): self.__name=name self.__score=score def print_score(self): print('%s: %s' % (self.__name,self.__score)) bart=Student1('Bart',34) bart.print_score() # Bart: 34 bart.__score=89 # 无法修改与访问 bart.print_score() # Bart: 34
若私有属性要获取,则在类中增加get_xx()方法,若私有属性要修改,则在类中增加set_xx()方法
class Student1(object): def __init__(self,name,score): self.__name=name self.__score=score def get_name(self): return self.__name def get_score(self): return self.__score def set_name(self,name): self.__name=name def set_score(self,score): if 0<=score<=100: self.__score=score else: raise ValueError('错误分数!') bart=Student1('Bart',34) bart.set_name('BART NAME') # 修改名字 print(bart.get_name()) # 获取名字——BART NAME bart.set_score(89) # 修改分数 print(bart.get_score()) # 获取分数——89
变量名__xxx__的是特殊变量,不是私有变量,可以直接访问,私有变量一定是后面没有__的
四 继承和多态
在OOP中,新的类称为子类,被继承的类称为基类、父类或超类。子类会获得父类的全部功能(默认继承父类所有属性和方法),还可以新增方法。当子类和父类存在相同方法时,子类的方法会覆盖父类的方法
1、单继承
一个子类继承一个父类
class A(object): def __init__(self): self.num=1 def info_print(self): print(self.num) class B(A): pass c=B() c.info_print()
2、多继承
一个子类同时继承多个父类,默认使用第一个父类的同名属性和方法
class A(object): def __init__(self): self.num=1 def info_print(self): print(self.num) class C(object): def __init__(self): self.num=3 def info_print(self): print(self.num) class B(A,C): # 优先继承A类的同名属性和方法 pass son=B() print(son.num) # 1 son.info_print() # 1 class D(C,A): # 优先继承A类的同名属性和方法 pass son1=D() print(son1.num) # 3 son1.info_print() # 3
3、多层继承
父类继承给子类,子类继承给孙类
class A(object): def __init__(self): self.num=1 def info_print(self): print(self.num) class C(object): def __init__(self): self.num=3 def info_print(self): print(self.num) class B(A,C): def __init__(self): self.num = 5 def info_print(self): self.__init__() print(self.num) def A_make(self): A.__init__(self) A.info_print(self) def C_make(self): C.__init__(self) C.info_print(self) class E(B): # 继承 pass grandson=E() grandson.info_print() grandson.A_make()
4、子类与父类同名方法和属性
4.1 子类重写父类同名方法和属性
若子类和父类有同名方法和属性,用子类创建对象,调用同名方法和对象,调用的是子类的
class A(object): def __init__(self): self.num=1 def info_print(self): print(self.num) class C(object): def __init__(self): self.num=3 def info_print(self): print(self.num) class B(A,C): def __init__(self): self.num = 5 def info_print(self): print(self.num) son=B() print(son.num) # 5 son.info_print() # 5
4.2 子类调用父类同名方法和属性
将父类的同名属性和方法再次封装即可
class A(object): def __init__(self): self.num=1 def info_print(self): print(self.num) class C(object): def __init__(self): self.num=3 def info_print(self): print(self.num) class B(A,C): def __init__(self): self.num = 5 def info_print(self): # 加自己的初始化原因:num数性值是上一次调用的init内的属性,而不是自己的属性 self.__init__() print(self.num) def A_make(self): # 再次调用初始化原因:如果不调用初始化,那么A的num就是5,而不是1。要调用父类同名方法和属性,属性在init初始化位置,因而要再次调用init A.__init__(self) # 父名类名.函数(self) A.info_print(self) def C_make(self): C.__init__(self) C.info_print(self) son=B() print(son.num) son.A_make() son.C_make() son.info_print()
4.3 super()调用父类方法
带参数语法:super(当前类名,self).函数()
class A(object): def __init__(self): self.num=1 def info_print(self): print(f'A类:{self.num}') class C(A): def __init__(self): self.num=3 def info_print(self): print(f'C类:{self.num}') super(C,self).__init__() # 父类带参数,当有这代码时,B类找到C类后可继续找到A类 super(C,self).info_print() class B(C): def __init__(self): self.num = 5 def info_print(self): self.__init__() print(f'B类:{self.num}') def C_make(self): super(B,self).__init__() # 父类带参数 super(B,self).info_print() son=B() son.C_make()
无参数用法:super().函数(),比较适合单继承使用
class A(object): def __init__(self): self.num=1 def info_print(self): print(f'A类:{self.num}') class C(A): def __init__(self): self.num=3 def info_print(self): print(f'C类:{self.num}') class B(C): def __init__(self): self.num = 5 def info_print(self): self.__init__() print(f'B类:{self.num}') def C_make(self): super().__init__() # 无参数,当C中无super时,只能追追到C而不能到A super().info_print() son=B() son.C_make()
5、查看类的继承关系
语法:类名.__mro__
print(B.__mro__) # (<class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>)