首页 > 代码库 > Python全栈开发,Day7 - 面向对象学习

Python全栈开发,Day7 - 面向对象学习

本章内容

  1. 面向对象编程介绍
  2. 面向对象开发
  3. 面向对象的特性

一、面向对象编程介绍

介绍之前,先说一个例子:

你的老板要你做一款枪战游戏,游戏里面有很多的角色,比如CF里面的潜伏者和保卫者,在游戏里还有很多的玩家,每个玩家都有不同的名字和装扮,但是你发现这些玩家同一个阵容(潜伏者、保卫者)里的玩家具有很多相同的属性,于是你开始写代码,首先定义潜伏者1,名字、武器......等,然后保卫者1,同样,名字、武器......:代码如下:

 1 def defenders(name,weapon,*args):
 2     data =http://www.mamicode.com/ {
 3             name:name,
 4             weapon:weapon,
 5             ...
 6                 }
 7 
 8     return data
 9 
10 def lurker(name,weapon,*args):
11     data =http://www.mamicode.com/ {
12             name:name,
13             weapon:weapon,
14             ...
15                 }
16     return data

 

两个角色就出来了,然后就要开始定义功能了,我们知道在爆破模式里面需要安放C4,于是你就开始定义潜伏者可以安放C4的功能,保卫者可以拆卸C4,开枪大家都会,嗒嗒嗒,然后又开始写代码,先定义潜伏者的功能,然后定义保卫者的功能,然后又分别定义各种各样的功能:

 1 def down_the_C4(l):
 2     print("Defenders %s removed the C4"%name)
 3 
 4 
 5 def put_the_C4(d):
 6     print("Lurker %s planted the C4"%name)
 7 
 8 
 9 def gun(p):
10     print("%s is gunning....."%name)
11 
12 
13 def ...

 

终于搞定了,然后你想调用哪个就可以调用哪个,想怎么样就怎么样,于是你一脸开心的去向老板报告。

你:老板你要的东西我给你带来了。

老板看了一分钟,就发现你所写的代码有问题,于是就跟你说。

老板:小伙子,你的想法可以啊,但是你没有发现潜伏者安放C4,保卫者也可以安放(保卫者也可以调用put_the_C4())?你这样工作怕不怕打哦?

你一听心里就慌了,老板这是要搞事的节奏啊,可是你一想老板说的也对,然后回去继续憋代码。过了半天你憋出了一下代码:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Lyon
 4 
 5 def defenders(name,weapon,*args):
 6 
 7     def down_the_C4( ):
 8         print("Defenders %s removed the C4" % name)
 9     data =http://www.mamicode.com/ {
10             name:name,
11             weapon:weapon,
12             #...
13             down_the_C4:down_the_C4,
14                  }
15     return data
16 
17 def lurker(name,weapon,*args):
18 
19      def put_the_C4():
20          print("Lurker %s planted the C4" % name)
21 
22      data =http://www.mamicode.com/ {
23              name:name,
24              weapon:weapon,
25              #...
26             put_the_C4:put_the_C4
27                  }
28      return data
29 
30 d1 = defenders("lyon","ak-47")
31 l1 = lurker("Lyon","awm")
32 d1[down_the_C4]()

 

你是如此聪明与机智,这样就限制了各自的功能之间的调用,于是你满怀信心的去向老板报告。

老板:小伙子不错.......(一顿乱夸),但是小伙子如果我要在给某的角色再加功能呢?那你又得重新写了是吧?比如我在100个潜伏者角色里面,把每个都加一个特殊的功能呢?难道你就写上100遍?

你一听开始冷汗直流,早知道当初就该好好学了。现在可怎么办呀,做不好就要被炒鱿鱼了,老板也看出来你能耐就这么大了,就在这个时候,你女朋友打电话来了,手机屏幕正是你女朋友的照片,老板一看,会心一笑,放心,我不会抄你鱿鱼的,今晚你到我办公室来我来教你怎么写。。。。。

从上述例子中,根据最后的要求如果让我们来写100遍大同小异的代码明显我们不可能这样去完成,因为你一旦这么写,那么老板就会让你明天不用来上班了。那我们应该怎么来写呢?下面就开始今天的笔记了,哈哈。

 

编程范式

编程是程序员用特定的语法+数据结构+算法组成的代码来高数计算机如何执行任务的过程,一个程序是程序员为了得到一个任务结果而编写的一组指令的集合,正所谓条条道路通罗马,实现一个任务的方式有很多种不同的方式,对这些不同的编程方式的特点进行归纳总结得出来的编程方式类别,即为编程范式。不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路,大多数语言只支持一种编程范式,当然有些语言可以同时支持多种编程范式。两种最重要的编程范式分别是面向过程编程和面向对象编程。

面向过程编程(Procedural Programming)

