面向对象(初级)
一、面向对象相关定义:
一、面向过程:面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。
优点:极大地降低了写成学的复杂度,只需要顺着执行的步骤,堆叠代码即可
缺点:一套流水线或者流程就是用来解决一个问题,如果修改代码就都得改变
二、面向对象:上帝的思想
优点:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法 预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
三、类:是具有相同特征的一类事物(人,狗,老虎)
对象/实例:具体的某一事物
实例化:类到对象的过程(实例=类名(参数1,参数2))
四、初始类和对象
类的定义:class Person: #class 类名:注意类名后面不要括号
类体
在python中,用变量表示特征,用函数表示技能,因而具有相同的特征和技能的一类事物就是‘类’,对象 则是这一类事物中具体的一个
class foo: #创建一个类 def a(self): #创建一个类方法 print('A') def b(self): #创建另一个类方法 print('B') p = foo() #创建一个对象 p.a() #调用一个对象
面向对象名词定义:
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 实例变量:定义在方法中的变量,只作用于当前实例的类。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型 的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
二、面向对象三大特性
1、封装
self:在实例化时自动将对象/实例本身传给__init__的第一个参数,你也可以给它起个别的名字,但是一般正常人都不会这么做,因为你改了别人就不认识了。
注意:def __init__(self): 这句话可以写也可以不写,只要有参数参进来的时候就必须得写
def 方法名(self):这里的self必须得写
封装:顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:
- 将内容封装到某处
- 从某处调用被封装的内容
第一步:将内容封装到某处
class foo: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def fun(self): print(self.name,self.age,self.gender) p = foo('yang',18,'男') p.fun() #yang 18 男
第二步:从某处调用被封装的内容
调用被封装的内容时,有两种情况:
- 通过对象直接调用
- 通过self间接调用
# class foo: # def __init__(self,name,age): # self.name = name # self.age =age # def fun(self): # print(self.name,self.age) # # obj1 = foo('Yang',19) # print(obj1) #<__main__.foo object at 0x0000026B0B2F6E48> # print(obj1.name) #Yang # print(obj1.age) #19 # obj2 = foo('Xin',23) # print(obj2) #<__main__.foo object at 0x0000026B0B2F6EB8> # print(obj2.name) #Xin # print(obj2.age) # 23 # print('***********************') # obj2.fun() # Python默认会将obj2传给self参数,即:obj2.fun(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 xin ; self.age 是 23
# 结果:Xin 23 调用了哪个对象,就传该对象的参数
综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
2、继承
继承:面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
格式:class A(B):A继承B
class foo1: def a(self): print('A') def b(self): print('B') def c(self): print('C') class foo2(foo1): def c(self): print('C') p = foo2() p.a() #A
重写
- 目的:防止调用父类
- self永远执行方法的调用者
- self(子类,self).父类中的方法(....) 父类名.父类中的方法(self,....)
class foo: def A(self): print('A') def B(self): print('B') class foo1(foo): def A(self): print('C') super(foo1,self).A() # ******同时调用父类的A方法 #foo.A(self) # ****** def B(self): print('D') p = foo1() p.A() 结果:C A
子类方法重写 # class foo1: # def a(self): # print('A') # def b(self): # print('B') # def c(self): # print('C') # # class foo2(foo1): # def c(self): # print('C2') #重写 # p = foo2() # p.c() # C2 本身对象中有该调用方法,不在使用父类的方法
多继承:(经典类执行顺序:1.从左到右2.一直到底3.同一个根父类,根父类最后执行)
1、Python的类可以继承多个类,Java和C#中则只能继承一个类
2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先
- 当类是经典类时,多继承情况下,会按照深度优先方式查找
- 当类是新式类时,多继承情况下,会按照广度优先方式查找
经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
class foo1(): def c(self): print('A') class foo2(foo1): def a(self): print('B') class foo3(foo1): def a(self): print('C') class foo4(foo2,foo3): def b(self): print('D') p = foo4() p.c() #foo4->foo2->foo1->foo3
class foo1(object): def c(self): print('A') class foo2(foo1): def a(self): print('B') class foo3(foo1): def a(self): print('C') class foo4(foo2, foo3): def b(self): print('D') p = foo4() p.c() #foo4->foo2->foo3->foo1
3、初级继承多个类,顺序由左到右
class foo1(): def a(self): print('A') class foo2(): def a(self): print('B') class foo3(foo1, foo2): def b(self): print('C') p = foo3() p.a() #顺序:foo3->foo1->foo2
3、多态