初识面向对象
一、面向过程 VS 面向对象
1、面向过程
核心是过程(流水线思维),过程即解决问题的步骤,即先干什么再干什么......面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式。
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
2、面向对象
核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。总之对象是特征与技能的结合体,与面向过程机械式的思维方式形成鲜明对比,面向对象更加注重对现实世界的模拟。
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。
2.1、常用名词解释
1)、类:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。
2)、对象/实例:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
3)、实例化:创建一个类的实例,类的具体对象(类—>对象的过程)。
2.2、相关补充知识
# 1.使用类中的名字 # 查看类中的名字: # 类名.变量名 # 可以修改变量的值 # 类名.__dict__['变量名'] # 不能修改 # 2.创造对象 实例化对象 # 对象就是实例,一个实际的例子 # 对象 = 类名()
一:我们定义的类的属性到底存到哪里了?有两种方式查看 dir(类名):查出的是一个名字列表 类名.__dict__:查出的是一个字典,key为属性名,value为属性值 二:特殊的类属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中)
2.3、具体实例
1)、人狗大战
#人类 class Person: role = '人' #静态变量 #初始化方法 def __init__(self,name,sex,aggr,hp): self.name = name self.sex = sex self.aggr = aggr self.hp = hp #攻击方法 def attack(self,dog): print('%s打了%s%s点血'%(self.name, dog.name,self.aggr)) dog.hp -= self.aggr #人的攻击力 #狗 class Dog: def __init__(self,name,kind,aggr,hp): self.name = name self.kind = kind self.aggr = aggr self.hp = hp #咬方法 def bite(self,person): print('%s咬了%s%s点血'%(self.name,person.name,self.aggr)) person.hp -= self.aggr #狗的攻击力 #对象实例化 xiaohei = Dog('小黑','teddy',50,1000) #创建狗的对象 alex = Person('alex','female',2,250) #创建人的对象 egon = Person('egon','male',5,300) alex.attack(xiaohei) #alex打了小黑2点血 egon.attack(xiaohei) #egon打了小黑5点血 print(xiaohei.hp) #993 xiaohei.bite(alex) #小黑咬了alex50点血 print(alex.hp) #200
2)、求圆形、长方形、正方形的周长和面积
#1、圆形 from math import pi class Circle(): #初始化方法 def __init__(self,r): self.r = r #面积 def area(self): return pi*self.r**2 #周长 def perimeter(self): return 2*pi*self.r cricle1 = Circle(5) print(cricle1.area()) #78.53981633974483 print(cricle1.perimeter()) #31.41592653589793 #2、矩形 class ChangFX(): def __init__(self,c,k): self.c = c self.k = k def area(self): return self.c * self.k def perimeter(self): return 2 * (self.c + self.k) cfx = ChangFX(8,10) print(cfx.area()) #80 print(cfx.perimeter()) #36 #3、正方形 class ZhengFX(): def __init__(self,c): self.c = c def area(self): return self.c * self.c def perimeter(self): return 4 * self.c zfx = ZhengFX(10) print(zfx.area()) #100 print(zfx.perimeter()) #40
3)、打印语句
class Person(): def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age def act1(self): print('%s,%s,%s岁,上山去砍柴'%(self.name,self.sex,self.age)) def act2(self): print('%s,%s,%s岁,开车去东北'%(self.name,self.sex,self.age)) def act3(self): print('%s,%s,%s岁,最爱大保健'%(self.name,self.sex,self.age)) xiaoming = Person("小明",'男',10) xiaoming.act1() xiaoming.act2() xiaoming.act3() laozhang = Person("老张",'男',40) laozhang.act1() laozhang.act2() laozhang.act3() laowang = Person("老王",'男',45) laowang.act1() laowang.act2() laowang.act3() #结果 小明,男,10岁,上山去砍柴 小明,男,10岁,开车去东北 小明,男,10岁,最爱大保健 老张,男,40岁,上山去砍柴 老张,男,40岁,开车去东北 老张,男,40岁,最爱大保健 老王,男,45岁,上山去砍柴 老王,男,45岁,开车去东北 老王,男,45岁,最爱大保健
二、类命名空间与对象、实例的命名空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
而类有两种属性:静态属性和动态属性
- 静态属性就是直接在类中定义的变量
- 动态属性就是定义在类中的方法
相关源码
class Person: # 定义一个人类 role = 'person' # 人的角色属性都是人 def __init__(self, name, aggressivity, life_value): self.name = name # 每一个角色都有自己的昵称; self.aggressivity = aggressivity # 每一个角色都有自己的攻击力; self.life_value = life_value # 每一个角色都有自己的生命值; def attack(self,dog): # 人可以攻击狗,这里的狗也是一个对象。 # 人攻击狗,那么狗的生命值就会根据人的攻击力而下降 dog.life_value -= self.aggressivity class Dog: # 定义一个狗类 role = 'dog' # 狗的角色属性都是狗 def __init__(self, name, breed, aggressivity, life_value): self.name = name # 每一只狗都有自己的昵称; self.breed = breed # 每一只狗都有自己的品种; self.aggressivity = aggressivity # 每一只狗都有自己的攻击力; self.life_value = life_value # 每一只狗都有自己的生命值; def bite(self,people): # 狗可以咬人,这里的狗也是一个对象。 # 狗咬人,那么人的生命值就会根据狗的攻击力而下降 people.life_value -= self.aggressivity egg = Person('egon',10,1000) #创造了一个实实在在的人egg ha2 = Dog('二愣子','哈士奇',10,1000) #创造了一只实实在在的狗ha2 print(ha2.life_value) #看看ha2的生命值 egg.attack(ha2) #egg打了ha2一下 print(ha2.life_value) #ha2掉了10点血 egon大战哈士奇
1、其中类的数据属性是共享给所有对象的
id(egg.role) #4341594072 id(Person.role) #4341594072
2、而类的动态属性是绑定到所有对象的
egg.attack #<bound method Person.attack of <__main__.Person object at 0x101285860>> Person.attack #<function Person.attack at 0x10127abf8>
示例:写一个类,能统计这个类被多少个对象实例化了.
class Foo: num = 0 #统计结果的变量 def __init__(self): Foo.num += 1 f1 = Foo() print(f1.num) #1 f2 = Foo() print(f1.num) #2
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
三、面向对象的组合用法
软件重用的重要方式除了继承之外还有另外一种方式,即:组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
求圆环的面积与周长
#圆环是由两个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是内部圆的周长加上外部圆的周长。 #这个时候,我们就首先实现一个圆形类,计算一个圆的周长和面积。然后在"环形类"中组合圆形的实例作为自己的属性来用 from math import pi #圆形 class Circle: #初始化 def __init__(self, r): self.r = r #面积 def area(self): return pi*(self.r**2) #周长 def perimeter(self): return 2*pi*self.r #圆环 class Ring: #初始化 def __init__(self,outer,inner): self.outer = Circle(outer) #大圆 self.inner = Circle(inner) #小圆 #圆环面积 def area(self): return self.outer.area() - self.inner.area() #圆环周长 def perimeter(self): return self.outer.perimeter()+self.inner.perimeter() #实例化对象 r = Ring(10,5) print(r.area()) #235.61944901923448 print(r.perimeter()) #94.24777960769379
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python课程
class BirthDate: def __init__(self,year,month,day): self.year=year self.month=month self.day=day class Couse: def __init__(self,name,price,period): self.name=name self.price=price self.period=period class Teacher: def __init__(self,name,gender,birth,course): self.name=name self.gender=gender self.birth=birth self.course=course def teach(self): print('teaching') p1=Teacher('egon','male', BirthDate('1995','1','27'), Couse('python','28000','4 months') ) print(p1.birth.year,p1.birth.month,p1.birth.day) #1995 1 27 print(p1.course.name,p1.course.price,p1.course.period) #python 28000 4 months
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好