python-----面向对象
Posted shijia-listen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python-----面向对象相关的知识,希望对你有一定的参考价值。
一、类和对象
1、类的概念:类是一种数据结构(和开始定义字典中共同的特征和动作类似),就好比一个模型,该模型用来表示一类事物(事物即数据和动作的结合体),用它来生产真正的物体(实例)。
2、对象的概念:我们看到的一切事物都是一个个对象,可以把对象理解为一个个具体的事物(事物即数据和动作的结合体)---花、树、狗、猫、人都是对象
3、类与对象的关系:对象都是由类产生的,上帝造人,上帝首先有一个造人的模板,这个模板即人的类,然后上帝根据类的定义来生产一个个人。
4、实例化:由类生产对象的过程叫作实例化,类实例化的结果就是一个对象,或者叫做一个实例(实例=对象)。
二、三大编程范式
1、面向过程(大问题分为一个一个步骤,最后解决---可读性高,重复代码多)
2、函数式编程(数学函数+函数编程---可读性低、代码量少、优雅)
3、面向对象(万物皆对象)
三、面向对象设计和面向对象编程
面向对象设计(Object oriented design):将一类具体事务的数据和动作整合到一起,即面相对象设计。
1 # _*_ encoding:utf-8 _*_ 2 __author__ = ‘listen‘ 3 __date__ = ‘2018/11/25 9:22‘ 4 #作用域实现狗和它的特征以及动作的绑定 一个函数嵌套一个函数,里面定义一些局部变量(函数),只有下一级才能调用或者本身,参数中可以添加上全局变量 5 # def dog(name,gender,type): 6 # def jiao(dog): 7 # print(‘这只狗[%s]正在汪汪汪‘%dog[‘name‘]) 8 # def chibaba(dog): 9 # print(‘这只[%s]正在吃粑粑‘%dog[‘type‘]) 10 # dog1={ 11 # ‘name‘:name, 12 # ‘gender‘:gender, 13 # ‘type‘:type, 14 # ‘jiao‘:jiao, 15 # ‘chibaba‘:chibaba 16 # } 17 # return dog1 18 # # print(dog()) 19 # d1=dog(‘大黄‘,‘gong‘,‘藏獒‘) 20 # d1[‘jiao‘](d1) 21 # d1[‘chibaba‘](d1) 22 #运行结果: 23 # 这只狗[大黄]正在汪汪汪 24 # 这只[藏獒]正在吃粑粑 25 26 #整理: 27 #面向对象设计 就是用函数实现的 28 # def dog(name,gender,type): 29 # def jiao(dog): 30 # print(‘这只狗[%s]正在汪汪汪‘%dog[‘name‘]) 31 # def chibaba(dog): 32 # print(‘这只[%s]正在吃粑粑‘%dog[‘type‘]) 33 # def init(name,gender,type): 34 # dog1={ 35 # ‘name‘:name, 36 # ‘gender‘:gender, 37 # ‘type‘:type, 38 # ‘jiao‘:jiao, 39 # ‘chibaba‘:chibaba 40 # } 41 # return dog1 42 # return init(name,gender,type) 43 # d2=dog(‘duoduo‘,‘母‘,‘泰迪‘) #一个对象 对象实例化的过程 44 # d2[‘jiao‘](d2) #这只狗[duoduo]正在汪汪汪 45 46 47 #有点像递归 风湿理论 和面向对象形式很像 48 def dog(name,gender,type): 49 def init(name,gender,type): 50 dog1={ 51 ‘name‘:name, 52 ‘gender‘:gender, 53 ‘type‘:type, 54 ‘jiao‘:jiao, 55 ‘chibaba‘:chibaba 56 } 57 return dog1 58 def jiao(dog): 59 print(‘这只狗[%s]正在汪汪汪‘%dog[‘name‘]) 60 def chibaba(dog): 61 print(‘这只[%s]正在吃粑粑‘%dog[‘type‘]) 62 63 return init(name,gender,type) 64 d2=dog(‘duoduo‘,‘母‘,‘泰迪‘) #一个对象 对象实例化的过程 65 d2[‘jiao‘](d2) #这只狗[duoduo]正在汪汪汪
面向对象编程:用定义类+实例(对象)方式去是实现面向对象的设计
1 # _*_ encoding:utf-8 _*_ 2 __author__ = ‘listen‘ 3 __date__ = ‘2018/11/25 10:37‘ 4 #数据属性和函数属性 5 class Chinese: 6 """ 7 类的属性 8 """ 9 dang=‘共产_党‘ #数据属性 10 def love(self): #函数属性又称方法 11 print(‘中国人都爱国‘) 12 def learn(): 13 print(‘活到老学到老‘) 14 15 ###两种方法查看类的属性 16 17 # print(Chinese.dang) #用点来得到属性 18 # Chinese.learn() #活到老学到老 19 # Chinese.love(1) #中国人都爱国 必须有一个参数 20 print(dir(Chinese)) #用列表的形式把Chinese所有属性都列出来 内置的+自定义的 21 print(Chinese.__dict__) #用列表的形式把Chinese的属性都列出来 key value 内置的+自定义的 22 print(Chinese.__dict__[‘dang‘]) #共产_党 23 Chinese.__dict__[‘love‘](1) #中国人都爱国
四、类的声明
1、只有在python2中才分新式类和经典类,python3中所有的类都为新式类。
2、新式类和经典类声明的最大不同在于,所有新式类必须继承至少一个父类。
3、所有类不管是否显示声明父类,都有一个默认继承object父类。
4、经典类格式:
class 类名:(首字母大写)
pass
5、新式类格式:
class 类名(父类):(默认object)
pass
6、在python3中上述两种定义类的方式都为新式类。
python3中声明类:
1 """ 2 class 类名: 3 4 ‘类的文档字符串‘ 5 6 类体 7 8 """ 9 def Data: 10 pass 11 12 13 d1=Data() #用类实例化了一个对象d1
五、类的属性
类有数据属性(特征)和函数属性(动作)(函数属性又称方法)
1 #数据属性和函数属性 2 class Chinese: 3 """ 4 类的属性 5 """ 6 dang=‘共产_党‘ #数据属性 7 def love(self): #函数属性又称方法 8 print(‘中国人都爱国‘) 9 def learn(): 10 print(‘活到老学到老‘) 11 12 ###两种方法查看类的属性 13 14 # print(Chinese.dang) #用点来得到属性 15 # Chinese.learn() #活到老学到老 16 # Chinese.love(1) #中国人都爱国 必须有一个参数
有两种方法查看类的属性:
1 #数据属性和函数属性 2 class Chinese: 3 """ 4 类的属性 5 """ 6 dang=‘共产_党‘ #数据属性 7 def love(self): #函数属性又称方法 8 print(‘中国人都爱国‘) 9 def learn(): 10 print(‘活到老学到老‘) 11 12 ###两种方法查看类的属性 13 14 print(dir(Chinese)) #用列表的形式把Chinese所有属性都列出来 内置的+自定义的 15 print(Chinese.__dict__) #用列表的形式把Chinese的属性都列出来 key value 内置的+自定义的 16 print(Chinese.__dict__[‘dang‘]) #共产_党 17 Chinese.__dict__[‘love‘](1) #中国人都爱国
特殊的类属性:
1 class Chinese: 2 """ 3 类的属性 4 """ 5 dang=‘共产_党‘ #数据属性 6 def love(self): #函数属性又称方法 7 print(‘中国人都爱国‘) 8 def learn(): 9 print(‘活到老学到老‘) 10 11 #类内置的特殊属性 12 #.__name__ .__doc__ __module__ 13 print(Chinese.__name__) #Chinese 14 print(Chinese.__doc__) # 类的属性 15 print(Chinese.__module__) #__main__ 模块属性 执行函数
类的方法属性的增、删、改、查(实例没有方法属性的增、删、修改,因为不是本身的,而是引用类的)
1 ###类的方法属性的增、删、改、查 2 class Person(object): 3 eyes=‘black‘ 4 hair=‘yellow‘ 5 def __init__(self,name,age,gender): 6 self.name=name 7 self.age=age 8 self.gender=gender 9 def say_hi(self): 10 print(‘%s 雷浩哇!‘%self.name) 11 def eat_food(self,food): 12 print(‘%s正在吃%s‘%(self.name,food)) 13 def sleep(self): 14 print(‘已经睡了‘) 15 p2=Person(‘listen‘,18,‘female‘) 16 #增加 17 def play_basketball(self): 18 print(‘正在打篮球‘) 19 Person.hobby=play_basketball 20 #类中增加了 21 print(Person.__dict__) #字典中加上了play_basketball 22 #实例的增加 23 p2.hobby() 24 Person.hobby(1) #正在打篮球 class 内部会自动把参数加上,我们是从外部添加的,所以自己得加上一个参数 25 # #修改 26 # def eat_fruits(self,food): 27 # print(‘%s开心的吃%s‘%(self.name,food)) 28 # Person.eat_food=eat_fruits 29 # print(Person.__dict__) 30 # p2.eat_food(‘麻辣烫‘) #listen开心的吃麻辣烫 只是内容变了,函数名没有改变 31 # #查找 32 # p2.say_hi() #listen 雷浩哇! 33 # #删除 34 # del Person.sleep 35 # print(Person.__dict__) #这个不属于对象的属性,只有类可以把它删掉 36 del p2.gender #数据属性 37 print(p2.__dict__) # {‘name‘: ‘listen‘, ‘age‘: 18}
类的数据属性的增、删、改、查(实例也可以)
1 class Chinese: 2 """ 3 类的属性 4 """ 5 dang=‘共产_党‘ #数据属性 6 def __init__(self,name): 7 self.name=name 8 def love(self): #函数属性又称方法 9 print(‘中国人都爱国‘) 10 def learn(self): 11 print(‘活到老学到老‘) 12 13 p1=Chinese(‘alex‘) 14 ###类的数据属性的增、删、改、查 15 #增加一个类属性 16 Chinese.hair=‘black‘ 17 18 #查找一个类属性 19 print(Chinese.dang) #共产_党 20 #查找一个实例属性 21 print(p1.name) #alex 22 print(p1.hair) #black 23 24 #修改一个类属性 25 Chinese.hair=‘yellow‘ 26 print(p1.hair) #yellow 27 print(Chinese.hair) #yellow 28 29 #删除一个属性 30 del Chinese.hair 31 # print(p1.hair) # ‘Chinese‘ object has no attribute ‘hair‘ 报错 32 print(Chinese.hair) #同样报错
小结:(为了方便自己理解)类的作用域和函数的作用域类似,实例中没有此方法会去类中找,直到找到为止,找不到报错,可以看到类中都有什么属性(__dict__),同样实例也很试用,self一般都是指实例化的对象:类名+()------->>执行的是__init__()函数;宏观上看实例绑定了数据属性和函数属性但从本制度上看并没有只是绑定了数据属性,通过引用方式调用类的属性,省内存。
勿操作:不要修改底层的字典。
六、类属性和对象属性
1、实例化会自动触发init函数的运行,最后返回一个值即实例,我们要找的实例属性就放在__init__函数局部作用域里。
2、类有类的属性字典,就是类的作用域,实例有实例的属性字典,即实例的作用域。
3、综上,一个点代表一层作用域,obj.x先从自己的作用域找,自己的作用域找到不到会从外层类的作用域中找,都找不到就会报错。
4、在类中没有使用点的调用,代表调用全局变量(普通的变量)。
1 country=‘canada‘ 2 class Chinese: 3 country=‘China‘ 4 def __init__(self,name): 5 self.name=name 6 print(‘---->‘,country) #----> canada 全局变量 没使用点调用 7 def play_basketball(self,ball): 8 print(‘%s正在打%s‘%(self.name,ball)) 9 p1=Chinese(‘alex‘) 10 print(p1.country) #China 类的属性
七、静态属性、类方法、静态方法
静态属性:加上一个@property,将实例化对象变成类的数据属性,将该方法封装起来,作用可隐藏的逻辑代码,直接用实例+‘.’调用该方法。
1 # _*_ encoding:utf-8 _*_ 2 __author__ = ‘listen‘ 3 __date__ = ‘2018/11/26 22:41‘ 4 class Room: 5 def __init__(self,owner,name,length,width,height): 6 self.owner=owner 7 self.name=name 8 self.length=length 9 self.width=width 10 self.height=height 11 @property #属性 加上property效果和调用数据属性一样了 r1.tiji r1.name 不知道调用方法的话,看着两个是一样的调用 12 def tiji(self): 13 return self.length*self.width*self.height 14 r1=Room(‘alex‘,‘别墅‘,100,100,5) 15 print(r1.tiji) #调用数据属性的方式 50000 16 print(r1.name)
类方法:@classmethod类方法,专门供类使用,与实例无关,类方法只能访问类相关的属性,不能访问实例属性,与实例无关。
1 class Room: 2 def __init__(self,owner,name,length,width,height): 3 self.owner=owner 4 self.name=name 5 self.length=length 6 self.width=width 7 self.height=height 8 9 @classmethod 10 def tell_info(cls,x): 11 print(cls) #__main__.Room 指的是类属性 12 print(‘--------->‘,x) 13 r1=Room(‘alex‘,‘别墅‘,100,100,5) 14 # print(Room.tiji(r1)) #可以通过中间实例来调用类的函数属性 15 16 #想直接调用类的函数属性 不想过中间值来调用 ----通过类方法@classmethod cls 把它变为类属性 17 Room.tell_info(‘a‘) 18 #r1.tell_info(‘b‘) 与实例无关,不这么用
静态方法:@staticmethod 类的静态方法,只是名义上的归属类管理,没有默认参数,不能使用类变量和实例变量,只支持类的工具包,与类和实例一点关系都没有。
1 class Room: 2 def __init__(self,owner,name,length,width,height): 3 self.owner=owner 4 self.name=name 5 self.length=length 6 self.width=width 7 self.height=height 8 9 @classmethod 10 def tell_info(cls,x): 11 print(cls) #__main__.Room 指的是类属性 12 print(‘--------->‘,x) 13 @staticmethod 14 def static_method(x,y,z): 15 print(x,y,z) 16 r1=Room(‘alex‘,‘别墅‘,100,100,5) 17 # print(Room.tiji(r1)) #可以通过中间实例来调用类的函数属性 18 19 #想直接调用类的函数属性 不想过中间值来调用 ----通过类方法@classmethod cls 把它变为类属性 20 Room.tell_info(‘a‘) 21 Room.static_method(1,2,3) #1 2 3 #类传参数可以调用 22 r1.static_method(4,5,6) #4 5 6 #实例传参数也可以调用
练习题:
1 # _*_encoding:utf-8 _*_ 2 # class School: 3 # def __init__(self,name,type,count): 4 # self.name=name 5 # self.type=type 6 # self.count=count 7 # def shang_ke(self): 8 # print(‘%s学校正在上课‘%(self.name)) 9 # def yundonghui(self): 10 # print(‘%s%s开展了运动会‘%(self.count,self.name)) 11 # @property 12 # def play_ball(self): 13 # return ‘%s好多学生喜欢打球‘%self.name 14 # @classmethod 15 # def eat_food(cls,food): 16 # print(‘学生正在吃%s‘%food) 17 # @staticmethod 18 # def jiaoliu(a,b,c): 19 # print(‘学校之间喜欢互相交流%s-%s-%s‘%(a,b,c)) 20 # s1=School(‘清华大学‘,‘公办‘,50000) 21 # s1.shang_ke() 22 # print(s1.name) 23 # print(s1.type) 24 # print(s1.play_ball) 25 # School.eat_food(‘烤鱼‘) 26 # School.jiaoliu(‘政治‘,‘文化‘,‘教学特点‘) 27 # s1.jiaoliu(‘政治‘,‘文化‘,‘教学特点‘) 28 #print(‘---------------------------------------------------------------‘) 29 # class Teacher: 30 # def __init__(self,name,degree,age,school): 31 # self.name=name 32 # self.age=age 33 # self.degree=degree 34 # self.school=school 35 # def hobby(self,aihao): 36 # print(‘%s老师喜欢%s‘%(self.name,aihao)) 37 # def leibie(self,lesson): 38 # print(‘%s大学的%s教%s‘%(self.school,self.name,lesson)) 39 # t1=Teacher(‘wusir‘,‘讲师‘,23,‘oldboy‘) 40 # t1.hobby(‘看电影‘) 41 # t1.leibie(‘python‘) 42 # print(‘------------------>‘) 43 # class Lesson: 44 # def __init__(self,name,org,teacher): 45 # self.name=name 46 # self.org=org 47 # self.teacher=teacher 48 # def study(self): 49 # print(‘%s课程被好多学生学习‘%self.name) 50 # def share(self,jingyan): 51 # print(‘%s机构分享好多%s‘%(self.org,jingyan)) 52 # l1=Lesson(‘java‘,‘olddboy‘,‘hf‘) 53 # l1.share(‘新思想‘) 54 # l1.study() 55 # print(‘----------------------------------------------->‘) 56 class Student: 57 country=‘china‘ 58 lesson_l=[‘math‘,‘chinese‘] 59 def __init__(self,name,age,gender,height): 60 self.name=name 61 self.age=age 62 self.gender=gender 63 self.height=height 64 def hobby(self,ball): 65 print(‘%s大多数喜欢打‘%(self.height,ball)) 66 def learn(self): 67 print(‘%s年龄段的学生正是记忆力最好的时刻‘%self.age) 68 @property 69 def gao_ezuoju(self): 70 return ‘性别%s学生爱搞恶作剧‘%(self.gender) 71 @classmethod 72 def after_lesson(cls): 73 print(‘下课的钟声想起来了‘) 74 @staticmethod 75 def nihao(x,y): 76 print(‘见面问候请说%s或%s‘%(x,y)) 77 s1=Student(‘listen‘,18,‘female‘,165) 78 print(s1.country) 79 print(Student.country) 80 s1.learn() #18年龄段的学生正是记忆力最好的时刻 81 print(s1.gao_ezuoju) #很像数据属性 82 print(s1.age) #本身就是数据属性 83 Student.after_lesson() #下课的钟声想起来了 类调用和实例没干系 84 Student.nihao(‘hello‘,‘hi‘) #见面问候请说hello或hi 85 s1.nihao(‘how are you‘,‘nice to meet you!‘) #见面问候请说how are you或nice to meet you! 86 print(Student.lesson_l) 87 print(s1.lesson_l) 88 # s1.lesson_l=[‘math‘,‘english‘] #不是修改类数据属性 而是给自己新添一个数据属性 89 # print(Student.lesson_l) #[‘math‘, ‘chinese‘] #所以类的lesson_l并没有改变 90 # print(s1.lesson_l) #[‘math‘, ‘english‘] 91 92 s1.lesson_l.append(‘english‘) #就改变了类的数据属性 因为用了 . 所以不是=所以引用了类的数据变量,所以就改变了类的数据属性 ---->> 可变和不可变 93 print(s1.lesson_l) #[‘math‘, ‘english‘, ‘english‘] 94 print(Student.lesson_l) #[‘math‘, ‘chinese‘, ‘english‘]
八、组合
作用:类和类之间做关联
①
1 class School: 2 def __init__(self,name,add): 3 self.name = name 4 self.add = add 5 class Teacher: 6 def __init__(self,name,sex,school): 7 self.name = name 8 self.sex = sex 9 self.school = school 10 class Lesson: 11 def __init__(self,name,price,period,techer): 12 self.name = name 13 self.price = price 14 self.period = period 15 self.techer = techer 16 17 p1 = School("old boy","北京") 18 t1 = Teacher("alex","male",p1)#将p1对象直接添加到t1对象属性中 19 L1 = Lesson("python班",10000,"4month",t1)
还可以这样:②
1 # _*_ encoding:utf-8 _*_ 2 __author__ = ‘listen‘ 3 __date__ = ‘2018/11/27 21:00‘ 4 # class School: 5 # def __init__(self,name,add): 6 # self.name=name 7 # self.add=add 8 # 9 # class Course: 10 # def __init__(self,name,price,period): 11 # self.name=name 12 # self.price=price 13 # self.period=period 14 # self.school=s1 15 # def jiao_ke(self): 16 # print(‘%s正在开展%s课程‘%(s1.name,self.name)) 17 # 18 # class Teacher: 19 # def __init__(self,name): 20 # self.name=name 21 # self.course=c1 22 # self.school=s1 23 # def jiang_ke(self): 24 # print(‘%s老师正在讲%s课程‘%(self.name,c1.name)) 25 # 26 # s1=School(‘oldboy‘,‘北京‘) 27 # c1=Course(‘python‘,200,‘1month‘) 28 # t1=Teacher(‘hf‘) 29 # print(s1.name) 30 # c1.jiao_ke() #oldboy正在开展python课程 类和类之间的关联 31 # t1.jiang_ke() #hf老师正在讲python课程
不过建议用第一种,不抽象
选课练习:
1 # _*_ encoding:utf-8 _*_ 2 __author__ = ‘listen‘ 3 __date__ = ‘2018/11/27 21:00‘ 4 5 6 #选课案例 7 class School: 8 def __init__(self,name,add): 9 self.name=name 10 self.add=add 11 12 class Course: 13 def __init__(self,name,price,period,school): 14 self.name=name 15 self.price=price 16 self.period=period 17 self.school=school 18 def jiao_ke(self): 19 print(‘%s课程很多人学习‘%(self.name)) 20 21 class Teacher: 22 def __init__(self,name,course,school): 23 self.name=name 24 self.course=course 25 self.school=school 26 def jiang_ke(self): 27 print(‘%s老师正在讲课‘%(self.name)) 28 29 s1=School(‘oldboy‘,‘北京校区‘) 30 s2=School(‘oldboy‘,‘上海校区‘) 31 s3=School(‘oldboy‘,‘深圳校区‘) 32 33 msg=""" 34 1 老男孩 北京校区 35 2 老男孩 上海校区 36 3 老男孩 深圳校区 37 """ 38 tag=True 39 while tag: 40 print(msg) 41 menue={ 42 ‘1‘:s1, 43 ‘2‘:s2, 44 ‘3‘:s3 45 } 46 choice=input(‘请选择学校 >>>‘) 47 school_obj=menue[choice] 48 name=input(‘课程名>>>‘) 49 price=input(‘价格>>>‘) 50 period = input(‘课程的周期>>>‘) 51 new_course=Course(name,price,period,school_obj) 52 print(‘%s课程是%s‘%(name,school_obj.add)) 53 54 msg1= """ 55 ‘1‘:‘袁浩‘, 56 ‘2‘: ‘海风‘, 57 ‘3‘: ‘佩琪‘ 58 """ 59 60 while tag: 61 print(msg1) 62 menue1 = { 63 ‘1‘:‘袁浩‘, 64 ‘2‘: ‘海风‘, 65 ‘3‘: ‘佩琪‘ 66 } 67 teacher_name=input(‘请输入课程的老师>>‘) 68 new_teacher = Teacher(menue1[teacher_name],new_course,school_obj) 69 print(‘您选择的老师是;%s‘%(new_teacher.name)) 70 print(‘您的选课结果是:------>>>[%s机构 %s %s老师的%s课程]‘% (school_obj.name,school_obj.add,new_teacher.name,new_course.name) ) 71 tag=False
九、面向对象的三大特性
一、继承
1、类的继承:类的继承和现实生活中的父、子、孙子、继承关系一样,父类又称为基类。
python中的继承分为:单继承和多继承
1 # _*_ encoding:utf-8 _*_ 2 class Dad: 3 pass 4 class Mom: 5 pass 6 class Son(Dad): 7 pass #单继承 8 class Daughter(Dad,Mom): #多继承 9 pass
2、子类继承了基类所有的属性
1 # _*_ encoding:utf-8 _*_ 2 __author__ = ‘listen‘ 3 __date__ = ‘2018/11/27 21:46‘ 4 class Dad: 5 money=1000 6 def __init__(self,name): 7 self.name=name 8 def da_pin(self): 9 print(‘%s努力为儿子打拼‘%self.name) 10 11 class Son(Dad): 12 money = 100000 #(后加的) 13 14 s1=Son(‘listen‘) 15 print(Son.money) #1000 自己里面没有会找父类属性 16 s1.da_pin() #listen努力为儿子打拼 调用父类的方法 17 print(Dad.__dict__) 18 print(Son.__dict__) #什么都没有 本来就没有定义什么 19 print(s1.money) #100000 20 print(Dad.money) #1000 同名的类变量并没有被子类的覆盖,相当于子类重新新增一个类变量
当类之间有显著的不同,并且较小的类是较大的类所需要的组件时,用组合比较好。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好。
3、接口和归一化设计
①、什么是接口
1 =================第一部分:Java 语言中的接口很好的展现了接口的含义: IAnimal.java 2 /* 3 * Java的Interface接口的特征: 4 * 1)是一组功能的集合,而不是一个功能 5 * 2)接口的功能用于交互,所有的功能都是public,即别的对象可操作 6 * 3)接口只定义函数,但不涉及函数实现 7 * 4)这些功能是相关的,都是动物相关的功能,但光合作用就不适宜放到IAnimal里面了 */ 8 9 package com.oo.demo; 10 public interface IAnimal { 11 public void eat(); 12 public void run(); 13 public void sleep(); 14 public void speak(); 15 } 16 17 =================第二部分:Pig.java:猪”的类设计,实现了IAnnimal接口 18 package com.oo.demo; 19 public class Pig implements IAnimal{ //如下每个函数都需要详细实现 20 public void eat(){ 21 System.out.println("Pig like to eat grass"); 22 } 23 24 public void run(){ 25 System.out.println("Pig run: front legs, back legs"); 26 } 27 28 public void sleep(){ 29 System.out.println("Pig sleep 16 hours every day"); 30 } 31 32 public void speak(){ 33 System.out.println("Pig can not speak"); } 34 } 35 36 =================第三部分:Person2.java 37 /* 38 *实现了IAnimal的“人”,有几点说明一下: 39 * 1)同样都实现了IAnimal的接口,但“人”和“猪”的实现不一样,为了避免太多代码导致影响阅读,这里的代码简化成一行,但输出的内容不一样,实际项目中同一接口的同一功能点,不同的类实现完全不一样 40 * 2)这里同样是“人”这个类,但和前面介绍类时给的类“Person”完全不一样,这是因为同样的逻辑概念,在不同的应用场景下,具备的属性和功能是完全不一样的 */ 41 42 package com.oo.demo; 43 public class Person2 implements IAnimal { 44 public void eat(){ 45 System.out.println("Person like to eat meat"); 46 } 47 48 public void run(){ 49 System.out.println("Person run: left leg, right leg"); 50 } 51 52 public void sleep(){ 53 System.out.println("Person sleep 8 hours every dat"); 54 } 55 56 public void speak(){ 57 System.out.println("Hellow world, I am a person"); 58 } 59 } 60 61 =================第四部分:Tester03.java 62 package com.oo.demo; 63 64 public class Tester03 { 65 public static void main(String[] args) { 66 System.out.println("===This is a person==="); 67 IAnimal person = new Person2(); 68 person.eat(); 69 person.run(); 70 person.sleep(); 71 person.speak(); 72 73 System.out.println(" ===This is a pig==="); 74 IAnimal pig = new Pig(); 75 pig.eat(); 76 pig.run(); 77 pig.sleep(); 78 pig.speak(); 79 } 80 } 81 82 java中的interface
PS:hi boy,给我开个查询接口。。。此时的接口指的是:自己提供给使用者来调用自己功能的方式方法入口
②、为何使用接口
接口提取了一群共同的函数,可以把接口当做一个函数的集合。
然后让子类去实现接口中的函数。
这么做得意义在于归一化,什么是归一化,就是只要基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上都一样。
归一化的优点:
1、归一化让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大限度的降低了使用者的使用难度。
2、归一化使高层的外部使用者可以不加区分的处理所有接口兼容的对象集合。
2.1:就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。
2.2:再比如:我们有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样
③、模仿interface
在python中没有一个关键字叫做interface,如果非要模仿接口的概念
可以借助第三方模块:
http://pypi.python.org/pypi/zope.interface
twisted的twistedinternetinterface.py里使用zope.interface
文档https://zopeinterface.readthedocs.io/en/latest/
设计模式:https://github.com/faif/python-patterns
也可以使用继承来实现:(下面3讲到)
3、继承同时具有两种含义:
1、继承基类的方法,并且做出自己的改变或者扩展。(代码重用)但继承的这种用途意义并不大,甚至有害的,因为使得基类和子类出现强耦合(功能都连到一块,并不明确)。----解耦
2、声明某个子类兼容于某基类,定义一个接口类(Java interface),接口类中定义了一些接口名(就是函数)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能。
1 class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。 2 def read(self): #定接口函数read 3 pass 4 5 def write(self): #定义接口函数write 6 pass 7 8 9 class Txt(Interface): #文本,具体实现read和write 10 def read(self): 11 print(‘文本数据的读取方法‘) 12 13 def write(self): 14 print(‘文本数据的读取方法‘) 15 16 class Sata(Interface): #磁盘,具体实现read和write 17 def read(self): 18 print(‘硬盘数据的读取方法‘) 19 20 def write(self): 21 print(‘硬盘数据的读取方法‘) 22 23 class Process(Interface): 24 def read(self): 25 print(‘进程数据的读取方法‘) 26 27 def write(self): 28 print(‘进程数据的读取方法‘)
上面的代码只是看起来像接口,其实并没有起到接口的作用,子类完全可以不用去实现接口,这就用到了抽象类
4、抽象类
1、什么是抽象类
与JAVA一样,python也有抽象类的概念但同样借助模块去实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能实例化 。
2、为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同内容而来的,内容包括数据属性和函数属性。
比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案
1 #一切皆文件 2 import abc #利用abc模块实现抽象类 3 4 class All_file(metaclass=abc.ABCMeta): 5 all_type=‘file‘ 6 @abc.abstractmethod #定义抽象方法,无需实现功能 7 def read(self): 8 ‘子类必须定义读功能‘ 9 pass 10 11 @abc.abstractmethod #定义抽象方法,无需实现功能 12 def write(self): 13 ‘子类必须定义写功能‘ 14 pass 15 16 # class Txt(All_file): 17 # pass 18 # 19 # t1=Txt() #报错,子类没有定义抽象方法 20 21 class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法 22 def read(self): 23 print(‘文本数据的读取方法‘) 24 25 def write(self): 26 print(‘文本数据的读取方法‘) 27 28 class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法 29 def read(self): 30 print(‘硬盘数据的读取方法‘) 31 32 def write(self): 33 print(‘硬盘数据的读取方法‘) 34 35 class Process(All_file): #子类继承抽象类,但是必须定义read和write方法 36 def read(self): 37 print(‘进程数据的读取方法‘) 38 39 def write(self): 40 print(‘进程数据的读取方法‘) 41 42 wenbenwenjian=Txt() 43 44 yingpanwenjian=Sata() 45 46 jinchengwenjian=Process() 47 48 #这样大家都是被归一化了,也就是一切皆文件的思想 49 wenbenwenjian.read() 50 yingpanwenjian.write() 51 jinchengwenjian.read() 52 53 print(wenbenwenjian.all_type) 54 print(yingpanwenjian.all_type) 55 print(jinchengwenjian.all_type)
3、抽象类和接口
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如:all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计。
5、继承顺序
当类是经典类,多继承情况下,会按照深度优先级方式查找。
当类是新式类,多继承情况下,会按照广度优先级方式查找。
经典类和新式类的差别:新式类在定义时便自动继承了object类,而经典类没有。python3都是新式类
新式类的继承顺序:对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表。
为了实现继承,python会再MRO列表上从左到右开始查找基类,直至找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不必深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表遵循如下三条准则;
1、子类会优先于父类被检查。
2、多个父类会根据它们在列表中的顺序被检查。
3、如果对下一个类存在两个合法的选择,会选择第一个类。
1 class A: 2 def test(self): 3 print("testA") 4 class B(A): 5 def test(self): 6 print("testB") 7 class C(A): 8 def test(self): 9 print("testC") 10 class D(B): 11 def test(self): 12 print("testD") 13 class E(C): 14 def test(self): 15 print("testE") 16 class F(D,E): 17 def test(self): 18 # print("testF") 19 pass 20 21 f1 = F() 22 print(F.__mro__)# 只有python3才有这个__mro__属性,python2没有(<class ‘__main__.F‘>, <class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>) 23 f1.test()#实例调用方法时,遵循mro顺序,会优先从子级寻找,找不到往上,先广度优先,若还找不到会找最深一级,若还没有会报错
新式类的继承顺序:F--D--B--E--C--A
经典类的继承顺序:E--D--B--A--E--C
python3中统一都是新式类
python2分为经典类(没有object)和新式类(带有object)
6、子类中调用父类的方法
方法一:指名道姓---即父类名.父类方法名
1 # _*_ encoding:utf-8 _*_ 2 __author__ = ‘listen‘ 3 __date__ = ‘2018/11/29 21:54‘ 4 #实现子类调用父类的数据属性和同名的函数属性 5 #方法一 6 # class Vehicle: 7 # counry=‘china‘ 8 # def __init__(self,name,speed,load,power): 9 # self.name=name 10 # self.speed=speed 11 # self.load=load 12 # self.power=power 13 # def run(self): 14 # print(‘开动啦‘) 15 # 16 # class Subway(Vehicle): 17 # def __init__(self,name,speed,load,power,line): 18 # Vehicle.__init__(self,name,speed,load,power) #类.方法调用 和父类一点关系也没有 体现不出继承关系 19 # self.line=line 20 # print(self.name,self.speed,self.load,self.power,self.line) #写活了 21 # #有一个和父类同名的方法,怎么调用? 22 # def run(self): 23 # Vehicle.run(self) 24 # print(‘%s号线开动啦‘%self.line) 25 # s=Subway(‘北京地铁‘,‘10m/s‘,10000,‘电‘,‘13‘) #开动啦 26 # s.run() #13号线开动啦
方法二:super()
1 class Vehicle: 2 counry=‘china‘ 3 def __init__(self,name,speed,load,power): 4 self.name=name 5 self.speed=speed 6 self.load=load 7 self.power=power 8 def run(self): 9 print(‘开动啦‘) 10 11 class Subway(Vehicle): 12 def __init__(self,name,speed,load,power,line): 13 super().__init__(name,speed,load,power) #万一这个类名改变了,整个代码都要动 麻烦 所有来了另一种方式 14 self.line=line 15 print(self.name,self.speed,self.load,self.power,self.line) #写活了 16 #有一个和父类同名的方法,怎么调用? 17 def run(self): 18 super().run() 19 print(‘%s号线开动啦‘%self.line) 20 s=Subway(‘北京地铁‘,‘10m/s‘,10000,‘电‘,‘13‘) #开动啦 21 s.run()
注意:两种方法使用哪都可以,但最好不要混用
二、多态
1、多态
2、多态性
一、多态
多态指的是一类事物有多种形态
h2o根据温度不同,有多种形态,液态水、冰、蒸汽
1 # class H2o: 2 # def __init__(self,name,temputer): 3 # self.name=name 4 # self.temputer=temputer 5 # def turn_ice(self): 6 # if self.temputer<0: 7 # print(‘[%s]温度太低,结冰了‘%self.name) 8 # elif self.temputer>0 and self.temputer<100: 9 # print(‘[%s]是流动的水‘%self.name) 10 # elif self.temputer>100: 11 # print(‘[%s]温度太高,变为水蒸气了‘%self.name) 12 # #水分为三种不同的形态 13 # class Water(H2o): 14 # pass 15 # 16 # 17 # class Ice(H2o): 18 # pass 19 # 20 # 21 # class Steam(H2o): 22 # pass 23 #
二、多态性
1、什么是多态动态的绑定?
在继承的背景下使用时,有时候也称多态性
多态性是指在不考虑实例的类型下使用实例
通俗的解释:在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。 比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同。
1 import abc 2 class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 3 @abc.abstractmethod 4 def talk(self): 5 pass 6 7 class People(Animal): #动物的形态之一:人 8 def talk(self): 9 print(‘say hello‘) 10 11 class Dog(Animal): #动物的形态之二:狗 12 def talk(self): 13 print(‘say wangwang‘) 14 15 class Pig(Animal): #动物的形态之三:猪 16 def talk(self): 17 print(‘say aoao‘)
1 peo=People() 2 dog=Dog() 3 pig=Pig() 4 5 #peo、dog、pig都是动物,只要是动物肯定有talk方法 6 #于是我们可以不用考虑它们三者的具体是什么类型,而直接使用 7 peo.talk() 8 dog.talk() 9 pig.talk() 10 11 #更进一步,我们可以定义一个统一的接口来使用 12 def func(obj): 13 obj.talk()
2、为什么要用多态性
1、增加程序的灵活性
以不变去应万变,不论对象千变万化,使用者都是同一种形式去调如fun(animal)
2、增加程序的可扩展性
通过继承animal类创建一个新的类,使用者无需改变自己代码,只需用func(animal)去调用
3、多态实际上就是继承的过程的体现
1 # _*_ encoding:utf-8 _*_ 2 __author__ = ‘listen‘ 3 __date__ = ‘2018/12/1 9:05‘ 4 # class H2o: 5 # def __init__(self,name,temputer): 6 # self.name=name 7 # self.temputer=temputer 8 # def turn_ice(self): 9 # if self.temputer<0: 10 # print(‘[%s]温度太低,结冰了‘%self.name) 11 # elif self.temputer>0 and self.temputer<100: 12 # print(‘[%s]是流动的水‘%self.name) 13 # elif self.temputer>100: 14 # print(‘[%s]温度太高,变为水蒸气了‘%self.name) 15 # #水分为三种不同的形态 16 # class Water(H2o): 17 # pass 18 # 19 # 20 # class Ice(H2o): 21 # pass 22 # 23 # 24 # class Steam(H2o): 25 # pass 26 # 27 # w1=Water(‘液态水‘,25) 28 # i1=Ice(‘固态冰‘,-10) 29 # s1=Steam(‘水蒸气‘,120) 30 # 31 # w1.turn_ice() 32 # i1.turn_ice() 33 # s1.turn_ice() 34 # python中标准类型就是多态的一个和好的示范 35 #好比__len__()这个方法 两个不同的对象调用相同的方法 就好比这两个对象的类都有继承同一个类,然后调用同一个类的一个方法 36 # s=‘123‘ 37 # l=[1,2,3] 38 # print(s.__len__()) #3 39 # print(l.__len__()) #3 40 41 #len()方法也可以实现 42 # s=‘123‘ 43 # l=[1,2,3] 44 # print(len(s)) #3 45 # print(len(l)) #3
多态反应的是运行的状态,不同的对象调用相同的方法,说明多态是由继承来的,先让子类继承父类,然后调用父类的方法。
所以说继承和多态分不开,继承和多态是相辅相成的,多态依赖于继承,但继承必须是让多态去实现,要不放那一个方法,没人去调用,失去了它的意义所在。
1 #怎么用上面的例子也实现这种方法呢-------------------接口(函数) 2 class Dt: 3 def __init__(self,name,temputer): 4 self.name=name 5 self.temputer=temputer 6 def turn_ice(self): 7 if self.temputer<0: 8 print(‘[%s]温度太低,结冰了‘%self.name) 9 elif self.temputer>0 and self.temputer<100: 10 print(‘[%s]是流动的水‘%self.name) 11 elif self.temputer>100: 12 print(‘[%s]温度太高,变为水蒸气了‘%self.name) 13 14 def func(obj): 15 return obj.turn_ice() 16 #水分为三种不同的形态 17 class Water(Dt): 18 pass 19 20 21 class Ice(Dt): 22 pass 23 24 25 class Steam(Dt): 26 pass 27 28 w1=Water(‘液态水‘,25) 29 i1=Ice(‘固态冰‘,-10) 30 s1=Steam(‘水蒸气‘,120) 31 32 func(w1) 33 func(i1) 34 func(s1)
三、封装
封装的概念就是隐藏
1、第一个层面的封装:类就是麻袋,里面有各种属性(数据属性和函数属性)这本身就是一种封装。
2、第二个层面的封装:类中定义私有的,只在内部使用,外部无法访问,类中定义属性名时在其前面加上_或__可实现该属性的隐藏,但这种隐藏只是一种语言上的预定,python并不会从底层禁止你的访问。
1 #封装,装是指把类的属性放到类的字典中,属性好比装的东西,类好比麻袋,封指的是把袋子口封好,不让别人看到,隐藏起来 2 # class People: 3 # # star=‘earth‘ 4 # # _star = ‘earth‘ 5 # __star=‘earth‘ 6 # def __init__(self,name,age,salary): 7 # self.name=name 8 # self.age=age 9 # self.salary=salary 10 # def get_id(self): 11 # print(‘我是私有的id‘) #私有的代表只能内部访问的到,外部访问不到 12 # 13 # p1=People(‘listen‘,18,10000) 14 # # print(p1.star) 15 # # print(p1._star) #外部照样可以访问到,没有实现封装功能 16 # # print(p1.__star) #外部就访问不到了 但是没有实现真正意义上的私有 17 # print(People.__dict__) 18 # print(p1._People__star) #earth 可以访问到了 _类名.属性名(实例._类名__单纯的属性名)
可以通过People.__dict__看到类内部自动给类的属性添加上了_People__star属性
3、第三个层面的封装:封装要充分考虑内和外的区别,应充分考虑好哪些应该是需要封装起来的,不需要让用户知道的,他们只需要会用就好,哪些他们会用到,就不要封装了,一旦把用户经常使用的封装起来,后面得写好多接口,目的是让用户可以访问到这个私有属性,最后接口越来越多,看起来很low。
1 class Room: 2 def __init__(self,length,weight,height): 3 self.__length=length 4 self.__weight=weight 5 self.__height=height 6 #真正意义的封装区分内部和外部 内部可以知道 外部只管用,不需要知道内部怎么去实现的 7 #所以封装的时候充分考虑用户的需要,用户不需要的就分装在里面,外部定义接口,用户直接使用就行,对于经常用到的,不要封装起来,以免以后得开好多口子,写好多接口,让类变得好low 8 #一旦封装好属性,就不能修改了,一旦单独修改属性,里面定义的函数属性就都得改,整个框架就乱了,所以为了实现这一功能,只能定义接口 9 def tell_area(self): 10 return self.__length*self.__weight 11 def tell_tiji(self): 12 return self.__length*self.__weight*self.__height 13 14 r=Room(10,10,10) 15 print(r.tell_area()) #求面积 16 print(r.tell_tiji()) #求体积
总结:继承、多态、封装是一种思想,比一定说一定要用这三种特性就好,为了用而用,只是支持这种特性,不要滥用
面向对象的优点:
从编程进化论我们得知,面向对象是一种更高等级的结构化编程方式,它的好处有两点:
1、通过封装明确了内外,作为缔造者,你来产生对象,无需让对象知道你的产生逻辑,这样就明确划分了等级,物就是调用者,缔造者就是物的创造者。
2、通过继承+多态在语言上层面上支持了归一化设计
注意:不用面向对象语言(即不用class),一样可以做归一化(一切皆文件,linux中),一样可以封装(通过定义接口和模块),只是面向对象语言可以直接用语言元素显示声明而已,而用了面向对象,满篇都是class,并不等于有了归一化设计。
以上是关于python-----面向对象的主要内容,如果未能解决你的问题,请参考以下文章