python面向对象编程(上)
面向对象编程(OOP,Object Oriented Programming)是每一个高级编程语言都支持的编程方法,比如JAVA/C++/C#等等。学习面向对象编程是每一个程序员都绕不开的重点内容。
一、面向对象的概念
面向对象是在面向过程的设计方法出现很多问题的情况下应运而生的。面向过程设计方法求解问题的基本策略是从功能的角度审视问题域。它将应用程序看成实现某些特定任务的功能模块,其中子过程是实现某项具体操作的底层功能模块。在每个功能模块中,用数据结构描述待处理数据的组织形式,用算法描述具体的操作过程。面对日趋复杂的应用系统,这种设计思路在不同方面逐渐暴露出了缺点:一是系统性较差;二是抽象级别较低;三是封装程度不够;四是重用性较差。在软件理论和硬件提升的过程中,出现了函数式编程(严格来说也算面向过程的一种),它更高级一点。没多久,面向对象编程出现了,实现了跨越式的发展。Java和C#来说只支持面向对象编程,而python比较灵活即支持面向对象编程也支持函数式编程。
- 面向过程:根据业务逻辑从上到下写垒代码
- 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
- 面向对象:对函数进行分类和封装,让开发“更快更好更强...”
二、类和对象
面向对象编程是一种编程方式,它需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。在这里请一定要忘记“面向对象”,“类”和“对象”这三个词的中文意思,不要按他们的字面意思去理解,请用代码组织和利用的形式来理解他们。
类就是一个模板,就像word模板一样,可以在它的基础之上填充内容。模板里可以包含多个函数和变量,函数里实现一些功能,变量里保存一些值。
对象则是根据模板创建的实例,也就是填充了东西之后,对象可以执行类中的函数,可以调用字段。
本质上,类是对事物的抽象,对象(也叫实例)是将抽象的类具体化成一个有血有肉的活体。例如:
定义一个类叫做“人”,他能吃能喝能睡能工作,这些是“人”这个类内部的函数(方法);他有身高有体重有性别,这是“人”这个类的字段。
然后我们可以实例化“人”这个类,比如“张三”、“李四"、”王五”,他们都是“人”这个类的对象,有各自的身高体重性别,但都能吃喝拉撒睡。
那么在程序中是如果创建类和对象的呢?
- class是关键字,表示类
- 创建对象,类名称后加括号即可
# 创建类 class Foo: def Bar(self): print 'Bar' def Hello(self, name): print 'i am %s' %name # 根据类Foo创建对象obj obj = Foo() obj.Bar() #执行Bar方法 obj.Hello('wupeiqi') #执行Hello方法
类和对象在内存中是如何保存的?
类以及类中的方法在内存中只有一份,而根据类创建的每一个对象都在内存中需要存一份,大致如下图:
如上图所示,根据类创建对象时,对象中除了封装 name 和 age 的值之外,还会保存一个类对象指针,该值指向当前对象的类。因此,对象可以寻找到自己的类,并进行某些调用,而类是无法寻找自己的某个对象,然后调用它的。
当通过 obj1 执行方法时,过程如下:
- 根据当前对象中的 类对象指针 找到类中的方法
- 将对象 obj1 当作参数传给 方法的第一个参数 self
三、面向对象三大特性
面向对象的三大特性是指:封装、继承和多态。
一、封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:
- 将内容封装到某处
- 从某处调用被封装的内容
第一步:将内容封装到某处
self 是一个形式参数,当执行 obj1 = Foo('wupeiqi', 18 ) 时,self 等于 obj1
当执行 obj2 = Foo('alex', 78 ) 时,self 等于 obj2
所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有 name 和 age 属性,在内存里类似于下图来保存。
第二步:从某处调用被封装的内容
调用被封装的内容时,有两种情况:
- 通过对象直接调用
- 通过self间接调用
1、通过对象直接调用被封装的内容
上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名
class Foo: def __init__(self, name, age): self.name = name self.age = age obj1 = Foo('jack', 18) print obj1.name # 直接调用obj1对象的name属性 print obj1.age # 直接调用obj1对象的age属性 obj2 = Foo('andy', 73) print obj2.name # 直接调用obj2对象的name属性 print obj2.age # 直接调用obj2对象的age属性
2、通过self间接调用被封装的内容
执行类中的方法时,需要通过self间接调用被封装的内容
class Foo: def __init__(self, name, age): self.name = name self.age = age def detail(self): print self.name print self.age obj1 = Foo('jack', 18) obj1.detail() # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 jack ;self.age 是 18 obj2 = Foo('andy', 73) obj2.detail() # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 andy ; self.age 是 78
综上所述,上面对于面向对象封装特性的解释是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容。然而,本人认为这只是一种低层次的理解。更高层面的理解是:面向对象封装的不仅仅是对象中的普通内容(字段),同时也封装了类本身包含的其他字段、方法和属性,封装也不简单的只是封闭、访问限制的意思,更有一种集成、打包、模块化的概念。
下面的例子中,Foo类中定义了一个私有方法,这是一种封装,它使得外部无法直接调用该方法;Foo还定义了一个静态方法,它可以在不实例化对象的情况下直接由类调用,这也是一种封装。
class Foo: def __init__(self, name): self.name = name def __show(self): print(self.name) @staticmethod def welcome(): print("welcome!") Foo.welcome() obj = Foo("jack") obj.__show()
究其本质,封装作为面向对象三大特性之首,从结构和使用上实现了类和对象两大元素,将事物抽象出来的本质特性封装成为类,又将每一个类的实现封装为一个对象。
二、继承
继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。但是,父亲不能继承儿子的内容。
对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。
注:除了子类和父类的称谓,还有派生类 和 基类 的说法,他们与子类和父类只是叫法不同而已。
那么问题又来了,多继承呢?
- 是否可以继承多个类
- 如果继承的多个类每个类中都定了相同的函数,那么那一个会被使用呢?
Python的类可以继承多个类,Java和C#中则只能继承一个类。注意,是同时继承多个类,而不是多层类的意思。
python2和python3在多继承策略中有很大不同!
注意:以下是python2中继承的方法!
在Python2版本中的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先
- 当类是经典类时,多继承情况下,会按照深度优先方式查找
- 当类是新式类时,多继承情况下,会按照广度优先方式查找
经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
class D: def bar(self): print 'D.bar' class C(D): def bar(self): print 'C.bar' class B(D): def bar(self): print 'B.bar' class A(B, C): def bar(self): print 'A.bar' a = A() # 执行bar方法时 # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错 # 所以,查找顺序:A --> B --> D --> C # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了 a.bar()
经典类多继承
class D(object): def bar(self): print 'D.bar' class C(D): def bar(self): print 'C.bar' class B(D): def bar(self): print 'B.bar' class A(B, C): def bar(self): print 'A.bar' a = A() # 执行bar方法时 # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错 # 所以,查找顺序:A --> B --> C --> D # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了 a.bar()
新式类多继承
经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
注意:以上是python2.x版本中多继承的问题!!!
下面,让我们看看在python3.x版本中是如何多继承的。需要说明的是,在python3.x之后,没有新式和经典类的概念了。
例子一:
我们设想了一个如下图一的继承关系:
图一
A同时继承B和C,B继承C,C继承D,其他类似不赘述。
class D: # def show(self): # print("i am D") pass class C(D): pass class B(C): def show(self): print("i am B") pass class G: pass class F(G): pass class E(F): def show(self): print("i am E") pass class A(B, E): pass a = A() a.show()
运行结果是i am B。在类A中,没有show这个方法,于是它只能去它的父类里查找,最后它在B类中找到并执行了show方法。可见,在A的定义中,继承参数的书写有先后顺序,写在前面的被优先继承。那如果B没有show方法,而是D有呢?
class D: def show(self): print("i am D") pass class C(D): pass class B(C): pass class G: pass class F(G): pass class E(F): def show(self): print("i am E") pass class A(B, E): pass a = A() a.show()
运行结果是i am D,左边具有深度优先权,当一条路走到黑也没找到的时候,就换一条路。可见,在图一的这种继承结构关系中,搜索顺序是这样的:
例子二:
如果继承结构图是这样的呢?
类D和类G又同时继承了类H。
当只有B和E有show方法的时候,无疑和上面的例子一样,找到B就不找了,直接打印i am B。但如果是只有H和E有show方法呢?如下面的代码:
class H: def show(self): print("i am H") pass class D(H): # def show(self): # print("i am D") pass class C(D): pass class B(C): # def show(self): # print("i am B") pass class G(H): pass class F(G): pass class E(F): def show(self): print("i am E") pass class A(B, E): pass a = A() a.show()
我们想当然地以为会打印i am H。但是,打印的却是i am E!为什么?因为在这种情况下,python的继承搜索路劲是这样的:
它会在搜索左边,直到快到定点H的前一个点D,然后转身搜索另一边的E,再一直往E这条线搜索到最后!很绕是吧?
其它类型的继承结构可以在这个的基础上进行修改和扩展,大家可以自己尝试一下,基本都是这个套路。
三、多态
多态就是多种形态、多种类型意思,表示同一件事物,在不同的情况下可以表现出不同的特性或实现不同的功能或产生不同的效果。
python面向对象编程(上)的更多相关文章
- python 面向对象编程学习
1. 问题:将所有代码放入一个py文件:无法维护 方案:如果将代码才分放到多个py文件,好处: 1. 同一个名字的变量互相不影响 2.易于维护 3.引用模块: import module 2.包:解决 ...
- python面向对象编程进阶
python面向对象编程进阶 一.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 1 ...
- Python面向对象编程(下)
本文主要通过几个实例介绍Python面向对象编程中的封装.继承.多态三大特性. 封装性 我们还是继续来看下上文中的例子,使用Student类创建一个对象,并修改对象的属性.代码如下: #-*- cod ...
- Python面向对象编程——继承与派生
Python面向对象编程--继承与派生 一.初始继承 1.什么是继承 继承指的是类与类之间的关系,是一种什么"是"什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创 ...
- 图解python | 面向对象编程
作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/56 本文地址:http://www.showmeai.tech/article-det ...
- python 面向对象编程(一)
一.如何定义一个类 在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法. 类是对现实世界中一些事物的封装,定义一个类可以采用下面的方式来定义: class c ...
- Python面向对象编程指南
Python面向对象编程指南(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1SbD4gum4yGcUruH9icTPCQ 提取码:fzk5 复制这段内容后打开百度网 ...
- Python 面向对象编程——访问限制
<无访问限制的对象> 在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑.但是,从前面Student类的定义来看(见:Py ...
- Python 面向对象编程 继承 和多态
Python 面向对象编程 继承 和多态 一:多继承性 对于java我们熟悉的是一个类只能继承一个父类:但是对于C++ 一个子类可以有多个父亲,同样对于 Python一个类也可以有多个父亲 格式: c ...
随机推荐
- 创建一个Windows的NTP Server
搭建一个VMware vRealize Suite的时候遇见了不少时间同步的问题, 实验室里网络与外界隔绝, 不能使用公网的NTP服务器, 所以使用文中的方法自己搭建了一个. 蛮好用的. Creati ...
- java list中的对象去重原理
/******************************************************************************* * * Copyright (c) W ...
- Spark随机森林实现学习
前言 最近阅读了spark mllib(版本:spark 1.3)中Random Forest的实现,发现在分布式的数据结构上实现迭代算法时,有些地方与单机环境不一样.单机上一些直观的操作(递归),在 ...
- myeclipse9或myeclipse10安装svn的方法
下载最新的SVN包 site-1.6.5.zip 从中解压出features与plugins文件夹,复制到C:\toBeInstalledSVN 里面,其它的*.xml文件不要 复制下列java代 ...
- 构造函数和:this()的应用
一.构造函数和:this()的应用 //本实例演示构造函数和:this()的应用 public class ClsA { public string A{set;get;} public string ...
- Flink 案例整合
1.概述 Flink 1.1.0 版本已经在官方发布了,官方博客于 2016-08-08 更新了 Flink 1.1.0 的变动.在这 Flink 版本的发布,添加了 SQL 语法这一特性.这对于业务 ...
- vs2010 “最近使用的项目”为空?解决办法!
本文转自http://blog.csdn.net/likaibs/article/details/39576361 谢谢该作者的分享,我在这里继续发扬光大,直接把原文粘贴过来,方便后面的朋友查看. “ ...
- AX2012 R3升级CU8的一些错误
AX2012 R3安装升级包CU8后进入系统,系统会提示打开软件升级清单“Software update checklist”,清单列出了升级要做的一系列动作. 在进行到编译应用时“Compile a ...
- Linux下php5.3编译oracle客户端
因项目需要在linux下进行php5.3的oracle客户端编译,简要介绍一下步骤及走过的弯路. 1.下载Oracle客户端程序包,其中包含OCI.OCCI和JDBC-OCI等相关文件. 1.1下载文 ...
- [Android界面] 这样的选择器怎么实现?? 充值选择
1 充值的或年纪的 或 1 先讲例子 http://blog.csdn.net/lmj623565791/article/details/48393217: 本文出自:[张鸿洋的博客] 一.概述 ...