一、面向对象和面向过程
各位,我们现在如果要将大象放冰箱,用面向过程怎么实现呢?
1.把大象放到冰箱里
第一步:把冰箱门打开
第二步:把大象放进去
第三步:把门关上
def open_fridge_door(): print("Open Fridge Door") def put_into_fridge(): print("Put into Fridge") def close_fridge_door(): print("Close Fridge Door") def put_elephant_into_fridge(): open_fridge_door() put_into_fridge() close_fridge_door()
但是这里存在什么问题呢?这样给使用者使用起来的时候就方便很多了,使用者只需要拿到最外层函数就可以调用了,但是现在写的代码有个问题,就是可重用性不高,比如我现在想把猪和egon都放到冰箱里,那怎么整呢?
def open_fridge_door(): print("Open Fridge Door") def put_into_fridge(): print("Put into Fridge") def close_fridge_door(): print("Close Fridge Door") def put_pig_fridge(): print("Put Pig Fridge") def put_elephant_into_fridge(func): open_fridge_door() func() close_fridge_door() put_elephant_into_fridge(put_pig_fridge)
这样就函数做为一个函数的参数传递进去(高阶函数),这时候就可以传哪个函数,我们就可以在里面执行哪个函数了!而且这样开门和关门也就得到了代码重用!
但是现在又有个问题,比如大象有年龄和体重,首先我们想这个年龄或者体重应该是作为局部变量还是函数的参数以及还是全局变量呢?这里其实很明显,只能是全局变量,局部变量和参数的改动都不会在函数之外得到维持,而且局部变量和参数在函数之外都是不可以改动的,所以只能是全局变量!但是这里局部变量又有个什么问题呢?就是一个字段的时候貌似没问题,只需要在用到的时候global 一下,如果是多个字段呢?难道要用多个global 么,这肯定是不行的,所以要将这些字段定义在一个全局变量字典中,但是这里又有一个问题,就是一个事物【猪】的有多个字段,但是如果有多个事物【牛、狗、马】都有年龄,姓名等字段如果都放到这个字典里,势必这个字段的数据太大【网络消耗多】,再一个就是数据不安全,比如猪的数据有可能就会在狗的方法中给改了!所以我们又改进了,将猪的数据放在一个函数中的一个字典的某些字段和将操作猪数据的方法也放在这个函数中,然后将这个内部方法也加入到字典中,最后只需要返回这个字典就OK!
如下代码所示:
def put_into_fridge(): dict={"name":"张三","age":12} def change_age(): dict["age"] = 13 dict.update({"change_age":change_age}) return dict
讲到这里实际上我们看着这貌似是用面向过程的方式实现的,但是面向函数基本上没有这么用的,因为面向函数一般就是函数的定义和调用,在函数调用的时候一般都是直接执行功能,而不是这么将数据和功能都返回给我们,然后我们再去取数据!
最后再给大家梳理一下我们的思路:函数代码封装--》函数可重用--》全局变量--》全局字典--》数据封装到函数中【这本身就是面向对象的思想了,变变样子就OK拉】!
这个如果是换成面向对象的思想就可以采用如下方式:
class Fridge: def open_fridge_door(self): print("Open Fridge Door") def close_fridge_door(self): print("Close Fridge Door") class Elephant: name="张三" age=12 def change_age(self): dict["age"] = 13
1.什么是面向过程和面向对象?
面向过程编程:
Procedural programming uses a list of instructions to tell the computer what to do step-by-step. 面向过程编程依赖 - 你猜到了- procedures,一个procedure包含一组要被进行计算的步骤, 面向过程又被称为top-down languages,就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 。基本设计思路就是程序一开始是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。
说白了,面向过程就是面向函数,面向函数注重的是问题的解决步骤,忽视了数据,对全局变量的维护极其不方便,而且面向过程符合计算机的认知规律,适合小型软件的开发!
面向对象编程:数据和对数据的操作是绑定在一起的,是更高级的语言,面向对象符合人的认知规律(要找谁干什么)!适合大中型软件的开发,当下的主流编程思想,易拓展,灵活易维护!
Object Oriented object:
1.OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,可以大大提高程序开发效率
2.另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
2.两者的共同点及区别?
共同点:面向过程和面向对象都是一种编程思想,没有谁好谁不好!
区别:
1.面向过程符合计算机的认知规律,面向对象符合人的认知规律。
2.面向过程是人注重的功能的实现,忽略了数据本身,面向对象将数据和功能封装在了一起
3.面向过程符合小型软件的开发【操作系统内核】效率高,面向对象适合大中型软件的开发【Windows操作系统】!
二、类的定义
各位我们先提到一个字“类”,你们心中有类的概念没?你们以前是不是早就学过这样的概念:自然界都可以划分为:植物类,动物类,动物类又分为:爬行类,鸟类,鱼类,人类。你们是怎么划分这些类的呢?是不是鸟类有翅膀,会飞,鱼类有鱼鳃,会在水里游泳,爬行类有腿,会爬行,人类会使用工具啊,简而言之,就是具有相同功能和属性的事物的统称我们称之为类,但是注意了,这里的类只是描述的共性的东西,是个宽泛的东西,是个概念,不是具体的某个个体,比如:张三、李四、王五 都有胳膊有腿,有鼻子有眼,但是类仅仅是描述这些共性的东西,并不能具体的描述这个人是张三,那个人是李四!你们知道人是怎么来的么?人是不是女娲造的啊,女娲造人吗,那女娲是一个一个捏的么?是不是女娲用模子将一团泥啪的一声拍在上面,创建了一个人啊,创建了张三,李四、王五,但是注意啦,这个模子实际上创建的是人都有的东西,比如都有胳膊有腿,有鼻子有眼,但是说你能区分开这个人是李四,那个人是王五么,不能对不对,如果要区分开,是不是要给每个个体【对象】贴上标签啊,这个标签就记录了是张三还是李四,【当然贴标签可以在创建的时候贴,也可以在创建出来再贴】,编程语言就是现实世界的反映,在python中也有类的概念,而且就是现实世界的映射,也有动物类,植物类,动物类又有鱼类,爬行类,鸟类,人类,然后人类也是描述所有人都共有的东西,有胳膊有眼,有腿,如果你要区分开,是不是要给这个人起个名字,实际上我要告诉大家的是python中的类就相当于我们女娲造人的模子,而张三李四,王五其实就是模子造出来的东西,而给这些人区分开,就要给这些人贴标签【起名字】,当然这个起名字实际上是在开始造的时候就起好就OK了【创建对象的同时传递参数】,所以我们在python中也是这样划分的,将一类具有相同属性和功能的事物划分为一类【类是一类事物的统称,具体的讲是一类具有相同属性和方法的事物的统称】,我们在python中定义类的时候是用class来完成的,来,带着大家看一下:[上代码:人]
1.类(Class)定义:
一个类即是对一类拥有相同属性的对象的蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、公共的方法
目的:提高程序设计能力,加快程序开发,便于程序的后期维护!
举例:月饼 和 房子的制造【模具、图纸就相当于类,月饼和房子就是对象】
总结:类的本质:模板【一类事物的统称】!
2.如何定义一个类?
1)具体定义类:将一类事物的共同属性("这类事物本身“有”什么?")和共同方法(“这类事物能“干”什么?”)
2)界定类: 往下---》找名词(类名词,不是具体的个体名词),往上--》更高层次的抽象类(最顶层是object类,妹的这个类名首字母小写的)
面向函数:每个函数对应一个功能,而面向对象,每个对象都是这一类事物都能解决的问题,是一类事物好多功能的集合!
类名的规范:
1.见名知意
2.首字母大写,驼峰式命名
3.符合标识符的定义
1)第一个字符必须是字母表中字母或下划线'_'。
2)标识符的其他的部分有字母、数字和下划线组成。
3)标识符对大小写敏感。
class Person: age = 0 country = "CN" def talk(self): print("Person talk") def walk(self): print("Person walk") person = Person() person.talk() person.walk() print(person.age) print(person.country)
上面我们举出的例子时人,也就是说定义一个类,就往里面添加属性【这类事物“有什么”】和方法【这类事物“能干什么”】,那有的同学说老师,你为什么定义的是人而不是男人啊,当然我们说定义类用男人也是可以的,毕竟这也是一类事物的统称,你还可以定义男人、女人、李宇春【金星】都没问题,这里开玩笑的啊,李宇春肯定是不行的,这是一个具体的对象,不是一类事物的统称对吧?当然我们这里除了人的定义我们再举几个例子,比如我们刚才讲到的把大象放进冰箱,这里也可以定义成类:
class Elepant: def go_to_fridge(self): print("Elepant go to fridge") class Fridge: def open(self): print("Fridge open the door") def close(self): print("Fridge close the door") elepant = Elepant() fridge = Fridge()
这里我们补充一个方法:__init__():类初始化对象的时候实际上是调用的这个方法【可验证】,这个方法即使我们自己在定义类的时候不写出来,实际上它默认也是存在的,只不过它什么都没干。如下所示:
class Car: color = "Red" def __init__(self): pass def start(self): print("car started............") def stop(self): print("car stopped===========") def turn_left(self): print("car turned left ************")
实际上我们通过看python中自带的类源码,通过导入threading模块可以查看到Thread类它的属性【这类事物“有什么”】都是放在__init__()中的!
from threading import Thread
从上面源码可以看出,我们前面讲的东西是有一点点问题的,所以以后大家再定义类的时候,都把属性放到__init__方法中,如下所示:
class Person: def __init__(self,name,age,country="CN",*args,**kwargs):#注意:**kwargs必须在*args后面 self.name = name self.age = age self.country = country print(country) print(args) #在这里面操作的是args哦,也就是指向元组、列表的地址 print(kwargs) #在这里面操作的是args哦,也就是指向字典的地址 st="打发" tuple1=("哈哈","嘿嘿") list1= [1,2,3,4,5] dict1={"address":"山东"} person = Person("张三",12,"USA",*st,**dict1) print(person.name)
再来一个正规的:
class Car: def __init__(self,brand,color,weight): self.brand = brand self.color = color self.weight = weight def start(self): print("car started............") def stop(self): print("car stopped===========") def turn_left(self): print("car turned left ************") def turn_right(self): print("the car turn right")
当然有的同学还是有点模糊,模糊的是不是不知道如何定义一个类,而是定义一个类之后属性该有哪些,方法该有哪些,这时候我要告诉同学们的是,你们的模糊是很正常的,你们之所以模糊是因为你们的需求不明确,看下面的项目中公司的实际需求:
类定义的补充:
1.一个类中只能有一个同名的方法
2.类中的普通函数第一个参数是self,这个参数不可以省略,且只能位于参数的第一个位置,代表的是实例本身,不是类本身,self名字可以换,但是根据大家约定的习惯,这里不要动!
3.类的实例化,体现面向对象编程的思想!
4.类是一类事物的统称,这个类到底什么类取决于你的认知和项目的需求分析,没有固定的形式,即:属性、方法可加可减,如上例子:我们可以不是设置Car,我们可以设置BMW,
也可以不定义Person类,而是定Man,或者Women!
5.类中方法的补充:
__init__:构造方法,初始化方法
__doc__:注释文档
应用案例:
练习一:
你现在是一家游戏公司的开发人员,现在需要你开发一款叫做<人狗大战>的游戏,你就思考呀,人狗作战,那至少需要2个角色,一个是人, 一个是狗,且人和狗都有不同的技能,比如人拿棍打狗, 狗可以咬人,怎么描述这种不同的角色和他们的功能呢?【要求:同学们自己找出这个需求应该有几个类,每个类中的属性和方法都是什么,都怎么定义?】
练习二:在终端输出如下信息
- 小明,10岁,男,上山去砍柴
- 小明,10岁,男,开车去东北
- 小明,10岁,男,最爱大保健
- 老李,90岁,男,上山去砍柴
- 老李,90岁,男,开车去东北
- 老李,90岁,男,最爱大保健
- 老张...
def kanchai(name, age, gender): print "%s,%s岁,%s,上山去砍柴" %(name, age, gender) def qudongbei(name, age, gender): print "%s,%s岁,%s,开车去东北" %(name, age, gender) def dabaojian(name, age, gender): print "%s,%s岁,%s,最爱大保健" %(name, age, gender) kanchai('小明', 10, '男') qudongbei('小明', 10, '男') dabaojian('小明', 10, '男') kanchai('老李', 90, '男') qudongbei('老李', 90, '男') dabaojian('老李', 90, '男')
class Foo: def __init__(self, name, age ,gender): self.name = name self.age = age self.gender = gender def kanchai(self): print "%s,%s岁,%s,上山去砍柴" %(self.name, self.age, self.gender) def qudongbei(self): print "%s,%s岁,%s,开车去东北" %(self.name, self.age, self.gender) def dabaojian(self): print "%s,%s岁,%s,最爱大保健" %(self.name, self.age, self.gender) xiaoming = Foo('小明', 10, '男') xiaoming.kanchai() xiaoming.qudongbei() xiaoming.dabaojian() laoli = Foo('老李', 90, '男') laoli.kanchai() laoli.qudongbei() laoli.dabaojian()
上述对比可以看出,如果使用函数式编程,需要在每次执行函数时传入相同的参数,如果参数多的话,又需要粘贴复制了... ;而对于面向对象只需要在创建对象时,将所有需要的参数封装到当前对象中,之后再次使用时,通过self间接去当前对象中取值即可。
练习三:看图定义类:
练习四:游戏人生程序
1、创建三个游戏人物,分别是:
- 苍井井,女,18,初始战斗力1000
- 东尼木木,男,20,初始战斗力1800
- 波多多,女,19,初始战斗力2500
2、游戏场景,分别:
- 草丛战斗,消耗200战斗力
- 自我修炼,增长100战斗力
- 多人游戏,消耗500战斗力
# -*- coding:utf-8 -*- # ##################### 定义实现功能的类 ##################### class Person: def __init__(self, na, gen, age, fig): self.name = na self.gender = gen self.age = age self.fight =fig def grassland(self): """注释:草丛战斗,消耗200战斗力""" self.fight = self.fight - 200 def practice(self): """注释:自我修炼,增长100战斗力""" self.fight = self.fight + 200 def incest(self): """注释:多人游戏,消耗500战斗力""" self.fight = self.fight - 500 def detail(self): """注释:当前对象的详细情况""" temp = "姓名:%s ; 性别:%s ; 年龄:%s ; 战斗力:%s" % (self.name, self.gender, self.age, self.fight) print temp # ##################### 开始游戏 ##################### cang = Person('苍井井', '女', 18, 1000) # 创建苍井井角色 dong = Person('东尼木木', '男', 20, 1800) # 创建东尼木木角色 bo = Person('波多多', '女', 19, 2500) # 创建波多多角色 cang.incest() #苍井空参加一次多人游戏 dong.practice()#东尼木木自我修炼了一次 bo.grassland() #波多多参加一次草丛战斗 #输出当前所有人的详细情况 cang.detail() dong.detail() bo.detail() cang.incest() #苍井空又参加一次多人游戏 dong.incest() #东尼木木也参加了一个多人游戏 bo.practice() #波多多自我修炼了一次 #输出当前所有人的详细情况 cang.detail() dong.detail() bo.detail()
3.类的实例化
class Elephant: name="hah" def go_to_fridge(self,name): self.name = name print(self.name) print(name) print(Elephant.name) print("Elephant go to Fridge! %s" %name) elephant = Elephant() print(id(Elephant.name)) print(id(elephant.name)) print(id(Elephant.go_to_fridge)) print(id(elephant.go_to_fridge)) elephant.go_to_fridge("小象")
注意:对象实例化之后我们就可以通过对象来调用方法和属性啦!
类实例化过程图解:
在这里要给同学们讲清楚几个概念:
实例化:类创建对象的过程叫实例化
对象:类实例化的结果是对象
类
1.变量:
类变量、类的私有变量----》实例变量、实例私有变量----》参数
针对上面的变量或者参数,在类内类外的访问方法!
class Car: price = 1000 __length = 2 def __init__(self,brand,color,weight,price): self.price = price self.brand = brand self.color = color self.weight = weight self.__age = 15 print("类变量:",Car.price) #类变量的访问方式 print("类私有变量:",Car.__length) #类私有变量的类内访问方式 print("实例变量:",self.price) #实例变量的访问方式 print("实例私有变量:",self.__age) print("参数:",price) #参数的访问方式 def start(self): print("car started............") print("类私有变量:",Car.__length) print("类变量:",Car.price) print("实例变量:",self.price) # 类变量和类私有变量、实例变量、实例私有变量是可以在类内直接这样访问的 def stop(self): print("car stopped===========") car = Car("奔驰","Red",1000,50000) car.start()
注意:1.可以通过dir(类名)的方式查看里面所有的属性和所有方法
2.类的私有变量在类内类外的访问方式是不同的!
2.方法
类方法,类的私有方法
class Car: price = 1000 __length = 2 def __init__(self,brand,color,weight,price): self.price = price self.brand = brand self.color = color self.weight = weight self.__age = 15 print("类变量:",Car.price) #类变量的访问方式 print("类私有变量:",Car.__length) #类私有变量的类内访问方式 print("实例变量:",self.price) #实例变量的访问方式 print("实例私有变量:",self.__age) print("参数:",price) #参数的访问方式 def start(self): print("car started............") print("类私有变量:",Car.__length) print("类变量:",Car.price) print("实例变量:",self.price) # 类变量和类私有变量、实例变量、实例私有变量是可以在类内直接这样访问的 def stop(self): Car.__turn_left(self) print("car stopped===========") def __turn_left(self): print("Car turn left") car = Car("奔驰","Red",1000,50000) print(dir(Car)) Car._Car__turn_left(car) car.stop()
注意:类的私有方法在类内和类外的访问方式是不同的!
综上:
注意:类和实例调用方法区别在于:类名.方法名(参数)必须自己给self传值,而 实例.方法名(参数)则不用!
再看代码:
class Person: __hi = "ad" country="China" def __init__(self,name,age,gender): self.name = name self.age = age self.__gender = gender def talk(self): print("Person talk") def walk(self): print("Person walk") def get_gender(self): #实例的私有属性在外界是不能够直接访问的,要想访问实例的私有属性要在类中提供方法,供外界调用! return self.__gender def set_gender(self,gender): if gender == "男" or gender == "女": self.__gender = gender print(self.__gender) # 会被python解释器生成_类名__方法名,如果真想在外界调用就直接调用这个,到底被编译为什么可以通过类.__dict__调用,要记得给self传值! def __hello(self): #在外界访问的时候,可以通过类名._类名__hello(obj)以及 实例._类名__hello()的方式调用 print("say Hello") person = Person("张三",23,"男") person.talk() person.set_gender("女") #在类的外面,我们是不能通过实例直接调用实例的私有变量的,私有方法也调用不了,注意:以__开头的变量或者方法为私有变量或者私有方法 print(person.__dict__) #可以查看实例变量及值 print(Person.__dict__) #可以查看类中的类变量和类方法 person._Person__hello() #通过对象调用类的私有方法 Person._Person__hello(person) #通过类调用类的私有方法 print(person._Person__hi) #通过实例调用类的私有属性,也就是说私有属性也可以被对象拷贝一份 print(Person._Person__hi) #通过类调用类的私有属性
4.类中代码执行顺序
各位,你们先告诉我下面这段代码的执行顺序是什么?
print("A.......") def func(): print("B..........") print(func) #print(func())呢?
类中代码执行顺序:
1.在使用到类[创建对象或者使用类]的时候先加载类文件到内存
2.然后按着如下顺序执行类中代码:
1)执行方法之外的代码 ----------> 2).构造器中的代码(__init__)--------------->3.类或对象调用的方法---------->4.析构方法(__del__)
python中的特殊方法,其中两个,构造函数和析构函数的作用:
“__init__”:构造函数,具有初始化的作用,也就是当该类被实例化的时候就会执行该函数。那么我们就可以把要先初始化的属性放到这个函数里面。
“__del__”:析构函数,当使用del 删除对象时,会调用他本身的析构函数,另外在虚拟机进行垃圾回收的时候,不会再使用的对象也会调用一次析构方法,这样可以用来释放内存空间。
三、面向对象的三大特征
1.回顾及概述:
面向对象编程:OOP Object Oriented Programming:
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量(成员变量):类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。 类变量作为默认共有属性,全局修改或者增加类的新属性。
- 实例变量:通过类实例或者类中self.的形式定义的变量,只作用于当前实例,每个实例独有的属性,
- 私有变量 :私有变量分为:类的私有变量和实例的私有变量;不想被的实例访问的属性和隐藏一些实现细节的功能,只是对外提供功能接口使用!
- 函数参数
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法:类中定义的函数,功能的体现。类中的方法不可以重名,否则会覆盖!
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 实例化:创建一个类的实例,类的具体对象。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法
概述:
- 封装【Encapsulation】:封装是面向对象的特征之一。封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
- 继承【Inheritance】:即一个派生类(derived class)【子类】继承基类(base class),【父类、超类】的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。继承分为:单继承,多重继承,多级继承;例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。继承的目的:实现代码重用
- 多态【Polymorphism】:父类的引用指向子类的对象,在python中,多态要依赖于继承!【对于开发者:制定开发标准,对于使用者:使用方便】多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,多态的典型使用:父类的引用指向子类的对象实例!例如:水:液态,固态,气态。人:父亲,丈夫,儿子,同事
2.封装
定义:封装,顾名思义,就是将某些内容封装到某个地方, 其实类本身就体现了封装【封装了数据和方法】
目的:1.对外隐藏数据
2.将数据和功能打包封装,调用者只需要拿到对象即可操作该对象中的数据和功能 !
class Person: country="China" def __init__(self,name,age): self.name= name self.age = age def talk(self): print("Person Talk") def walk(self): print("Person Walk") person = Person("张安",2) person.walk()
这里体现了封装:
1.类本身就是对象,封装了数据和方法
2.实例化对象的时候也体现了封装
3.方法也体现了封装(对外界透明,外界不需要知道里面具体是怎么实现的)
从上面我们可以看成,实际上类、方法也是特殊的对象【类是type的对象,函数本身就是特殊的对象、模块也可看成是个对象】
class Person: country="China" def __init__(self,name,age): self.name= name self.age = age def talk(self): print("Person Talk") def walk(self): print("Person Walk") person = Person("张安",2) person.walk() print(type(person)) print(type(Person)) print(isinstance(person,Person)) # 既然有了type()来判断类型,为什么还有isinstance()呢? # 一个明显的区别是在判断子类。 # type()不会认为子类是一种父类类型。 # isinstance()会认为子类是一种父类类型。
3.继承
目的:通过代码的继承机制,实现了代码的重用
语法:需要注意的地方,继承语法: class 派生类(基类): //...基类名写在括号里,基本类是在类定义的时候,在元组之中指明的。
特点:
1.到底从父类继承了什么?继承了父类的类变量,类私有变量,类方法、类的私有方法【代码说明】
class Parent: name = "张三" __age = 15 def get_gender(self,gender): self.gender= gender def eat(self,obj): print("Eat so",obj) def __walk(self,something): #给私有方法打了标签 _Parent__walk(self,something) print("self==============>",something) class Son(Parent): pass son = Son() print(son.name) #继承了类变量 print(Son._Parent__age) #继承了类的私有属性 print(son.eat("把菜")) #继承了类的方法 print(son._Parent__walk("好吧")) #继承了类的私有方法 print(son.__dict__) #可以看出这里只是类中的变量、私有变量、被继承了 print(Parent.__dict__) #打印当前类的变量、私有变量、方法、私有方法、但是不包含继承的!
2.如果要在子类中调用父类中的方法可以通过父类.的方式直接调用或者super().的方式调用【区别在于:super().方式调用的时候不用传递对象】
3.继承之后也可以重写【覆写】父类【基类、超类】中的方法和变量,当然也可以通过添加自己所特有的属性和方法。
4.Python总是首先查找对应类型的方法,先在本类中查找调用的方法,找不到采取基类中找。如果在继承元组中列了一个以上的类,那么它就被称作“多重继承”【多继承】,注意:区别多继承和多级继承的概念!
5.多继承时的查找顺序:Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先【Python 2.x】和广度优先【Python 3.x】。
代码演示【给学生画图演示】:
class D: def sayhello(self): print(" D Hello...........") class B(D): def sayhello(self): print(" B Hello...........") class C(D): def sayhello(self): print(" C Hello...........") class A(B,C): def sayhello(self): print(" A Hello...........") a = A() a.sayhello()
注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)!print(A.__mro__) #python2中没有这个属性
继承的父类的查看:子类名.__bases__ eg:print(People.__bases__)
4.多态:
定义:多态指的是一类事物的多种形态!
例子:水:固态、液态、气态 你:丈夫、儿子、老公、同事 这种都是多态的体现!
在代码中的体现:父类的引用指向子类的实例对象【因而多态依赖于继承】
java代码演示:
1 public interface School { 2 public void work(); 3 } 4 5 public class Teacher implements School{ 6 public void work() { 7 System.out.println("老师要上课!!!!!!!!!"); 8 } 9 } 10 11 12 class Student implements School{ 13 public void work() { 14 System.out.println("学生要上课学习"); 15 } 16 }
实际上Python中是没有多态的,因为它对类型的不检查导致了你实际上就是传递了一个对象进去,然后直接调用这个对象的方法,这不算多态!虽然Python中没有多态,但是我们在Python中可以用抽象类大体模拟出多态的效果!
5.抽象类:
定义:如果说类是从一堆对象中抽取出相同的内容来,那么抽象类就是从一堆类中抽取出相同的内容来,内容包括数据属性和函数属性,但是通常我们只是将函数属性抽取出来放到抽象类中,在抽象类中的方法不做实现,留给子类实现,这样可以达到归一化设计程序的目的!
什么是归一化设计?
说白了,抽象类(归一化设计)主要是让大家统一编程规范,接口名称不是自己说了算,而是由大Boss说了算!
归一化设计的使用场景:
公司的项目经理或者架构师:设计好了抽象类,你只要实现这个抽象类中的方法即可,这样就避免了每个人都按照自己的方式给方法起名字,有利于规范代码!
注:抽象类是特殊的类,只能被继承,不能被实例化,metaclass=abc.ABCMeta和装饰器@abc.abstractmethod同时标记才起作用,只标记一个不起作用!
import abc class AllFile(metaclass=abc.ABCMeta): adb="aa" @abc.abstractmethod def func1(self): print("哈哈") @abc.abstractmethod def func2(self): pass class Text(AllFile): def func1(self): print("the first function") def func2(self): print("the second function") f = Text() print(f.adb) f.func1() f.func2()
import abc class AllFile(metaclass=abc.ABCMeta): adb="aa" @abc.abstractmethod def func1(self): print("哈哈") @abc.abstractmethod def func2(self): pass class Text(AllFile): def func1(self): print("the first function") def func2(self): print("the second function") def function(obj): obj.func1() text = Text() function(text)
6.对象之间的关系
对象之间常用的两种关系:
1.依赖关系(交互,不再是孤立的个体):通过给类的方法传递参数的形式!
2.组合:组合关系即:包含的关系(整体与局部的关系),一个对象作为另一个类的一个属性存在。
eg:Person--》年龄
这两者的区别:
组合的关系实际上就是类整体的一个属性,只不过这部分又可以被拆分成多个属性,又形成的一个类,组合的方式适合对象与对象之间的"包含"的关系,说白了!
依赖关系不是作为一个对象的属性存在,这个对象与依赖的对象仅仅是使用的关系
总之:当上面两种关系有点模糊,或者你也分不清到底是组合还是依赖关系的时候,你就看看你创建的这个类中有没有那个对象作为成员变量,如果没有,则说明是依赖关系,如果有,那么就按照组合关系!如果代码是需要自己设计,那就要根据自己的需求设计了,如果确实需要这个字段作为属性,那就作为组合关系。如果不需要作为属性,那么就按依赖关系处理也可以!例如:学生和课程等!
class Car: def run(self): print("/汽车在奔跑") class Driver: def drive(self,car): car.run() driver = Driver() car = Car() driver.drive(car)
class Person: def __init__(self,birthday): print("birthday ",birthday) class Birthday: def __init__(self,year,month,day): self.year = year self.month = month self.day = day def __str__(self): return "year:%s month:%s day:%s"%(self.year,self.month,self.day) birthday = Birthday(1992,12,12) person = Person(birthday)
补充:__str__方法的知识