Python全栈day24-25(面向对象编程)
参考文档:
http://www.cnblogs.com/linhaifeng/articles/6182264.html#
类:把一类事物的相同的特征和动作整合到一起就是类,类是抽象的概练
对象:就是基于类而创建的具体存在的,也是特征和动作整合到一起
一,面向对象设计过程
现实世界中先有对象有了明确的特征以及动作才有类,比如先有人,人有名字,有性别等特征,有吃饭睡觉等动作,有着这些相同的人统称为人类
设计一个公司,公司有名称,有地址,有公司类型,有上班的动作
面向对象设计1.py
1 2 3 4 5 6 7 8 9 10 11 12 | c1 = { 'name' : 'bbc' , 'addr' : 'ShenZhen' , 'type' : 'big' } def shangban(company): print ( '[%s]公司在[%s]是一家[%s]正常上班' % (company[ 'name' ],company[ 'addr' ],company[ 'type' ])) shangban(c1) #[bbc]公司在[ShenZhen]是一家[big]正常上班 |
这样设置假如有另外一家公司又需要定义一个新的字典比如c2,明显不合理。
把公司定义为一个函数作为一个类来生成公司
面向对象设计2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #定义公司的函数,参数为公司名称name公司地址addr公司类型type def company(name,addr, type ): def shangban(c): print ( '[%s]公司在[%s]是一家[%s]正常上班' % (c[ 'name' ],c[ 'addr' ],c[ 'type' ])) #定义一个字典接收用户传递的公司信息,并且作为函数的返回值 c1 = { 'name' : name, 'addr' : addr, 'type' : type , 'shangban' : shangban } return c1 #通过定义的函数company相当于是定义的类生成一个公司 #返回的是一个字典 c1 = company( 'bbc' , 'ShenZhen' , 'big' ) print (c1) #{'shangban': <function company.<locals>.shangban at 0x000001F812336950>, 'addr': 'ShenZhen', 'name': 'bbc', 'type': 'big'} #需要执行公司的一个特定动作,因为函数内部的动作函数上班需要传递的参数为一个字典及需要传递刚刚的公司返回值作为参数执行 c1[ 'shangban' ](c1) #[bbc]公司在[ShenZhen]是一家[big]正常上班 #同理可以通过定义的公司类生成另外一个对象及另外一家公司 c2 = company( 'CCTV' , 'BeiJing' , 'litter' ) c2[ 'shangban' ](c2) #[CCTV]公司在[BeiJing]是一家[litter]正常上班 |
这样定义还不够好,需要在内部在定义一个初始化函数init用于初始化公司信息
面向对象设计3.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # 定义公司的函数,参数为公司名称name公司地址addr公司类型type def company(name, addr, type ): def shangban(c): print ( '[%s]公司在[%s]是一家[%s]正常上班' % (c[ 'name' ], c[ 'addr' ], c[ 'type' ])) # 定义一个字典接收用户传递的公司信息,并且作为函数的返回值 def init(name,addr, type ): c1 = { 'name' : name, 'addr' : addr, 'type' : type , 'shangban' : shangban } return c1 #运行初始化公司的函数,运行的结果也就是一个字典作为返回值返回 ret = init(name,addr, type ) print (ret) #{'type': 'big', 'addr': 'ShenZhen', 'shangban': <function company.<locals>.shangban at 0x0000016212AC6950>, 'name': 'bbc'} return ret # 通过定义的函数company相当于是定义的类生成一个公司 # 返回的是一个字典 c1 = company( 'bbc' , 'ShenZhen' , 'big' ) #print(c1) # {'shangban': <function company.<locals>.shangban at 0x000001F812336950>, 'addr': 'ShenZhen', 'name': 'bbc', 'type': 'big'} # 需要执行公司的一个特定动作,因为函数内部的动作函数上班需要传递的参数为一个字典及需要传递刚刚的公司返回值作为参数执行 c1[ 'shangban' ](c1) # [bbc]公司在[ShenZhen]是一家[big]正常上班 # 同理可以通过定义的公司类生成另外一个对象及另外一家公司 #c2 = company('CCTV', 'BeiJing', 'litter') #c2['shangban'](c2) # [CCTV]公司在[BeiJing]是一家[litter]正常上班 |
以上的编程思想就是面向对象的编程思想,虽然是使用函数的方式来实现的。
下面使用python提供的类方法class实现
面向对象设计4.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class company: def __init__( self ,name,addr, type ): self .name = name self .addr = addr self . type = type def shangban( self ): print ( '[%s]公司在[%s]是一家[%s]公司正常上班' % ( self .name, self .addr, self . type )) c1 = company( 'bbc' , 'ShenZhen' , 'big' ) #使用内置方法可以打印出对应的字典 #与函数实现的面向对象的方法返回来的字典不同少了一个函数对应的对象,直接打印出字典 print (c1.__dict__) #{'addr': 'ShenZhen', 'name': 'bbc', 'type': 'big'} c1.shangban() #[bbc]公司在[ShenZhen]是一家[big]公司正常上班 |
二,类的相关知识
类的相关知识.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class Chinese: #这是一个中国人的类 dang = '党' def sui_di_tu_tan( self ): print ( '%s朝着墙上就是一口痰' % self ) def cha_dui( self ): print ( '插到了前面' ) print (Chinese.dang) Chinese.sui_di_tu_tan( 'asd' ) #查看类的属性 print ( dir (Chinese)) #查看类的属性字典 print (Chinese.__dict__) #打印类名 print (Chinese.__name__) #Chinese #打印类的文档名 print (Chinese.__doc__) #None #打印类的祖先 print (Chinese.__base__) #<class 'object'> print (Chinese.__bases__) #打印类的祖先(以元祖的形式) #(<class 'object'>,) #打印类的模块 print (Chinese.__module__) #__main__ #打印实例对应的类 print (Chinese.__class__) #<class 'type'> |
类的相关知识2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | class Chinese: #这是一个中国人的类 dang = '党' #定义初始化函数 必须用__init__这种定义方式才能接收参数 #不需要像函数一样写return #必须有默认需要的self参数 def __init__( self ,name,age,gender): print ( '我是初始化函数 我开始运行了' ) #dic = { # 'name':name, # 'age':age, # 'gender':gender # } #return dic self .mingzi = name self .nianji = age self .xingbie = gender print ( '初始化函数运行完毕' ) def sui_di_tu_tan( self ): print ( '朝着墙上就是一口痰' ) def cha_dui( self ): print ( '%s插到了前面' % self .mingzi) #return init(name,age,gender) #实例化 #其实就是调用了类里面__init__这个函数的运行 #返回的就是一个实例化以后的对象 #其实执行的过程是p1 = __init__(p1,name,age,genter) p1 = Chinese( '月明' , 18 , 'female' ) #打印p1这个对象的字典属性 print (p1.__dict__) #{'mingzi': '月明', 'nianji': 18, 'xingbie': 'female'} #调用字典对象的属性 #以下两种方法效果一样,第二种更加简洁高效 print (p1.__dict__[ 'mingzi' ]) print (p1.mingzi) #月明 #调用类的属性(虽然这个属性不在字典里面) #为什么可以打印出来,和函数的作用域有关 #在本作用域找不到就返回上一层寻找 print (p1.dang) #党 #通过类调用里面的方法和实例无关 #因为函数需要一个参数把实例化以后的对象p1作为参数传递 Chinese.cha_dui(p1) #p1.sui_di_tu_tan() #默认已经把p1对象作为参数传递给函数cha_dui所以这里调用在()里面不需要加参数 p1.cha_dui() #PS:类有数据属性和函数属性 实例(对象)只有数据属性没有函数属性需要使用函数属性去找类要 |
PS:类里面定义的方法函数都需要带有self参数,调用方法默认把对象作为实参传递给形参self
类属性的增删改查
类属性的增删改查.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #类属性又称为静态变量,或者静态数据。这些数据与他们所属的类对象绑定,不依赖于任何类实例 class ChinesePeople: country = 'China' def __init__( self ,name): self .name = name #函数属性定义的原则是动词加名词(做什么事情) def play_ball( self ,ball): print ( '%s 正在打 %s' % ( self .name)) def say_word( self ,word): print ( '%s 说 %s' % ( self .name,word)) #查看类属性 print (ChinesePeople.country) #China #修改类属性 ChinesePeople.country = 'CHINA' #修改后查看 print (ChinesePeople.country) #CHINA #删除类属性 del ChinesePeople.country #打印会报错因为没有这个属性了 #print(ChinesePeople.country) #增加类属性 ChinesePeople.location = 'ASia' p1 = ChinesePeople( 'zhangsan' ) #增加函数方法 def eat_food( self ,food): print ( '%s正在吃%s' % ( self .name,food)) ChinesePeople.eat = eat_food print (ChinesePeople.__dict__) p1.eat( '米饭' ) #zhangsan正在吃米饭 #修改函数方法是重新定义一个函数然后赋值给原函数方法 def test( self ): print ( 'test' ) ChinesePeople.play_ball = test p1.play_ball() |
实例属性的增删改查.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #类属性又称为静态变量,或者静态数据。这些数据与他们所属的类对象绑定,不依赖于任何类实例 class ChinesePeople: country = 'China' def __init__( self ,name): self .name = name #函数属性定义的原则是动词加名词(做什么事情) def play_ball( self ,ball): print ( '%s 正在打 %s' % ( self .name,ball)) def say_word( self ,word): print ( '%s 说 %s' % ( self .name,word)) p1 = ChinesePeople( 'zhangsan' ) #查看实例属性字典 print (p1.__dict__) #{'name': 'zhangsan'} #查看实例的数据属性 print (p1.name) #zhangsan #查看实例的函数属性 print (p1.play_ball) #<bound method ChinesePeople.play_ball of <__main__.ChinesePeople object at 0x000001FA7A8D72B0>> #PS:可以看到这个一个绑定在类ChinesePeople的方法 #增加数据属性 p1.age = 18 print (p1.__dict__) #{'name': 'zhangsan', 'age': 18} def test( self ): print ( '我是来自实例的函数属性' ) #增加实例的函数属性 p1.test = test print (p1.__dict__) #{'age': 18, 'test': <function test at 0x00000155FE2A9048>, 'name': 'zhangsan'} #调用不会传递默认参数需要手动加 p1.test(p1) #PS:实例的函数属性增加几乎不用,知道即可 #需要增加函数属性直接在类里面定义这步纯属多余 #PS:实例只有数据属性,之所以能添加修改是因为是直接对字典进行修改,强烈不建议修改字典属性 #修改 p1.age = 19 print (p1.__dict__) #{'age': 19, 'name': 'zhangsan', 'test': <function test at 0x0000027325FF9048>} #删除 del p1.age print (p1.__dict__) #删除后就没有age了 #{'name': 'zhangsan', 'test': <function test at 0x000001F784489048>} |
类里面定义的数据属性及函数属性通过定义的对象加.调用,如果不使用对象加.的方式调用其实就相当于一个普通变量,看以下列子
类里面数据属性及函数属性的调用方式.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | country = '中国---' class ChinesePeople: country = '中国' def __init__( self ,name): self .name = name print ( '不使用.的调用方式调用的就是一个普通的变量' ,country) #函数属性定义的原则是动词加名词(做什么事情) def play_ball( self ,ball): print ( '%s 正在打 %s' % ( self .name,ball)) #对象实例化会执行__init__函数 因为在里面定义了一个print打印country这里的country因为没有加.所以只是一个普通的全局变量 #在类里面也定义了country但是这个是在类里面的,需要通过加.调用 p1 = ChinesePeople( '张三' ) #不使用.的调用方式调用的就是一个普通的变量 中国--- #使用.调用类的属性 print (ChinesePeople.country) #中国 #实例对应的属性也是中国 print ( '实例的' ,p1.country) |
之前对对象及类的属性修改均是通过赋值的方式修改,假如类里面有个数据属性是一个列表通过append等方式直接修改列表情况又不一样
对象属性补充.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class ChinesePeople: country = 'China' l = [ 'a' , 'b' ] def __init__( self ,name): self .name = name def play_ball( self ,ball): print ( '%s 正在打 %s' % ( self .name,ball)) p1 = ChinesePeople( 'zhangsan' ) p1.country = 'Japan' #修改p1的countr对应的值后类的对应值保持China不变 print (p1.country) #Japan print (ChinesePeople.country) #China #以上是通过赋值的方式修改,但是通过如下的方式修改其实是对类里面的列表进行修改所 #所以类和对象对应的属性均修改了 p1.l.append( 'c' ) print (p1.l) ##['a', 'b', 'c'] print (ChinesePeople.l) ##['a', 'b', 'c'] |
PS:实例(对象)调用类的方法会自动传递参数,类调用类的方法需要手动输入参数
三,静态属性
看以下列子
静态属性1.py
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Room: def __init__( self ,name,owner,width,length,heigh): self .name = name self .owner = owner self .width = width self .length = length self .heigh = heigh r1 = Room( '厕所' , 'zhangsan' , 100 , 100 , 10000 ) print ( '[%s] 住的 %s 总面积是%s' % (r1.owner,r1.name,r1.width * r1.length)) #[zhangsan] 住的 厕所 总面积是10000 |
需要计算出住所面积,可以直接在类外面调用对应参数计算,假如需要计算多个人员的则最好把计算面积写在类里面定下一个方法
静态属性2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Room: def __init__( self ,name,owner,width,length,heigh): self .name = name self .owner = owner self .width = width self .length = length self .heigh = heigh #定义计算面积的函数方法 def cal_area( self ): print ( '[%s] 住的 %s 总面积是%s' % ( self .owner, self .name, self .width * self .length)) r1 = Room( '厕所' , 'zhangsan' , 100 , 100 , 10000 ) #直接通过函数调用,减少重复代码 r1.cal_area() |
Python类提供一个装饰器的方法把该动态的函数属性转换成一个静态属性
静态属性3.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class Room: def __init__( self ,name,owner,width,length,heigh): self .name = name self .owner = owner self .width = width self .length = length self .heigh = heigh # 定义计算面积的函数方法 # 并且使用property装饰成静态属性 @property def cal_area( self ): print ( '[%s] 住的 %s 总面积是%s' % ( self .owner, self .name, self .width * self .length)) r1 = Room( '厕所' , 'zhangsan' , 100 , 100 , 10000 ) #调用不需要加()来执行函数 r1.cal_area #[zhangsan] 住的 厕所 总面积是10000 |
在类内部加了装饰器调用时候和调用数据属性一样,对于外部调用用户无感知,不知道在类里面定义的是数据类型还是函数类型
四,类方法
一个类需要调用类里面的属性必须要通过一个实例(对象)调用或者通过类调用(也需要传递一个实例作为参数)
以下列子需要获取到类的数据属性tag信息
类方法1.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class Room: tag = 1 def __init__( self ,name,owner,width,length,heigh): self .name = name self .owner = owner self .width = width self .length = length self .heigh = heigh # def tell_info(cls): # print('--->',cls.tag) def tell_info( self ): print ( '---->' , self .tag ) r1 = Room( 'WC' , 'zhangsan' , 1 , 1 , 1 ) #通过实例获取信息 r1.tell_info() #----> 1 #就算是通过类来执行也需要传递一个实例参数才能获取信息 Room.tell_info(r1) #----> 1 |
Python类提供装饰器可以不通过实例(对象直接获取对应数据属性),不需要借助实例(对象)
类方法2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Room: tag = 1 def __init__( self ,name,owner,width,length,heigh): self .name = name self .owner = owner self .width = width self .length = length self .heigh = heigh #类方法装饰器 @classmethod def tell_info( cls ): print ( '--->' , cls .tag) #通过类方法调用对应数据属性 Room.tell_info() #---> 1 |
五,静态方法
静态方法1.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class Room: tag = 1 def __init__( self ,name,owner,width,length,heigh): self .name = name self .owner = owner self .width = width self .length = length self .heigh = heigh @property def cal_area( self ): print ( '[%s] 住的 %s 总面积是%s' % ( self .owner, self .name, self .width * self .length)) @classmethod def tell_info( cls ): print ( '--->' , cls .tag) #静态方法装饰器 #类的工具包,与类和实例是剥离的 #静态方法只是名义上归属类管理,不能使用类变量和实例变量,只是类的工具包 @staticmethod def wash_body(a,b,c): print ( '%s %s %s正在洗澡' % (a,b,c)) def test(x,y): print (x,y) #使用类可以调用静态方法 Room.wash_body( 'zhangsan' , 'lisi' , 'wangwu' ) #zhangsan lisi wangwu正在洗澡 #使用实例(对象)也可以调用静态方法 r1 = Room( 'WC' , 'zhangsan' , 1 , 1 , 1 ) r1.wash_body( 'zhangsan' , 'lisi' , 'wangwu' ) #zhangsan lisi wangwu正在洗澡 #PS:静态方法其实就相当于一个普通的函数,只不过是定义在类里面 |
小结:
静态属性是把函数封装成数据属性的形式,外面调用感受不到内部的逻辑
类方法定义时候自动加参数cls,可以不通过实例访问类的数据属性和函数属性,不能访问实例的属性
静态方法参数不是self和cls,不能访问类的属性和实例属性,只是类的工具包
六,组合
组合.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | # class Hand: # pass # # class Foot: # pass # # class Trunk: # pass # # class Head: # pass # # class Person: # def __init__(self,id_num,name): # self.id_num=id_num # self.name=name # self.hand=Hand() # self.foot=Foot() # self.trunk=Trunk() # self.head=Head() # p1 = Person('1111','zhangs') # # print(p1.__dict__) #定义学校类,有名字,地址 class School: def __init__( self ,name,addr): self .name = name self .addr = addr def zhao_sheng( self ): print ( '%s正在招生' % self .name) #定义课程类,有名字,价格,周期,学校 class Course: def __init__( self ,name,price,period,school): self .name = name self .price = price self .period = period self .school = school #实例化出3个校区 s1 = School( 'oldboy' , '北京' ) s2 = School( 'oldboy' , '南京' ) s3 = School( 'oldboy' , '东京' ) #实例化出1个课程 #学校传递一个实例化出来的学校 c1 = Course( 'linux' , 10 , '1h' ,s1) print (c1.__dict__) #{'period': '1h', 'school': <__main__.School object at 0x000002BB732E8080>, 'price': 10, 'name': 'linux'} print (c1.school.name) #oldboy msg = ''' 1,老男孩 北京校区 2,老男孩 南京校区 3,老男孩 东京校区 ''' while True : print (msg) menu = { '1' :s1, '2' :s2, '3' :s3 } choice = input ( '选择学校>>:' ) school_boj = menu[choice] name = input ( '课程名>>:' ) price = input ( '课程费用>>:' ) period = input ( '课程周期>>:' ) new_course = Course(name,price,period,school_boj) print ( '课程[%s]属于[%s]学校[%s]校区' % (new_course.name,new_course.school.name,menu[choice].addr)) |
七,面向对象的三大特性
1,继承
类的继承类似于现实生活中的父子等关系
继承1.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Dad: money = 10 def __init__( self ,name): print ( '爸爸' ) self .name = name def hit_son( self ): print ( '%s正在打儿子' % self .name) #定义一个类继承Dad class Son(Dad): pass s1 = Son( 'zhangsan' ) print (s1.name) #zhangsan #子类继承父类的数据属性 print (s1.money) #子类继承父类的方法 s1.hit_son() #zhangsan正在打儿子 |
什么时候用继承
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
例如:描述一个机器人了,机器人这个大类是由很多互不相关的小类组成,比如机械胳膊类,腿类,身体类
当类之间有很多相同的功能,提取这些共同的功能组成基类,用继承比较好
例如
猫可以:喵喵叫,吃喝拉撒
狗可以:汪汪叫,吃喝拉撒
单独定义
继承2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class 猫: def 喵喵叫( self ): print ( '喵喵叫' ) def 吃( self ): pass def 喝( self ): pass def 拉( self ): pass def 撒( self ): pass class 狗: def 汪汪叫( self ): print ( '汪汪叫' ) def 吃( self ): pass def 喝( self ): pass def 拉( self ): pass def 撒( self ): pass |
定义一个动物父类用于继承
继承3.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class 动物: def 吃( self ): pass def 喝( self ): pass def 拉( self ): pass def 撒( self ): pass class 猫(动物): def 喵喵叫( self ): print ( '喵喵叫' ) class 狗(动物): def 汪汪叫( self ): print ( '汪汪叫' ) |
概念:继承和衍生
子类继承了父类的方法,子类衍生出自己的方法
以上的代码实现
继承4.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | class Animal: def eat( self ): print ( '%s 吃' % self .name) def drink( self ): print ( '%s 喝' % self .name) def shit( self ): print ( '%s 拉' % self .name) def pee( self ): print ( '%s 撒' % self .name) class Cat(Animal): def __init__( self ,name): self .name = name self .breed = '猫' def cry( self ): print ( '喵喵叫' ) class Dog(Animal): def __init__( self , name): self .name = name self .breed = '狗' def cry( self ): print ( '汪汪叫' ) # ######## 执行 ######## c1 = Cat( '小白家的小黑猫' ) c1.eat() #小白家的小黑猫 吃 c2 = Cat( '小黑家的小白猫' ) c2.drink() #小黑家的小白猫 喝 |
继承同时具有两种含义
含义一,继承基类的方法,并且做出自己的改变或者扩展(代码重用)
含义二,声明某个子类兼容于某基类,定义一个接口类,子类继承接口类,并且实现接口中定义的方法
接口继承.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import abc #接口继承定义的方式与普通的有不同看以下代码 class All_file(metaclass = abc.ABCMeta): @abc .abstractmethod def read( self ): pass @abc .abstractmethod def write( self ): pass class Disk(All_file): def read( self ): print ( 'disk read' ) def write( self ): print ( 'disk write' ) class Cdrom(All_file): def read( self ): print ( 'cdrom read' ) def write( self ): print ( 'cdrom write' ) class Mem(All_file): def read( self ): print ( 'mem read' ) def write( self ): print ( 'mem write' ) m1 = Mem() m1.read() #mem read m1.write() #mem write |
接口继承需要在子类中分别定义父类中有的方法,并且必须定义,否则调用的时候报错
PS:接口基类只是一个规范,不需要实例化
继承顺序
按如下图示写继承
继承顺序.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class A: def test( self ): print ( "A" ) class B(A): # def test(self): # print("B") pass class C(A): # def test(self): # print("C") pass class D(B): # def test(self): # print("D") pass class E(C): # def test(self): # print("E") pass class F(D,E): # def test(self): # print("F") pass # # f1=F() # f1.test() print (F.__mro__) #(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) |
对于定义的每一个类,python会计算出一个方法解析顺序(MRO)列表
MRO列表遵循如下三条准则
- 子类会先于父类被检查
- 多个父类会根据他们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
在子类中调用父类的方法
在子类中调用父类的方法.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #定义交通工具类 class Vehicle: Country = 'China' def __init__( self ,name,speed,load,power): self .name = name self .speed = speed self .load = load self .power = power def run( self ): print ( '开动了...' ) #定义地铁类 class Subway(Vehicle): def __init__( self ,name,speed,load,power,line): # self.name=name # self.speed = speed # self.load = load # self.power = power #减少代码重复在子类中调用父类的方法 #需要和父类中一样传递对应参数 Vehicle.__init__( self ,name,speed,load,power) self .line = line def show_info( self ): print ( self .name, self .line) def run( self ): Vehicle.run( self ) print ( '%s %s 线,开动了' % ( self .name, self .line)) line13 = Subway( '北京地铁' , '10km/s' , 100000000 , '电' , 13 ) line13.show_info() line13.run() |
PS:在子类中调用父类为了减少代码重复可以使用以上方法,多余的参数再另外定义
假如父类名称有变改,可以使用super方法
super方法的使用.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #定义交通工具类 class Vehicle: Country = 'China' def __init__( self ,name,speed,load,power): self .name = name self .speed = speed self .load = load self .power = power def run( self ): print ( '开动了...' ) #定义地铁类 class Subway(Vehicle): def __init__( self ,name,speed,load,power,line): #Vehicle.__init__(self,name,speed,load,power) #使用super方法代替以上方法,不需要写父类名 #不需要传递参数self super ().__init__(name,speed,load,power) self .line = line def show_info( self ): print ( self .name, self .line) def run( self ): #Vehicle.run(self) super ().run() print ( '%s %s 线,开动了' % ( self .name, self .line)) line13 = Subway( '北京地铁' , '10km/s' , 100000000 , '电' , 13 ) line13.show_info() line13.run() |
2,多态
多态1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | class H2O: def __init__( self ,name,temperature): self .name = name self .temperature = temperature def turn_ice( self ): if self .temperature < 0 : print ( '[%s]温度太低结冰了' % self .name) elif self .temperature > 0 and self .temperature < 100 : print ( '[%s]液化成水' % self .name) elif self .temperature > 100 : print ( '[%s]温度太高变成了水蒸气' % self .name) class Water(H2O): pass class Ice(H2O): pass class Steam(H2O): pass w1 = Water( '水' , 25 ) i1 = Ice( '冰' , - 20 ) s1 = Steam( '蒸汽' , 3000 ) #三个对象调用相同的方法,执行的结果不一样 w1.turn_ice() #[水]液化成水 i1.turn_ice() #[冰]温度太低结冰了 s1.turn_ice() #[蒸汽]温度太高变成了水蒸气 #改成一个函数形式 def func(obj): obj.turn_ice() func(w1) func(i1) func(s1) |
3,封装
封装1.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class People: #前面加_代表私有属性或者私有方法 _star = 'earth' def __init__( self , id ,name,age,salary): self . id = id self .name = name self ._age = age self ._salary = salary def _get_id( self ): print ( '我是私有方法,我找到的id是[%s]' % self . id ) print (People._star) p1 = People( '362426199001011111' , 'zhangsan' , 18 , 10 ) print (p1._age,p1._salary) p1._get_id() |
以上只是加了一个_进行封装
封装2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class People: #前面加_代表私有属性或者私有方法 __star = 'earth' def __init__( self , id ,name,age,salary): self . id = id self .name = name self ._age = age self ._salary = salary def _get_id( self ): print ( '我是私有方法,我找到的id是[%s]' % self . id ) #print(People._star) p1 = People( '362426199001011111' , 'zhangsan' , 18 , 10 ) print (p1._age,p1._salary) p1._get_id() #加两个_的需要通过类名来调用 print (p1._People__star) |
封装属性虽然可以在外部使用方法调用但是一般不这样调用,可以在内部定义接口函数来访问内部的私有变量
这种封装才是真正意义的封装
封装3.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Room: def __init__( self ,name,owner,width,length,high): self .name = name self .owner = owner self .__width = width self .__length = length self .__high = high #在内部定义函数可以访问私有变量计算面积 #该函数是接口函数 def tell_arer( self ): return self .__width * self .__length #如果在编写程序之初就被封装了,但是在使用过程中被频繁调用 #可能需要再另外开接口函数来放开 #所以在设计之初就要确定哪些参数需要隐藏 def tell_width( self ): return self .__width r1 = Room( '卫生间' , 'zhangsan' , 100 , 100 , 10000 ) area = r1.tell_arer() print (area) |
面向对象概念总结
面向对象是一种更高级的结构化编程方式,它的好处就两点
1,通过封装明确了内外
2,通过继承+多态在语言层面支持了归一化设计
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!