面向对象
介绍(特性(class、object--->封装、继承,多态))、--->世界万物,皆可分类;世界万物,皆可对象
只要是对象,就肯定属于某种品类;只要是对象,就肯定有属性
你是上帝 地球---> 山川,河流,大海,森林
--->飞禽-飞,吃虫子,下蛋,(几百种鸟(布谷鸟-飞,吃虫子,下蛋,唱歌;乌鸦-飞,吃虫子,下蛋....)),走兽(狮子-百兽之王;老虎-森林之王)
臭鱼烂虾---->人-思考,说话,吃喝拉撒睡
语法(属性、方法、构造函数、析构函数(在实例释放、销毁的时候自动执行的,通常用于做一些收尾工作,如关闭一些数据库链接,关闭打开的临时文件))、; 类变量的用途?大家共用的属性,节省开销(内存)
(私有方法、私有属性)、(类变量、实例变量)
一、面向过程 VS 面向对象
编程范式
编程是 程序 员 用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程 , 一个程序是程序员为了得到一个任务结果而编写的一组指令的集合,正所谓条条大路通罗马,实现一个任务的方式有很多种不同的方式, 对这些不同的编程方式的特点进行归纳总结得出来的编程方式类别,即为编程范式。 不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路, 大多数语言只支持一种编程范式,当然也有些语言可以同时支持多种编程范式。 两种最重要的编程范式分别是面向过程编程和面向对象编程。
面向过程编程(Procedural Programming)
Procedural programming uses a list of instructions to tell the computer what to do step-by-step.
面向过程编程依赖 - 你猜到了- procedures,一个procedure包含一组要被进行计算的步骤, 面向过程又被称为top-down languages, 就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 。基本设计思路就是程序一开始是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。举个典型的面向过程的例子, 数据库备份, 分三步,连接数据库,备份数据库,测试备份文件可用性。代码如下
1 def db_conn(): 2 print("connecting db...") 3 4 5 def db_backup(dbname): 6 print("导出数据库...",dbname) 7 print("将备份文件打包,移至相应目录...") 8 9 def db_backup_test(): 10 print("将备份文件导入测试库,看导入是否成功") 11 12 13 def main(): 14 db_conn() 15 db_backup('my_db') 16 db_backup_test() 17 18 19 if __name__ == '__main__': 20 main()View Code
这样做的问题也是显而易见的,就是如果你要对程序进行修改,对你修改的那部分有依赖的各个部分你都也要跟着修改, 举个例子,如果程序开头你设置了一个变量值 为1 , 但如果其它子过程依赖这个值 为1的变量才能正常运行,那如果你改了这个变量,那这个子过程你也要修改,假如又有一个其它子程序依赖这个子过程 , 那就会发生一连串的影响,随着程序越来越大, 这种编程方式的维护难度会越来越高。
所以我们一般认为, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护 的, 那还是用面向对象最方便了。
面向对象编程
OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
面向对象的几个核心特性如下
Class 类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、相同的方法
Object 对象
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同
三大特性
Encapsulation 封装
在类中对数据的赋值、内部调用对外部用户是透明的(不可见),这使类变成了一个胶囊或容器,里面包含着类的数据和方法
Inheritance 继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承
Polymorphism 多态
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。
编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。
对不同类的对象发出相同的消息将会有不同的行为。比如,你的老板让所有员工在九点钟开始工作, 他只要在九点钟的时候说:“开始工作”即可,而不需要对销售人员说:“开始销售工作”,对技术人员说:“开始技术工作”, 因为“员工”是一个抽象的事物, 只要是员工就可以开始工作,他知道这一点就行了。至于每个员工,当然会各司其职,做各自的工作。
多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定
二、面向对象编程(Object-Oriented Programming )介绍
对于编程语言的初学者来讲,OOP不是一个很容易理解的编程方式,大家虽然都按老师讲的都知道OOP的三大特性是继承、封装、多态,并且大家也都知道了如何定义类、方法等面向对象的常用语法,但是一到真正写程序的时候,还是很多人喜欢用面向过程来写代码,特别是初学者,很容易陷入一个窘境就是“我知道面向对象,我也会写类,但我依然没发现在使用了面向对象后,对我们的程序开发效率或其它方面带来什么好处,因为我使用函数编程就可以减少重复代码并做到程序可扩展了,为啥子还用面向对象?”。 对于此,我个人觉得原因应该还是因为你没有充分了解到面向对象能带来的好处,今天我就写一篇关于面向对象的入门文章,希望能帮大家更好的理解和使用面向对象编程。
无论用什么形式来编程,我们都要明确记住以下原则:
- 写重复代码是非常不好的低级行为
- 你写的代码需要经常变更
1 # role 1
2 name = 'Alex'
3 role = 'terrorist'
4 weapon = 'AK47'
5 life_value = 100
6
7 # rolw 2
8 name2 = 'Jack'
9 role2 = 'police'
10 weapon2 = 'B22'
11 life_value2 = 100
12 #上面定义了一个恐怖份子Alex和一个警察Jack,但只2个人不好玩呀,一干就死了,没意思,那我们再分别一个恐怖分子和警察吧,
13 # role 1
14 name = 'Alex'
15 role = 'terrorist'
16 weapon = 'AK47'
17 life_value = 100
18 money = 10000
19
20 # role 2
21 name2 = 'Jack'
22 role2 = 'police'
23 weapon2 = 'B22'
24 life_value2 = 100
25 money2 = 10000
26
27 # role 3
28 name3 = 'Rain'
29 role3 = 'terrorist'
30 weapon3 = 'C33'
31 life_value3 = 100
32 money3 = 10000
33
34 # role 4
35 name4 = 'Eric'
36 role4 = 'police'
37 weapon4 = 'B51'
38 life_value4 = 100
39 money4 = 10000
40 #4个角色虽然创建好了,但是有个问题就是,每创建一个角色,我都要单独命名,name1,name2,name3,name4…,
41 # 后面的调用的时候这个变量名你还都得记着,要是再让多加几个角色,估计调用时就很容易弄混啦,所以我们想一想,
42 # 能否所有的角色的变量名都是一样的,但调用的时候又能区分开分别是谁?
43 #当然可以,我们只需要把上面的变量改成字典的格式就可以啦。
44 roles = {
45 1: {'name': 'Alex',
46 'role': 'terrorist',
47 'weapon': 'AK47',
48 'life_value': 100,
49 'money': 15000,
50 },
51 2: {'name': 'Jack',
52 'role': 'police',
53 'weapon': 'B22',
54 'life_value': 100,
55 'money': 15000,
56 },
57 3: {'name': 'Rain',
58 'role': 'terrorist',
59 'weapon': 'C33',
60 'life_value': 100,
61 'money': 15000,
62 },
63 4: {'name': 'Eirc',
64 'role': 'police',
65 'weapon': 'B51',
66 'life_value': 100,
67 'money': 15000,
68 },
69 }
70
71 print(roles[1]) # Alex
72 print(roles[2]) # Jack
73 # 很好,这个以后调用这些角色时只需要roles[1],roles[2]就可以啦,角色的基本属性设计完了后,我们接下来为每个角色开发以下几个功能
74 # 1.被打中后就会掉血的功能
75 # 2.开枪功能
76 # 3.换子弹
77 # 4.买枪
78 # 5.跑、走、跳、下蹲等动作
79 # 6.保护人质(仅适用于警察)
80 # 7.不能杀同伴
81 # 。。。
82 # 我们可以把每个功能写成一个函数,类似如下:
83 def shot(by_who):
84 #开了枪后要减子弹数
85 pass
86 def got_shot(who):
87 #中枪后要减血
88 who['life_value'] -= 10
89 pass
90 def buy_gun(who,gun_name):
91 #检查钱够不够,买了枪后要扣钱
92 pass
so far so good, 继续按照这个思路设计,再完善一下代码,游戏的简单版就出来了,但是在往下走之前,我们来看看上面的这种代码写法有没有问题,至少从上面的代码设计中,我看到以下几点缺陷:
- 每个角色定义的属性名称是一样的,但这种命名规则是我们自己约定的,从程序上来讲,并没有进行属性合法性检测,也就是说role 1定义的代表武器的属性是weapon, role 2 ,3,4也是一样的,不过如果我在新增一个角色时不小心把weapon 写成了wepon , 这个程序本身是检测 不到的
- terrorist 和police这2个角色有些功能是不同的,比如police是不能杀人质的,但是terrorist可能,随着这个游戏开发的更复杂,我们会发现这2个角色后续有更多的不同之处, 但现在的这种写法,我们是没办法 把这2个角色适用的功能区分开来的,也就是说,每个角色都可以直接调用任意功能,没有任何限制。
- 我们在上面定义了got_shot()后要减血,也就是说减血这个动作是应该通过被击中这个事件来引起的,我们调用get_shot(),got_shot()这个函数再调用每个角色里的life_value变量来减血。 但其实我不通过got_shot(),直接调用角色roles[role_id][‘life_value’] 减血也可以呀,但是如果这样调用的话,那可以就是简单粗暴啦,因为减血之前其它还应该判断此角色是否穿了防弹衣等,如果穿了的话,伤害值肯定要减少,got_shot()函数里就做了这样的检测,你这里直接绕过的话,程序就乱了。 因此这里应该设计 成除了通过got_shot(),其它的方式是没有办法给角色减血的,不过在上面的程序设计里,是没有办法实现的。
- 现在需要给所有角色添加一个可以穿防弹衣的功能,那很显然你得在每个角色里放一个属性来存储此角色是否穿 了防弹衣,那就要更改每个角色的代码,给添加一个新属性,这样太low了,不符合代码可复用的原则
1 class Role: 2 def __init__(self, name, role, weapon, life_value=100, money=15000): 3 #构造函数 4 #在实例化时做一些类的初始化的工作 5 self.name = name 6 self.role = role 7 self.weapon = weapon 8 self.life_value = life_value 9 self.money = money 10 11 def shot(self): 12 print("shooting...") 13 14 def got_shot(self): 15 print("%s:ah...,I got shot..."%self.name) 16 17 def buy_gun(self, gun_name): 18 print("%s just bought %s" % (self.name,gun_name)) 19 20 21 r1 = Role('Alex', 'police', 'AK47') #把一个类变成一个具体对象的过程叫实例化(初始化一个类,相当于造了一个对象), 22 # 赋给r1,否则只能用一次 23 r2 = Role('Jack', 'terrorist', 'B22') #生成一个角色 24 25 r1.buy_gun('AK47') 26 r2.got_shot()#Role.got_shot(r2)cs_ 先不考虑语法细节,相比靠函数拼凑出来的写法,上面用面向对象中的类来写最直接的改进有以下2点:
- 代码量少了近一半
- 角色和它所具有的功能可以一目了然看出来
没有使用类:调用函数--->执行--->返回结果
r1=Role.__init__() return x3223123
使用类
r1=Role(r1,"Alex","Police","15000")
r1.name="Alex"
r1.role="Police"
r1.money="15000"
r1.buy_gun() #Role.buy_gun(r1),让类知道是谁在调用它,所以类下的方法都至少有一个self
三、实例变量与类变量
实例先找实例中的变量,再找类中的变量
1 class Role: 2 n=123#类变量 3 n_list=[] 4 name="我是类name" 5 def __init__(self, name, role, weapon, life_value=100, money=15000): 6 #构造函数 7 #在实例化时做一些类的初始化的工作 8 self.name = name #实例变量(静态属性),作用域就是实例本身 9 self.role = role 10 self.weapon = weapon 11 self.life_value = life_value 12 self.money = money 13 14 def shot(self):#类的方法,功能(动态属性) 15 print("shooting...") 16 17 def got_shot(self): 18 print("%s:ah...,I got shot..."%self.name) 19 20 def buy_gun(self, gun_name): 21 print("%s just bought %s" % (self.name,gun_name)) 22 23 print(Role.n) 24 25 26 r1 = Role('Alex', 'police', 'AK47') #Role(r1,'Alex', 'police', 'AK47') 27 # 把一个类变成一个具体对象的过程叫实例化(初始化一个类,相当于造了一个对象), 28 # 赋给r1,否则只能用一次 29 r1.name="陈荣华" 30 r1.n_list.append("from r1") 31 r1.bullet_prove=True 32 r1.n="改类变量"#实际上是在r1内存里创建了一个新的n变量 33 print(r1.weapon) 34 #del r1.weapon 35 36 37 38 print(r1.n,r1.name,r1.bullet_prove) 39 r2 = Role('Jack', 'terrorist', 'B22') #生成一个角色,Role类的一个实例 40 r2.name="徐良伟" 41 r2.n_list.append("from r2") 42 print(r2.n, r2.name,r2.n_list) 43 # r1.buy_gun('AK47') 44 # r2.got_shot()#Role.got_shot(r2) 45 Role.n="ABC" 46 print(Role.n_list) 47 print(r1.n,r2.n)cs_2
析构函数,私有属性,私有方法
1 class Role: 2 n=123#类变量 3 n_list=[] 4 name="我是类name" 5 def __init__(self, name, role, weapon, life_value=100, money=15000): 6 #构造函数 7 #在实例化时做一些类的初始化的工作 8 self.name = name #实例变量(静态属性),作用域就是实例本身 9 self.role = role 10 self.weapon = weapon 11 self.__life_value = life_value #私有属性,从外面不能更改 12 self.money = money 13 def __del__(self): #析构函数 14 pass #print("%s 彻底死了。。"%self.name) 15 def show_status(self): 16 self.__life_value-=50 #在里面可以改 17 print("name:%s weapon:%s life_value:%s"%(self.name,self.weapon,self.__life_value)) 18 19 def __shot(self):#类的方法,功能(动态属性)# 私有方法 20 print("shooting...") 21 22 def got_shot(self): 23 print("%s:ah...,I got shot..."%self.name) 24 25 def buy_gun(self, gun_name): 26 print("%s just bought %s" % (self.name,gun_name)) 27 r1 = Role('Alex', 'police', 'AK47') 28 # r1.buy_gun("AK47") 29 r1.show_status()#可以看血量,但不可改View Code
继承
1 #class People:经典类 2 class People(object):#新式类 3 def __init__(self,name,age): 4 self.name=name 5 self.age=age 6 self.friends=[] 7 def eat(self): 8 print("%s is eating..."%self.name) 9 def talk(self): 10 print("%s istalking..." % self.name) 11 def sleep(self): 12 print("%s is sleeping..." % self.name) 13 class Relation(object): 14 def make_friends(self,obj):# 15 print("%s is making friends with %s"%(self.name,obj.name)) 16 self.friends.append(obj) 17 class Man(People,Relation): 18 #往Man类里加参数又不改变对父类的调用 19 def __init__(self,name,age,money): 20 #People.__init__(self,name,age) 21 super(Man,self).__init__(name,age) #两者功能一样。#新式类写法 22 self.money=money 23 print("%s 一出生就有%s money"%(self.name,self.money)) 24 def piao(self): 25 print("%s is piaoing...20s...done"%self.name) 26 def sleep(self): 27 People.sleep(self) 28 print("man is sleeping..." ) 29 class Woman(Relation,People): 30 def get_birth(self): 31 print("%s is born a baby..."%self.name) 32 m1=Man("Jack",22,10) 33 # m1.eat() 34 # m1.piao() 35 # m1.sleep() 36 w1=Woman("Chenronghua",26) 37 # w1.get_birth() 38 #w1.piao() #不可以调用piao() 39 m1.make_friends(w1) 40 w1.name="陈三炮" 41 print(m1.friends[0].name)heritage_
多继承
python3.x经典类和新式类都是统一按广度优先继承,python2.x中经典按类深度优先继承,新式类按广度优先继承。
1 class A: 2 def __init__(self): 3 print("A") 4 class B(A): 5 pass 6 # def __init__(self): 7 # print("B") 8 class C(A): 9 #pass 10 def __init__(self): 11 print("C") 12 class D(B,C): 13 pass 14 # def __init__(self): 15 # print("D") 16 17 18 obj = D()heritage___
继承的例子
1 class School(object): 2 def __init__(self,name,addr): 3 self.name=name 4 self.addr=addr 5 self.students=[] 6 self.staffs=[] 7 def enroll(self,stu_obj): 8 print("为学员%s办理注册手续"%stu_obj.name) 9 self.students.append(stu_obj) 10 def hire(self,staff_obj): 11 print("雇佣新员工%s" % staff_obj.name) 12 self.staffs.append(staff_obj) 13 class SchoolMember(object): 14 def __init__(self,name,age,sex): 15 self.name=name 16 self.age=age 17 self.sex=sex 18 def tell(self): 19 pass 20 class Teacher(SchoolMember): 21 def __init__(self,name,age,sex,salary,course): 22 super(Teacher,self).__init__(name,age,sex) 23 self.salary=salary 24 self.course=course 25 def tell(self): 26 print(''' 27 ---info of Teacher:%s--- 28 Name:%s 29 Age:%s 30 Sex:%s 31 Salary:%s 32 Course:%s 33 '''%(self.name,self.name,self.age,self.sex,self.salary,self.course)) 34 def teach(self): 35 print("%s is teaching course [%s]"%(self.name,self.course)) 36 class Student(SchoolMember): 37 def __init__(self,name,age,sex,stu_id,grade): 38 super(Student, self).__init__(name, age, sex) 39 self.stu_id = stu_id 40 self.grade = grade 41 def tell(self): 42 print(''' 43 ---info of Student:%s---- 44 Name:%s 45 Age:%s 46 Sex:%s 47 Stu_id:%s 48 Grade:%s 49 '''%(self.name,self.name,self.age,self.sex,self.stu_id,self.grade)) 50 def pay_tuition(self,amount): 51 print("%s has paid tuition for $%s"%(self.name,amount)) 52 53 school=School("老男孩IT","沙河") 54 55 t1=Teacher("Oldboy",56,"MF","200w","Linux") 56 t2=Teacher("Alex",22,"M",3000,"PythonDevOps") 57 58 s1=Student("ChenRonghua",36,"MF",1001,"PythonDevOps") 59 s2=Student("徐良伟",19,"M",1002,"Linux") 60 61 t2.tell() 62 s1.tell() 63 64 school.hire(t1) 65 school.enroll(s1) 66 school.enroll(s2) 67 68 print(school.students) 69 print(school.staffs) 70 school.staffs[0].teach() 71 72 for stu in school.students: 73 stu.pay_tuition(5000)heritage_school
四、多态:一种接口,多种实现
多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。 那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。 Pyhon 很多语法都是支持多态的,比如 len(),sorted(), 你给len传字符串就返回字符串的长度,传列表就返回列表长度。1 class Animal: 2 def __init__(self, name): # Constructor of the class 3 self.name = name 4 5 def talk(self): # Abstract method, defined by convention only 6 pass #raise NotImplementedError("Subclass must implement abstract method") 7 8 @staticmethod 9 def animal_talk(obj): 10 obj.talk() 11 12 class Cat(Animal): 13 def talk(self): 14 print('Meow!') 15 16 17 class Dog(Animal): 18 def talk(self): 19 print('Woof! Woof!') 20 21 22 d = Dog("陈荣华") 23 #d.talk() 24 25 c = Cat("徐良伟") 26 #c.talk() 27 # 28 # def animal_talk(obj): 29 # obj.talk() 30 31 Animal.animal_talk(c) 32 Animal.animal_talk(d)View Code
本节作业: 选课系统
角色:学校、学员、课程、讲师
要求:
1. 创建北京、上海 2 所学校
2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开
3. 课程包含,周期,价格,通过学校创建课程
4. 通过学校创建班级, 班级关联课程、讲师
5. 创建学员时,选择学校,关联班级
6. 创建讲师角色时要关联学校,
7. 提供两个角色接口
7.1 学员视图, 可以注册, 交学费, 选择班级,
7.2 讲师视图, 讲师可管理自己的班级, 上课时选择班级, 查看班级学员列表 , 修改所管理的学员的成绩
7.3 管理视图,创建讲师, 创建班级,创建课程
8. 上面的操作产生的数据都通过pickle序列化保存到文件里
posted on 2017-10-27 11:20 我很好u 阅读( ...) 评论( ...) 编辑 收藏
转载于:https://wwwblogs/jyh-py-blog/p/7742270.html
更多推荐
python学习笔记_week6_面向对象
发布评论