python - 面向对象

面向对象编程的定义:

面向对象”是专指在程序设计中采用封装、继承、多态等设计方法,它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
在Python中一切皆为对象,可以理解为Python 中的一切都可以赋值给变量或者作为参数传递给函数。

面向对象的基本原则 (参考自https://www.cnblogs.com/WuXuanKun/p/5386495.html)

单一职责原则:

一个类应该只有一个发生变化的原因,核心:解耦和增强内聚性(高内聚,低耦合)
类被修改的几率很大,因此应该专注于单一的功能。如果你把多个功能放在同一个类中,功能之间就形成了关联,改变其中一个功能,有可能中止另一个功能,这时就需要新一轮的测试来避免可能出现的问题。

开闭原则

对扩展开放,对修改关闭。即在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。
根据开闭原则,在设计一个软件系统模块(类,方法)的时候,应该可以在不修改原有的模块(修改关闭)的基础上,能扩展其功能(扩展开放)。
扩展开放:某模块的功能是可扩展的,则该模块是扩展开放的。软件系统的功能上的可扩展性要求模块是扩展开放的。
修改关闭:某模块被其他模块调用,如果该模块的源代码不允许修改,则该模块修改关闭的。软件系统的功能上的稳定性,持续性要求是修改关的。

里氏替换原则

1.在任何父类出现的地方都可以用他的子类来替代(子类应当可以替换父类并出现在父类能够出现的任何地方)子类必须完全实现父类的方法。在类中调用其他类是务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则。
2.子类可以有自己的个性。子类当然可以有自己的行为和外观了,也就是方
3.覆盖或实现父类的方法时输入参数可以被放大。即子类可以重载父类的方法,但输入参数应比父类方法中的大,这样在子类代替父类的时候,调用的仍然是父类的方法。即以子类中方法的前置条件必须与超类中被覆盖的方法的前置条件相同或者更宽松。
4.覆盖或实现父类的方法时输出结果可以被缩小。

依赖倒转原则

核心:要依赖于抽象,不要依赖于具体的实现
1.高层模块不应该依赖低层模块,两者都应该依赖其抽象(抽象类或接口)
2.抽象不应该依赖细节(具体实现)
3.细节(具体实现)应该依赖抽象。
三种实现方式:1.通过构造函数传递依赖对象
2.通过setter方法传递依赖对象
3.接口声明实现依赖对象

接口隔离原则

不应该强迫客户程序依赖他们不需要使用的方法。
接口分离原则的意思就是:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有的操作都封装到一个接口当中.
分离接口的两种实现方法:
1.使用委托分离接口。2.使用多重继承分离接口。

合成聚合复用原则

尽量使用对象组合,而不是继承来达到复用的目的。该原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分:新的对象通过向这些对象的委派达到复用已有功能的目的。
复用的种类:
1.继承
2.合成聚合

迪米特法则(最少知识原则)

Python中面向对象的特性(参考自https://www.cnblogs.com/wangxin37/p/6598466.html)

Python 的所有对象都有三个特性:

一、身份:每个对象都有一个唯一的身份标识自己,任何对象的身份都可以使用内建函数 id() 来得到,可以简单的认为这个值是该对象的内存地址。

二、类型:对象的类型决定了对象可以保存什么类型的值,有哪些属性和方法,可以进行哪些操作,遵循怎样的规则。可以使用内建函数 type() 来查看对象的类型。

三、值:对象所表示的数据

对象的属性:大部分 Python 对象有属性、值或方法,使用句点(.)标记法来访问属性。最常见的属性是函数和方法,一些 Python 对象也有数据属性,如:类、模块、文件等

对象的创建和引用

a = 3

简单来看,上边的代码执行了以下操作:
创建了一个对象来代表数字 3
如果变量 a 不存在,创建一个新的变量 a
将变量 a 和数字 3 进行连接,即 a 成为对象 3 的一个引用,从内部来看,变量是到对象的内存空间的一个指针,尤其注意:变量总是连接到对象,而不会连接到其他变量。
从概念上可以这样理解,对象是堆上分配的一个内存空间,用来表示对象所代表的值;变量是一个系统创建的表中的元素,拥有指向对象的引用;引用是从变量到对象的指针。
从技术上来说,每一个对象有两个标准的头部信息,一个类型标识符来标识类型,还有一个引用的计数器,用于决定是否需要对对象进行回收。这里还涉及到对象的一种优化方法,Python 缓存了某些不变的对象对其进行复用,而不是每次创建新的对象。

a = 1
b = 1
id(a)
26188904
id(b)
26188904 # a 和 b 都指向了同一对象

共享引用
在 Python 中变量都是指向某一对象的引用,当多个变量都引用了相同的对象,成为共享引用。

a = 1
b = a
a = 2
b
1 # 由于变量仅是对对象的一个引用,因此改变 a 并不会导致 b 的变化

但对于像列表这种可变对象来说则不同

a = [1, 2, 3]
b = a
a[0] = 0
a
[0, 2, 3] # 这里并没有改变 a 的引用,而是改变了被引用对象的某个元素
b
[0, 2, 3] # 由于被引用对象发生了变化,因此 b 对应的值也发生了改变

由于列表的这种可变性,在代码执行某些操作时可能出现一些意外,因此需要对其进行拷贝来保持原来的列表

a = [1, 2, 3]
b = a[:]
id(a)
140200275166560
id(b)
140200275238712 # 由于 b 引用的是 a 引用对象的一个拷贝,两个变量指向的内存空间不同
a[0] = 0
b
[1, 2, 3] # 改变 a 中的元素并不会引起 b 的变化

对于字典和集合等没有分片概念的类型来说,可以使用 copy 模块中的 copy() 方法进行拷贝

import copy
b = copy.copy(a)

对象相等
== 操作符用于测试两个被引用的对象的值是否相等
is 用于比较两个被引用的对象是否是同一个对象

a = [1, 2, 3]
b = a
a is b
True # a 和 b 指向相同的对象
a = [1, 2, 3]
b = [1, 2, 3]
a is b
False # a 和 b 指向不同的对象

当操作对象为一个较小的数字或较短的字符串时,又有不同:

a = 7
b = 7
a is b
True # a 和 b 指向相同的对象

这是由于 Python 的缓存机制造成的,小的数字和字符串被缓存并复用,所以 a 和 b 指向同一个对象

对象回收机制
上边提到对象包含一个引用的计数器,计数器记录了当前指向该对象引用的数目,一旦对象的计数器为 0 ,即不存在对该对象的引用,则这个对象的内存空间会被回收。这就是 Python 中对象的回收机制,一个最明显的好处即在编写代码过程中不需要考虑释放内存空间。

可以通过 sys 模块中的 getrefcount() 函数查询一个对象计数器的值

import sys
sys.getrefcount(1)
718

你可能感兴趣的:(python - 面向对象)