第一:程序设计思想与发展历程(了解)
1940年以前:面向机器编程
最早的是采用机器语言编程,也就是直接使用二进制码来表示机器能够识别的指令和数据。
优点:机器语言由机器直接执行,速度快
缺点:写起来非常困难,并且不容易修改
汇编语言:用助记符号代替机器指令的操作码,用地址符号或者标号代替指令或操作数的地址
优点:比机器语言的二进制码编写方便些
缺点:汇编语言本质上还是一种面向机器的语言,编写困难,易出错
脱离机器后:面向过程编程
面向过程的结构化程序设计强调功能的抽象和程序的模块化, 它将解决问题的过程看作是一个处理过程,如c语言
优点:对底层的硬件,内存,cpu等操作比较方便
缺点:不易扩展,写代码,调试比较麻烦
第一次软件危机:结构化程序设计
采取“自顶向下、逐步细化、模块化”的指导思想。结构化程序设计本质上还是一种面向过程的设计思想,但通过“自顶向下、逐步细化、模块化”的方法,将软 件的复杂度控制在一定范围内,从而从整体上降低了软件开发的复杂度
1960年爆发,背景:由于软件质量低下,项目无法如期完成、项目严重超支,因为软件而导致的重大事故经常发生,主要体现在复杂性上
1968年第一个结构化程序语言Pascal诞生
1970年成为软件开发的主流
第二次软件危机:面向对象程序设计
根本原因:软件生产力远远跟不上硬件和业务的发展。
主要体现在‘可扩展性’与‘可维护性’上
早在1967年的Simula语言就提出面向对象,第二次危机促进了面向对象的发展
1980s年代,得益于C++,以及后来java,C#把面向对象推向了高峰,现在已经成为主流开发思想
第二:什么是面向对象程序设计
首先在这说一下什么是面向过程设计:
面向过程的程序设计的核心是过程,过程即解决问题的步骤。面向过程可理解成一条流水线
优点是:极大的降低了程序的复杂度
缺点是:一套流水线或者流程就是用来解决一个问题,如果是生产面包的流水线不可能生产包子,即便是能,也得是大改,改一个组件,牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象设计:
面向对象的程序设计的核心是对象,对象可理解成特征,属性等
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是神也无法预测最终结果。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方
第三:类和对象
面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
类:数据与函数的结合,二者称为类的属性
类:
类的定义:
class Garen: #定义英雄盖伦的类,不同的玩家可以用它实例出自己英雄; camp=‘Demacia‘ #所有玩家的英雄(盖伦)的阵营都是Demacia; def __init__(self,nickname,aggresivity,life_value): #盖伦英雄的名字,攻击力,生命值 self.nickname=nickname #别名 self.aggrv=aggresivity #攻击力 self.life_value=life_value #生命值
类的两种作用:实例化和属性引用
#!/usr/bin/env python #-*-coding:utf-8-*- class Garen: camp=‘Demacia‘ def __init__(self,nickname,aggresivity,life_value): self.nickname=nickname self.aggrv=aggresivity self.life_value=life_value def attack(self,enemy): #攻击技能,enemy是敌人 print(‘is attacking‘,self,enemy) #类的功能一:实例化(__init__与self)类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征 g1=Garen(‘草丛伦‘,80,120) #Garen.__init__(g1,‘草丛伦‘,80,120) #g1=self,nickname=‘草丛伦‘,aggresivity=80,life_value=120
#实例调用g1.attack(3) #Garen.attack(g1,‘a‘)#输出结果:#is attacking <__main__.Garen object at 0x0000000002679C50> 3
#类功能二:属性引用(类名.属性),包括数据属性和函数属性 #数据属性: print(Garen.camp) #输出结果:Demacia # #函数属性: print(Garen.__init__) print(Garen.attack) #输出结果: #<function Garen.__init__ at 0x000000000252B840> #<function Garen.attack at 0x000000000252B8C8>
类的属性的补充:
一:我们定义的类的属性到底存到哪里了?有两种方式查看 dir(类名):查出的是一个名字列表 类名.__dict__:查出的是一个字典,key为属性名,value为属性值 二:特殊的类属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中)
对象:
单独说一下对象,借助上一个例子
g1=Garen(‘草丛伦‘) #类实例化得到g1这个实例,基于该实例看下对象
实例/对象只有一个属性:
#对于一个实例来说,只有一个功能:属性引用,实例本身只拥有数据属性 print(g1.nickname) print(g1.aggrv) print(g1.life_value) 输出结果: 草丛伦 80 120
对象补充:
查看实例属性 同样是dir和内置__dict__两种方式 特殊实例属性 __class__ __dict__
对象/实例本身只有数据属性,但是python的class机制会将类的函数绑定到对象上,称为对象的方法,或者叫绑定方法
#实例可以调用类的数据属性和函数属性 print(g1.camp) print(g1.attack) #对象的绑定方法
#输出结果:# Demacia # <bound method Garen.attack of <__main__.Garen object at 0x0000000002269CC0>>
#类的调用: 相当于函数 Garen.attack(1,2) # 输出结果: # is attacking 1 2
对象之间的交互:
class Garen: camp=‘Demacia‘ def __init__(self,nickname,aggresivity,life_value): self.nickname=nickname self.aggrv=aggresivity self.life_value=life_value def attack(self,enemy): print(‘is attacking‘,self,enemy) class Riven: camp=‘Noxus‘ def __init__(self,nickname,aggresivity,life_value): self.nickname=nickname self.aggrv=aggresivity self.life_value=life_value def attack(self,enemy): print(‘is attacking‘,self,enemy) enemy.life_value-=self.aggrv #g1.life_value-=r1.aggrv 根据盖伦的攻击力干掉瑞文的生命值 g1=Garen(‘草丛伦‘,80,100) r1=Riven(‘瑞文‘,60,200) print(g1.life_value) r1.attack(g1) print(g1.life_value) 输出结果: 100 is attacking <__main__.Riven object at 0x00000000021A9E10> <__main__.Garen object at 0x00000000021A9DD8> 40
类的名称空间:
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
类有两种属性:数据属性和函数属性
其中类的数据属性是共享给所有对象的
print(id(g1.camp)) print(id(Garen.camp)) 输出结果: 34575448 34575448
而类的函数属性是绑定到所有对象的:
print(id(g1.attack)) print(id(Garen.attack)) 输出结果: 31839048 40155336
总结:创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
在Garen里面找camp,会先从__init__中找,camp,如果没有会在类中去找,如果还没有的话,就到父类中去找,一直把所有的父类都找完,还没有的话,就会抛出异常。