Python基础—面对对象三大特征—封装、继承(方法重写)、多态
Python基础—面对对象三大特征—封装、继承(方法重写)、多态
封装
- 提高程序的安全性
- 将属性和方法包装在类中
- python中没有专门的修饰符用来属性私有化,如果属性不希望在类外部被访问,则前边使用两个’_’
实现一个学生类的封装
#定义一个学生类
class Student:
#定义构造方法
def __init__(self,name,age):
self.name = name
self.__age = age#这里的age加了__,则在类的外部不可访问
#定义实例化方法
def show(self):
print(self.name,self.__age)
如何访问类中一个“私有化”属性
访问类中属性
#实例化一个对象
stu1 = Student('张三',20)
stu1.show()
#单独访问name,和age
print(stu1.name)
print(stu1.age)
输出报错:类中没有这个对象
则:私有化属性不可访问
如果非要访问可以这么做
方法 :dir()获取类中所有的对象
#实例化一个对象
stu1 = Student('张三',20)
stu1.show()
#单独访问name,和age
print(stu1.name)
# print(stu1.age)
#用dir()强行获取类的私有属性
print(dir(stu1))
print(stu1._Student__age)
输出:
继承
提高程序的复用性
- 语法格式
class 子类类名(父类1,父类2,.....):
pass
- 如果一个类没有继承任何类,则默认继承object类
- python支持多继承
- 自已子类时必须在构造方法中调用父类的构造方法否则将无法继承父类中的方法
调用父类构造方法方式有两种:
'''调用父类构造方法要进行传参,且与原形式保持一致'''
父类名.__init__(self)#常用
super().__init__(self)#super()里传入调用的父类名,单继承时默认不填写
例如:
#定义一个性别类Gender
class Gender(object):
def __init__(self,gender):
self.gender = gender
#定义实例方法
def a(self):
print('性别是%s'%self.gender)
#定义一个人员类
class Person(object):#默认继承object类
#定义构造方法
def __init__(self,name,age):
self.name = name
self.age = age
#定义实例方法
def show(self):
print('%s的年龄是%d'%(self.name,self.age))
#定义一个学生类继承Person
class Student(Person):
#定义构造方法
def __init__(self,name,age,stu_id):
#调用父类构造方法
Person.__init__(self,name,age)
self.stu_id = stu_id
#定义一个老师类继承Person
class Teacher(Person,Gender):
#定义构造方法
def __init__(self,name,age,th_class,gender):
#调用父类构造方法
Person.__init__(self,name,age)
Gender.__init__(self,gender)
self.th_class = th_class
#实例化Student和Person对象
stu1 = Student('张三',17,1711620056)
tea1 = Teacher('Miss黄',28,'python','女')
#访问父类方法
stu1.show()
tea1.show()
tea1.a()
输出:
方法重写
- 子类对继承父类的某个属性或者方法不满意,在子类中可以对其方法体进行重新编写,方法名不变
- 子类重写后的方法中,可以通过 super(). 函数() 来调用父类中被重写的方法
问题:对于上面的学生类,我们不满足person类里的show()方法,我们想在调用父类方法的时候即输出Person属性,还要输出Srudent特有的属性,那么,就要对Person中的Show()方法进行重写
当然,在重写的方法里还可以嵌套调用原本的父类方法,代码如下:
#这里我们重新定义一个学生类继承Person类和Gender类
class Student2(Person,Gender):
#定义构造方法
def __init__(self,name,age,stu_id,gender):
#调用Person父类的构造方法
Person.__init__(self,name,age)
#调用Gender父类的构造方法
Gender.__init__(self,gender)
self.stu_id = stu_id
#重写Student的show()方法
def show(self):
#调用父类方法
Person.show(self)
print('我叫:%s!性别%s,年龄%d岁,我的学号是:%d。'%(self.name,self.gender,self.age,self.stu_id))
#实例化一个Student2对象stu2
stu2 = Student2('杨洋',11,1711620056,'男')
#调用Studen2的实例方法
Student2.show(stu2)
输出:
可以看到,show()方法已被重写,但是调用的父类show()方法依然进行展示
Object类
- Object是所有类的父类——所有类都有object类的属性和方法
- 内置函数dir(对象名) 可以查看指定对象的所有属性
- Object有一个 _ str_() 方法,用于返回一个对于 ** 对象的描述 ** ,对应于内置函数str()经常用于print()方法,帮我们查看对象的信息,所以我们经常会对 _ str_() 进行重写
定义一个类Student
#定义一个类Student
class Student(object):#默认继承object类
pass
#实例化一个对象
stu = Student()
#打印输出stu对象
print(stu)#输出的是stu的存储地址
#打印stu对象具有的属性值,因为是继承object类,说以应该具有object的所有属性和方法
print(dir(stu))
输出结果:
当用print()输出对象时,输出的时stu的存储位置,
观察dir出的stu对象的属性,发现包含子类中没有的属性,说明这都是父类object类的属性,
所以我们在定义构造方法时的__init__()方法,都是对object类方法的重写
现在我们
重写__str__()方法
class Student(object):#默认继承object类
def __init__(self,name,age):
self.name = name
self.age = age
#重写__str__()方法
def __str__(self):
return '姓名:%s,年龄%d'%(self.name,self.age)
#实例化一个对象
stu = Student('kiki',20)
#再用print()方法打印stu对象
print(stu)
输出:
可以看到,再次用print()方法打印的对象不再是一个内存地址,而是我们自定义定义的对象的描述
多态(Pyhon:鸭子类型语言)
提高程序的可拓展性和可维护性
多态——具有多种形态
即便不知道一个变量所引用的对象时什么类型,依然可以通过变量调用方法,在运行过程中,
python自己会根据变量所引用的对象类型,动态决定调用哪个对象中的方法
例子:
#定义一个Dog类继承Animal类
class Dog(Animal):
#重写eat()
def eat(self):
print('狗吃骨头')
#定义一个Cat类继承Animal
class Cat(Animal):
#重写eat()
def eat(self):
print('猫吃鱼')
#定义一个人Person类,默认继承Object类
class Person():
#定义吃的方法
def eat(self):
print('人吃五谷杂粮')
#定义一个吃啥的方法
def fun(obj):
obj.eat()
#当我们给函数传入不同类型的对象时,我们不知道要传入的是什么类型的
fun(Animal())#传入Animal类型的对象,直接调用Animal中的eat()方法
fun(Dog())#传入Dog类型的对象,直接调用Dog中的eat()方法
fun(Cat())#传入Cat类型的对象,直接调用Dog中的eat()方法
fun(Person())#传入Person类型的对象,直接调用Person中的eat()方法
输出:
python会自自己判断传入变量的类型,调用合适的对象方法