类和对象是面向对象编程的两个主要方面。类创建一个新类型,而对象是这个类的 实例 。这类似于你有一个int
类型的变量,这存储整数的变量是int
类的实例(对象)。 (比如鸟就是“鸟类”的实例,鸟类有很多子类,比如“百灵鸟类”就是一个“鸟类”的子类,“鸟类”是“百灵鸟”的超类)
所有子类都有父类的方法,定义子类只是个定义更多(或者重载已经存在的)的方法的过程
对象可以使用普通的 属于 对象的变量存储数据。属于一个对象或类的变量被称为域。对象也可以使用 属于 类的函数来具有功能。这样的函数被称为类的方法。这些术语帮助我们把它们与孤立的函数和变量区分开来。域和方法可以合称为类的属性。
1.多态: (百度百科)多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作,也就是说,父亲的行为像儿子,而不是儿子的行为像父亲。 把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异。简单的说,建立一个父类对象的引用,它所指对象可以是这个父类的对象,也可以是它的子类的对象。
(python基础教程)就算不知道变量所引用的对象类型是什么,还是能对他操作,它会根据对象(或类)类型的不同表现出不同的行为
(个人理解):把子对象都看作父对象,当赋值时,根据所赋的值,通过父对象调用不同的子对象的方法
2.封装:(百科)封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。
(个人理解):就是把对象的工作细节隐藏起来 ,把相关类的相关变量作为特性,封装在类内,对象的方法可以改变对象的特性。
-
特性是对象内部的变量
-
对象的状态由它的特性来描述,对象的方法可以改变它的特性
-
可以直接从对象外部访问特性
-
3.继承:以通用的类为基础建立专门的类对象(子类型)
1.多态和方法
让用户对不知道是什么类的对象进行方法调用
不需要检测类型,只需要知道x有个叫做count的方法
例如‘+’ 无需知道什么加什么,‘+’都可以操作
2.封装
对对象进行抽象,调用时不用关心其他的东西。作为 特性 存储,“封装”在对象内
对象有自己的状态,状态由他的特性(比如名字)来描述。对象的方法可以改变特性。
3.继承
7.2.2创建自己的类
7.2.3 特性,函数和方法
self参数是对对象自身的引用,作为第一个参数绑定到所属实例上(因此你无需在调用对象方法的时候显示的提供该参数),好让让成员方法访问他们要对其操作的对象本身
例如:foo是Person的实例,foo.greet()可作为Person.greet(foo)的简写
self参数正是方法和函数的区别
注:其实python并没有真正的私有化支持
默认情况下,程序可以从外部访问一个对象的特性。
>>>c.name
'Sir Lancelot'
>>>c.name='Sir gumby'
>>>c.getname()
'Sir gumby'
但是,有的时候,希望 完全隐藏(不可访问) 。此时,就要使用私有特性(方法)这样,外部对象无法访问,但是内部的方法能够访问。必须得通过使用同一个对象的方法 访问器 访问 ——————访问器的替代者是属性,见第九章
1.只要在名字前面加上双下划线
原理是类的内部定义中,所有以双下划线开始的名字都被翻译成了前面加上单下划线和类名的形式
例如
class Secretive:
def __inacessible(self):
变为
def _Secretive.__inacessible(self)
所以,其实还是可以在类外访问这些私有类
也可以使用单下划线让其他对象不要访问内部数据 和双下划线是两种级别的私有性
3、 __xx__定义的是特殊方法。用户控制的命名空间内的变量或是属性,如init , __import__或是file 。只有当文档有说明时使用,不要自己定义这类变量。这些特殊方法会在特殊情况下根据名字被python调用。几乎没有直接调用他们的必要。 (就是说这些是python内部定义的变量名)
在这里强调说一下私有变量,python默认的成员函数和成员变量都是公开的,没有像其他类似语言的public,private等关键字修饰.但是可以在变量前面加上两个下划线"_",这样的话函数或变量就变成私有的.这是python的私有变量轧压(这个翻译好拗口),英文是(private name mangling.) **情况就是当变量被标记为私有后,在变量的前端插入类名,再类名前添加一个下划线"_",即形成了_ClassName__变量名.**
7.2.4 类的命名空间 (这里说明self.attr和attr的区别)
类的定义其实就是执行代码块,而class中的代码都在特殊的命名空间中执行----类命名空间,可由类内所有成员访问
一个特别的例子
>>> class MemberCount:
member=0
def init(self):
MemberCount.member+=1 #注意这里,init改变的是类的特性,不是改变实例的变量(self.member),所以,m2。member会变成2
>>> m1=MemberCount()
>>> m1.init()
>>> MemberCount.member
1
>>> m2=MemberCount()
>>> m2.init()
>>> MemberCount.member
2
>>> m1.member
2
>>> m1.member='two'
>>> m1.member
'two'
>>> m2.member
2
7.2.5 指定超类
class Spamfilter(Filter):
Spamfilter是Filter的子类
子类继承超类
也可在子类中重写Filter的某些定义
7.2.6 检查继承
使用issubclass()检查一个类是否另一个类的自类
使用基类的特殊特性__bases__ 得到已知类的基类
使用__class__ 知道一个对象属于哪个类
或者使用type()来查看新式类的实例的所属类
7.2.7 多个超类(多重继承)
需要注意的事,,如果一个方法从多个超类继承,要注意顺序:先继承的类的方法,重写 后继承 的类的方法。子类的方法 重写超类的方法
Python类继承之深度优先
python 支持多继承,但对与经典类和新式类来说,多继承查找的顺序是不一样的。
经典类:
实例d调用foo()时,搜索顺序是 D => C1 => P1
实例d调用bar()时,搜索顺序是 D => C1 => P1 => P2
换句话说,经典类的搜索方式是按照“从左至右,深度优先”的方式去查找属性。d先查找自身是否有foo方法,没有则查找最近的父类C1里是否有该方法,如果没有则继续向上查找,直到在P1中找到该方法,查找结束。
Python类继承之广度优先
新式类:
实例d调用foo()时,搜索顺序是 D => C1 => C2 => P1
实例d调用bar()时,搜索顺序是 D => C1 => C2
可以看出,新式类的搜索方式是采用“广度优先”的方式去查找属性。
7.2.8 接口和内省
判断对象是否符合当前接口(是否能实现当前方法)内省
使用hasattr(x,'__call__')来判断某个特性是否可调用
可以使用__dict__特性来查看对象内所有储存的值