目录
组合
1.什么是组合
在一个类中以另外一个类的对象作为数据属性,称为类的组合。
继承是一个子类是一个父类的关系,而组合则是一个类有另一个类的关系。
组合就是一个类中使用到另一个类,从而把几个类拼到一起。组合的功能也是为了减少重复代码。
2.为什么要使用组合
组合的目的和继承一样,为了减少代码冗余
3.如何使用组合
# 定义父类 class people: def __init__(self,name,age): self.name = name self.age =age # 定义学生类 class teach(people): def __init__(self,name,age): super().__init__(name,age) # 定义老师类 class student(people): def __init__(self,name,age): super().__init__(name,age) # 定义一个日期类 class Data: def __init__(self,n,y,d): self.n = n self.y = y self.d = d def dayin(self): print(f''' ===打印年月日=== 年:{self.n} 月:{self.y} 日:{self.d} ''') # 实例化teach得到对象t t = teach('aaa','s') # 实例化Data 得到data_obj对象 data_obj = Data(1999,10,1) # 将data_obj添加到对象t中,让t 可以调用Data的方法 t.data = data_obj # t中有data_obj == t中可以使用Data的方法 t.data.dayin()
组合的练习
''' 选课系统需求: 1.学生类,老师类, 学生和老师都有课程属性, 每一门课程都是一个对象. 课程: 课程名字,课程周期,课程价钱 2.学生和老师都有选择课程的功能, 还有打印所有课程的功能. ''' # 定义父类 class people: def __init__(self,name,age,sex): self.name = name self.age =age self.sex = sex '''定义选课的方法''' def add_kecheng(self,course_obj): '''将选择的课程传入''' self.course_list.append(course_obj) # self自己的list列表增加传入的课程 '''得到一个老师学生的对象''' def print_all(self): # (传入当前的老师或学生对象) '''循环拿到当前对象的课程列表,列表中存放的是一个个的课程对象''' for course_obj in self.course_list: # 对象的课程列表(之前追加的课程) '''循环每一个课程对象调用查看课程信息的方法''' course_obj.get_info() # 获取到的课程对象直接调用其中的打印方法 # 定义老师类 class teach(people): def __init__(self,name,age,sex): super().__init__(name,age,sex) # 学生选课的功能 self.course_list = [] # 定义学生类 class student(people): def __init__(self,name,age,sex): super().__init__(name,age,sex) self.course_list = [] # 定义一个课程类 class Course: '''定义课程类的名称周期价格''' def __init__(self,course_name,course_period,course_prize): self.course_name = course_name self.course_period = course_period self.course_prize = course_prize def get_info(self): '''打印课程的所有信息''' print(f''' 课程名称:{self.course_name} 课程周期:{self.course_period} 课程价格:{self.course_prize} ''') # 实例化老师与学生的对象 tea1 = teach('老师',10,'男性') stu1 = student('学生',50,'男性') # 实例化课程的对象 python_obj = Course('python0',6,2.0) linux_obj = Course('linux',6,1.0) # 通过老师学生将两门课程对象添加进teach内 '''将整个课程信息实例化的对象传入了add_kecheng方法中 教师类中列表course_list接受课程信息''' tea1.add_kecheng(python_obj) tea1.add_kecheng(linux_obj) '''将保存在tea1中的python获取并使用打印方法''' # tea1.course_list[0].get_info() # python_obj.get_info() '''直接调用查看所有的课程''' tea1.print_all()
总结
继承:
类与类的关系,一种什么是什么的关系,子类与父类是从属关系
组合:
对象与对象的关系,一种什么有什么的关系,一个对象拥有另一个对象
封装
1.什么是封装
把一堆属性(特征与技能)封装到一个对象中,对象可以通过.
的方式获取属性
这就是面向对象的第一个特性(好处)
:封装
封装特性,可以把复杂的信息,流程,包起来,内部处理,让使用者不去关注细节
2.为什么要封装
目的是为了方便存取,可以通过对象.
属性的方式获取属性.
3.如何封装
特征 : 变量 ==> 数据类型 技能 : 函数 ==>方法属性
在类内部定义一堆属性(特征与技能)
通过 对象.属性 = 属性值
方式
访问限制机制
在Python中,实例的变量名如果以__
开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
1.什么是访问限制机制
在类内部定义,凡是以__
开头的数据属性与方法属性
都会被python内部隐藏起来,让外部不能直接访问类内部__
开头的属性.
比如 __name = 'tank'
2.访问限制的目的
一堆隐私的属性与不能被外部轻易访问的属性,可以隐藏起来,不被外部直接调用
好处: 对重要数据获取的逻辑更加严谨,进而保证了数据的安全.
class Foo: # 数据类型 __name = 'tank' # 方法属性 def __run(self): print('runing...') foo = Foo() print(Foo.__name) '''报错type object 'Foo' has no attribute '__name''''
接口
隐私属性可以挺过封装一个接口,在借口内做业务逻辑的处理,再把数据返回给调用者
# 类在定义时执行,使用接口,隐私 class Foo: # 数据类型 __name = 'tank' # 方法属性 def __run(self): print('runing...') # 接口 def get_name(self): '''在接口里返回出去,类内部访问''' # 可以做些业务逻辑判读是否给你访问 return self.__name foo = Foo() res = foo.get_name() print(res) # tank '''内部修改''' def set_name(self): self.__name = 'nick' foo = Foo() foo.set_name() print(foo.get_name()) # nick '''访问限制判断''' class ATM: # 1.插卡 def __inster_card(self): print('插卡') pass # 2.输入密码 def __input_pwd(self): print('输入密码') pass # 3.输入取款 def __money(self): print('输入金额') pass # 4.开始吐钱 def __getmoney(self): print('开始吐钱') pass # 5.打印账单 def flow(self): print('流水') pass # 取钱直接接口,封装所有的隐藏接口 def withdraw(self): self.__inster_card() self.__input_pwd() self.__money() self.__getmoney() self.flow() # 实例化atm atm = ATM() atm.withdraw()
注意: 在python中,不会强制限制属性的访问,类内部__
开头的属性,只是做了一种变形
class Foo: __name = 'tank' # 将__name改成 _student__name了 print(foo._Foo__name) # tank _(父类)__(属性名) 可以直接获取
property
1.什么是property
python中内置的装饰器,主要是给类内部的方法使用
2.为什么要用property
将类内部的方法def 方法名()
变成def 方法
,
在对象调用某个方法是将对象.方法()
变成对象.方法
,看着像数据属性
3.如何使用property
@ property
注意 不能对呗装饰过的方法属性修改
''' 计算人体bmi, bmi = 体重/身高的平方 ''' class People: def __init__(self,name,w,h): self.name = name self.w = w self.h = h def bmi(self): return self.w / (self.h ** 2 ) t1 = People('wang',160,175) print( t1.bmi() ) # 加()像是动词,所以使用property 让其变为名词 '''使用 @ property ''' class People: def __init__(self,name,w,h): self.name = name self.w = w self.h = h @property # 在想要变成普通的函数上进行调用 def bmi(self): return self.w / (self.h ** 2 ) t1 = People('wang',160,175) print( t1.bmi ) # 打印时去除括号() '''不能对被装饰过的方法进行属性修改''' t1.bmi = 18 # 会进行报错
了解: 可以通过特殊方法来进行修改(通过修改类中属性)
# 改 class People: def __init__(self, name, w, h): self.name = name self.w = w self.h = h @property # 在想要变成普通的函数上进行调用 def bmi(self): return self.w / (self.h ** 2) @property def get_name(self): return self.name @get_name.setter def set_name(self, val): self.name = val t1 = People('wang', 160, 175) print(t1.get_name) t1.set_name = 'tank' print(t1.set_name) '''wang tank'''
多态
1.什么是多态
多态指的是同一种事物的多种形态,
就是同样的行为,后代们有多种不同的状态
多态就是 从父亲那里继承来的同一个的行为, 孩子们各自的表现状态不一样
2.多态的目的
多态也称之为多态性,在程序中继承就是多态的表现形式
多态的目的是为了让不同类型的对象,
在使用相同功能的情况下,调用同一个名字的方法名
父类: 定义一套统一的标准 子类: 遵循父类统一的标准 多态的最终目的: 统一子类编写的规范,为了让使用者更方便调用相同功能的方法
3.如何实现
继承
在python中不会强制要求子类必须遵循父类的一套标准,所以出现了抽象类
抽象类abc
1.是什么:
abc模块 abstract_class
2.使用的目的
强制子类必须遵循父类的一套标准
3.如何使用
import abc
import abc class animal(metaclass=abc.ABCMeta): @abc.abstractclassmethod def eat(self): pass @abc.abstractclassmethod def drink(self): pass @abc.abstractclassmethod def speak(self): pass class pig(animal): def eat(self): pass def speak(self): pass def drnk(self): pass p = pig() # 只要继承了父类,就必须有父类的方法,可以多不能少
鸭子类型
1.什么是鸭子类型
在不知道当前对象是何物的情况下,但是你长得像鸭子,那么你就是鸭子类型
在python中,不推荐使用抽象类强子限制子类的定义,但推荐类都遵循鸭子类型
一种定义的方式,遵循父类的定义,(子类与父类的同名会替换父类)
我们在前面所说的,Python 不检查传入的对象的类型,这种方式通俗的被称为「鸭子类型」,比较高端的方式是叫做「隐式类型」或者「结构式类型」。 鸭子类型这个命名源于一句名言:如果它像鸭子一样走路,像鸭子一样叫,那么它就是一只鸭子。 鸭子类型就意味着可以向任何对象发送任何的消息,语言只关心这个对象能不能接收该消息,不会去强求该对象是否为某一种特定的类型 —— 该对象的多态表现。
-继承
耦合性太高,程序的可扩展性差
-鸭子类型
耦合性低,程序的可扩展性强