Procedural programming uses a list of instructions to tell the computer what to do step-by-step.面向过程编程依赖procedures,一个procedure包含一组要被进行计算的步骤,面向过程又被称为top-down languages,就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题。基本设计思路就是程序一开始要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程继续分解知道小问题足够简单可以在一个小步骤范围内解决。

对于面向过程编程,当有的程序需要进行修改时,如果修改的内容在后续中有子程序依赖,那么修改起来就会很麻烦,并且随着程序越来越大,你的修改难度也就越来越高。所以我们就可以发现,如果写一些简单的脚本,去做一些一次性任务,面线过程编程是极好的,但是处理复杂的任务还是用面向对象最方便。

面向对象编程

OOP编程是利用“类”和“对象”来创建各种模型来实现对真是世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得简单,并且可以大大提高程序开发效率,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。

面向对象的几个核心特性:

Class 类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法

Object 对象 
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同

Encapsulation 封装
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法

Inheritance 继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承

Polymorphism 多态
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。
编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。
对不同类的对象发出相同的消息将会有不同的行为。比如,你的老板让所有员工在九点钟开始工作, 他只要在九点钟的时候说:“开始工作”即可,而不需要对销售人员说:“开始销售工作”,对技术人员说:“开始技术工作”, 因为“员工”是一个抽象的事物, 只要是员工就可以开始工作,他知道这一点就行了。至于每个员工,当然会各司其职,做各自的工作。
多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定。

 

以上的这么多东西,我们一下就能看懂,可是我们发现,我们还是不好理解面向对象到底有什么用?牛逼在哪里?。

编程有两个原则:

  1. 写重复代码是非常不好的低级行为
  2. 你写的代码需要经常变更

我们开发程序和自己普通写的小脚本不一样,小脚本可以随时写,随手写,随手丢,但是对于开发程序,你的代码需要不断的改进,就像我们玩的网络游戏,如果你是那个游戏的开发者,而此时你所开发的游戏出现了bug怎么办?你不可能重新再写一个游戏吧?一个正规的开发程序也不是短期内能完成的。所以作为一个开发者我们不能够给自己挖坑,写代码一定要遵循可读性好、易扩展的原则。再比如你写了一个程序,程序里面有很多的地方需要用到一段相同的代码,然后你就把代码全部给复制粘贴一遍,然后你一不小心改漏了一个,这个时候你怎么去找?你得找几天几夜来弥补你不必要的过失?

然后从上面的例子你发现,你写的函数都可以实现这个,对不对?那好,你再想想刀跟枪是不是都可以用来杀人?然后你就说刀不能杀人,然后我就会说,泥奏凯!我们发现两个都可以杀人,但是枪杀人是不是方便、快捷些?所以函数编程和OOP编程是一个道理,函数编程和OOP编程都可以达到我们的要求,但是OOP编程比函数编程牛逼多多了,这里OOP编程就是所谓的“枪”。

