一、封装:
1、要封装什么
封装数据和方法
2、为什么要封装
封装不是单纯意义的隐藏:
1:封装数据的主要原因是:保护隐私
2:封装方法的主要原因是:隔离复杂度
3、封装分为两个层面
封装其实分为两个层面,但无论哪种层面的封装,都要对外界提供好访问你内部隐藏内容的接口(接口可以理解为入口,有了这个入口,使用者无需且不能够直接访问到内部隐藏的细节,只能走接口,并且我们可以在接口的实现上附加更多的处理逻辑,从而严格控制使用者的访问。
第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装。
注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口
第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。
在python中用双下划线的方式实现隐藏属性(设置成私有的)
类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:
1 classTeacher:2 def __init__(self,name,age):3 self.__name=name4 self.__age=age5
6 deftell_info(self):7 print('姓名:%s,年龄:%s' %(self.__name,self.__age))8 defset_info(self,name,age):9 if notisinstance(name,str):10 raise TypeError('姓名必须是字符串类型')11 if notisinstance(age,int):12 raise TypeError('年龄必须是整型')13 self.__name=name14 self.__age=age15
16 t=Teacher('egon',18)17 t.tell_info()18
19 t.set_info('egon',19)20 t.tell_info()
View Code
这种自动变形的特点:
1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。
2.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
注意:对于这一层面的封装(隐藏),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了。
二、继承
2.1.1、含义
前面我们提到过,面向对象编程有个好处就是代码复用,而其中一种方法就是通过继承机制。继承就是说定义的一个新类,继承现有的类,获得现有类的非私有属性、方法,避免定义重复的变量和方法,提到个私有,就是前面加两个下划线的那个东西,他在外部无法调用,继承 他的子类也不能。被继承的那个类称为基类、父类或超类,子类也可以叫做派生类。
2.1.2、特点
1、如果在子类中需要父类的构造方法就需要显式地调用父类的构造方法,或者不重写父类的构造方法。子类不重写 __init__,实例化子类时,会自动调用父类定义的 __init__;如果重写了__init__ 时,实例化子类,就不会调用父类已经定义的 __init__
2、继承后可以重写(覆盖)父类的属性或方法,当然也可以添加子类特有的属性或方法
3、在python中,首先查找对应类型的方法,如果在子类中找不到对应的方法,才到基类中逐个查找。
2.2、单继承:一个子类只有1个父类
直接上代码,仔细理解一下里面的关系,我把讲解都写在注释的地方
C5.py
1 classPeople():2 sum=03 def __init__(self,name,age,money):4 self.name=name5 self.age=age6 self.__money=money #私有属性,被引入时,继承不了,但他们的set,get函数可以继承
7
8 defget_money(self):9 return self.__money
10
11 defset_money(self,money):12 self.__money=money13
14 defset_name(self,name):15 self.name=name16
17 defget_name(self):18 returnself.name19
20 defdo_homework(self):21 print("这是父类的作业")
C6.py
1 from package3.C5 importPeople2 class Student(People): #继承People类
3 def __init__(self,name,age,stuid,money):4 super(Student,self).__init__(name,age,money) #继承父类的构造方法,super是代表父类的一个关键字,调用父类的方法
5 self.stuid = stuid #子类可以由一些自己独有的属性或者方法
6 defset_stuid(self,stuid):7 self.stuid=stuid8
9 defdo_homework(self): # 定义一个和父类中方法名称一样的方法10 print("这是子类的作业")11 super(Student, self).do_homework() #super也可以调用构造方法以外的普通的方法
C7.py
1 from package3.C6 importStudent2
3 student1=Student("毛毛",28,11,1111)4 print(student1.name)5 student1.set_name("兔兔")6 print(student1.get_name())7 student1.set_stuid(1000)8 print(student1.stuid)9 student1.set_money(123) #调用父类方法修改私有变量
10 print(student1.get_money())11 print(student1.__dict__)12 student1.do_homework() #如果子类中的方法或者属性和父类中的方法或属性同名时,就会覆盖掉父类的方法或属性,调用子类的方法或属性----这种叫做覆盖(python中的多态)
------------------------------------------------------------------------------------------------------------------
毛毛
兔兔
1000
123
{'name': '兔兔', 'age': 28, '_People__money': 123, 'stuid': 1000}
这是子类的作业
这是父类的作业
2.3、多继承:一个子类可以有多个父类
三、多态
python这里的多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数,比如C5.py和C6.py中的do_homework方法