二、面向对象开发

 还是上面的例子我们用OOP中的“类”来实现,顺便多加几个属性以及功能,代码如下:

 1 class Role(object):
 2     def __init__(self,name,role,weapon,life_value=http://www.mamicode.com/100,money=15000):
 3         self.name = name
 4         self.role = role
 5         self.weapon = weapon
 6         self.life_value =http://www.mamicode.com/ life_value
 7         self.money = money
 8 
 9     def put_the_C4(self):
10         print("Lurker %s planted the C4" % self.name)
11 
12     def down_the_C4( self):
13         print("Defenders %s removed the C4" % self.name)
14 
15     def got_shot(self):
16         print("ah......,I got shot....")
17 
18     def buy_gun(self,gun_name):
19         print("just bought %s"%gun_name)
20 
21 r1 = Role("Lyon","defenders","AK-47")

 

这就是“类”的写法,现在你还体会不到有什么牛逼的,但是就现在来讲,除去所加的功能及属性,我们可以看出来两点:

  1. 代码量大大减少
  2. 角色和功能一目了然

现在我们先不管上面的这段代码,先来学习类的基本定义。

类的语法:

1 #创建一个类
2 class God(object):
3     #打印,hello,I am god!
4     print("hello, I am god!")
5 #实例化这个类    
6 g = God()   #此时g就是类God的实例化对象
7 
8 #实例化,其实就是God类为模块,在内存里开辟一块空间,存上数据,赋值成一个变量名

 

上面的代码你发现这个类你无法传变量名进去,往下看。

 1 #创建一个类
 2 class God(object):
 3 
 4     #构造方法,初始化这个类,生成一个角色时要初始化的一些属性就填写在这里
 5     #在类里面函数已经不叫函数了,而叫做方法,如__init__叫构造方法
 6     def __init__(self,name):
 7         #self是啥玩意儿?
 8         self.name = name
 9 
10     def produce(self):
11         #打印,hello,I am god!
12         print("hello, I am %s!"%self.name)
13 
14 #实例化这个类
15 g = God("Lyon")
16 #调用类中的方法
17 g.produce()

 

我们看到这个代码的时候发现了一个__init__函数,以及self.,这两个东西是什么呢?第一个就不说了,接下来说self.。

1 #g = God("Lyon")
2 
3 #g.produce()
4 
5 print(God)
6 
7 #输出:<class ‘__main__.God‘>

 

我们发现,即使我们不实例化这个类,这个God也是存在于内存中的,那为什么要self.呢,当我们传值的时候其实是通过self.的方法来进行传递的,而self就是实例本身什么意思呢?这样来讲,我们用 g = God(“Lyon”)实例化的时候,把g的地址和赋值参数传进来,而“Lyon”对应的是name,这里的方式不是name = “Lyon”,而是g.name = “Lyon”,你还发现上面调用类的方法的时候是用的 g.produce(),没错,在类里面的调用方式就是用“.”来实现的,所以这时候你应该知道了,self其实就是实例本身,也就是g本身。

然后我们再看,发现构造方法下面开始了一些动作,比如self.name = name ,这又是什么鬼?为啥要这样?这里我们先看 g.produce() ,我们这里明明就没有给produce()穿参数,但是它的输出确是有参数的,这又是为莫比咧?其实当你调用这个类的时候,__init__()会帮你自动给self参数赋值,于是你self.name就自动给你赋值了。

技术分享
g1 = God(Lyon) #此时self 相当于g1 
God(g1,Lyon)
__init__做的那些事

 

最后self.name = name,当我们实例化一个类(比如上面的g)的时候,就像我们存变量一样,实例化g,电脑就会开辟一块空间来存放这个g,而self.name = name 的作用就是把这个值放到g的那个内存空间,就是把属于g那个“房间”的东西,都给一一放好。

完美!!!!

 

三、面向对象的特性

封装:

封装是面向对象的特征之一,是对象和类概念的主要特征。

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

继承:

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

通过继承创建的新类称为“子类”或“派生类”。

被继承的类称为“基类”、“父类”或“超类”。

继承的过程,就是从一般到特殊的过程。

要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。

在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

继承概念的实现方式主要有2类:实现继承、接口继承。

  • 实现继承是指使用基类的属性和方法而无需额外的编码的能力;
  • 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构父类方法)
在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不能继承 Person 类,因为腿并不是一个人。
 
抽象类仅定义将由子类创建的一般属性和方法。

OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。

 

技术分享
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Lyon
 4 class Person(object):
 5     def __init__(self,name,age,sex,):
 6         self.name = name
 7         self.age = age
 8         self.sex = sex
 9         self.friends =[]
10     def sleep(self):
11         print("%s is sleepping.."%self.name)
12 
13     def eat(self):
14         print("%s is eatting..."%self.name)
15 
16     def talk(self):
17         print("%s is talking..."%self.name)
18 
19 class Relation(object):
20     def __init__(self,name,age,sex):
21         self.name = name
22         print("In the Relation...")
23     def makefriends(self,obj):
24         print("%s is making friends with %s"%(self.name,obj))
25 
26 
27 class Man(Relation,Person):
28     def __init__(self,name,age,money):
29         #Person.__init__(self,name,age) 这是经典类的写法
30         super(Man,self).__init__(name,age,money)#新式类的写法
31 
32         self.money = money
33         print("%s 一出生就有%s money"%(self.name,self.money))
34 
35     def piao(self):
36         print("%s is piaoing....."%self.name)
37 
38     def stand_wc(self):
39         print("%s is standing in the WC"%self.name)
40 
41 class Women(Relation,Person): #在这里没有__init__函数的话就会直接调用Relation方法
42     def get_birth(self):
43         print("%s is born a baby...")
44 
45 
46 M1 = Man("Lyon",20,"一亿")
47 M1.makefriends(WM)
48 W1 = Women("安妮海瑟薇",25,100)
继承例子

 

 

多态:

多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
 
Pyhon 很多语法都是支持多态的,比如 len(),sorted(), 你给len传字符串就返回字符串的长度,传列表就返回列表长度。
技术分享
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Lyon
 4 #接口重用
 5 class Animal:
 6     def __init__(self,name):
 7         self.name=name
 8 
 9     def talk(self):
10         pass
11 
12     @staticmethod
13     def animal_talk(obj):
14         obj.talk()
15 
16 class Cat(Animal):
17     def talk(self):
18         print("Meow!")
19 
20 class Dog(Animal):
21     def talk(self):
22         print("wang wang wang")
23 
24 d = Dog("chengronghua")  #d.talk()
25 c = Cat("xuliangwei")  #c.talk()
26 Animal.animal_talk(c)
27 Animal.animal_talk(d)
多态例子

 

 

 

 

 

 

 

注:本文仅为学习笔记、摘要。

详细来源:http://www.cnblogs.com/alex3714/articles/5188179.html

Python全栈开发,Day7 - 面向对象学习