Python 类与面向对象
1,程序 = 指令 + 数据
·代码可以选择以指令为核心或以数据为核心进行编写
2,两种范型
·以指令为核心:围绕"正在发生什么"进行编写
1)面向过程编程:程序具有一系列性步骤;主体思想是代码作用于数据
·以数据为核心:围绕"将影响谁"进行编写
1)面向对象编程(OOP):围绕数据及为数据严格定义的接口来组织程序用数据控制对代码的访问。
3,所有编程语言的最终目的都是提供一种抽象方法
1)在机器模型(“解空间"或"方案空间”)与实际解决的问题模型(“问题空间”)之间,程序员必须建立一种联系。
·面向过程:程序 = 算法 + 数据结构
·面向对象:将问题空间中的元素以及它们在解空间中的表示物抽象为对象,并允许通过问题来描述问题而不是方案
1)可以把对象想象成一种新型变量,它保存着数据,但可以对自身的数据执行操作
4,类型由状态集合(数据)和转换这些状态的操作集合组成
1,类抽象
类:定义了被多个同一类型对象共享的结构和行为(数据和代码)
类的数据和代码:即类的成员
数据:成员变量或实例变量
成员方法:简称为方法,是操作数据的代码,用于定义如何使用成员变量;因此以个类的行为和接口是通过方法来定义的
2,方法和变量:
· 私有:内部使用
· 公共:外部可见
面向对象的程序设计方法
1,所有东西都是对象
2,程序是一大堆对象的组合
·通过消息传递,各对象知道自己该做什么
·消息:即调用请求,它调用的是从属于目标对象的一个方法
3,每个对象都有自己的存储空间,并可容纳其它对象
·通过封装现有对象,可以制作成新型对象
4,每个对象都属于某一类型
·类型,也即使类
·对象是类的是咧
·类的一个重要特性为"能发什么样的消息给它"
5,同一个类的所有对象都能接收相同的消息
对象的接口:
1,定义一个类后,可以根据需要实例化出多个对象
2,如何利用对象完成真正有用的工作?
1)必须有一种办法能向对象发出请求,令其做一些事情
2)每个对象仅能接受特定的请求
·能向对象发送的请求由其"接口"进行定义
·对象的"类型"或"类"则规定了它的接口形式
类型名 light
接口 on()
off()
brighten()
dim()
类:将同一种具体物事的共同特性抽象出来的表现
状态和转换这些状态的操作
数据:状态
变量:就是属性
方法:操作
函数:操作变量引用的数据的代码
方法是类的组成部分。
类间关系
1,依赖(“uses -a”)
· 一个类的方法操作另一个类的对象
2,聚合(“has -a”)
·类A 的对象包含类B的对象
3,继承(“is -a”)
·描述特殊与一般关系
面向对象编程的原则
1,面向对象的模型机制有3个原则:封装,继承及多态
2,封装(Encapsulation)
·隐藏实现方案细节
·将代码及其处理的数据绑定在一起的一种编程机制,用于保证程序和数据不受外部干扰且不会被误用!
3,继承(Inheritance)
·一个对象获得另一个对象属性的过程;用于实现按层分类的概念
·一个深度继承的子类继承了类层次中它的每个祖先的所有属性
·超类,基类,父类
·子类,派生派
4,多态性(Ploymorphism)
·允许一个借口被多个通用的类动作使用的特性,具体使用哪个动作与应用场合相关
·“一个接口,多个方法”
1),用于为一组相关的动作设计一个通用的接口,以降低程序复杂性
5,面向对象编程的3个原则
1) 类是一种数据结构,可用于创建实例
·一般情况下,类封装了数据和可用于该数据的方法
2) Python类是一个可调用对象,即类对象
3) Python2.2之后,类是一种自定义类型,而实例则是声明某个自定义类型的变量
4) 实例初始化
·通过调用类来创建实例
instance = ClassName(args…)
·类在实例化时可以使用_init_和_del_两个特殊的方法
class class_name
实例对象
类存储的对象叫类对象!
类存储被实例化后的对象叫实例对象!
Python 中创建类
1,Python 使用class关键字创建类,语法格式如下
·class ClassName(bases):
1)‘class documentation string’
2) class_suite
·超类是一个或多个用于继承的父类的集合
·类体可以包含:声明语句,类成员定义,数据属性,方法
·注意:
1)如果不存在继承关系,ClassName后面的"(bases)"可以不提供
2)类文档为可选
2,class语句的一般形式
·class ClassName(bases):
1)data = value → 定义数据属性
2)def method(self,…): → 定义方法属性
·self.member = value
创建类:例如
class TestClass():
pass
将类转为实例:例如
obj1 = TestClass()
也就是说将类对象赋值传递给一个参数,进行实例化
Python中,class语句类似def ,是可执行代码;直到运行clas语句后类才会存在
>>> class FirstClass:
spam = 30 类数据属性
def display(self): 类方法,属于可调用的属性
print self.spam
>>> x = FirstClass()
>>> x.display() 方法调用
30
如下例子:
In [28]: class thirdclass():
…: data = ‘hello ThirdClass’
…: def setdata(self,x):
…: self.str1 = x
…: print self.str1
…: def printdata(self):
…: print self.str1
…:
需要 test = thirdclass()
test.setdata() 赋值
然后输出test.printdata、test.setdata,test.str1才能正常输出
Python类方法及调用
1,实例(对象)通常包含属性
·可调用的属性:方法
object.method()
·数据属性
在OOP中,实例就像是带有"数据"的记录,而类是处理这些记录的"程序"
2,通过实例调用方法相当于调用所属类的方法来处理当前实例
·类似instance.method(args…)会被自动转换为
class.method(instance,args…)
1)如前面的例子,x.display()会被自动转换为FirstClass.display(x),即调用类的方法来处理实例x
3,因此,类中每个方法必须具有self参数,它隐含当前实例之意
4,在方法内对self属性做赋值运算会产生每个实例自己的属性
5,Python规定,没有实例,方法不允许被调用,此即为"绑定"
Python类和实例的属性
1,class语句中的赋值语句会创建类属性,如前面例子中的spam
2, 在类方法中对传给方法的特殊参数self进行赋值会创建实例属性
Python构造器
1,创建实例时,Python会自动调用类中的_init_方法,以隐形地为实例提供属性
2,如果类中没有定义_init_方法,实例创建之初仅是一个简单的名称空间
例如:
>>> class Myclass():
gender = 'Male'
def _init_(self,who):
self.name = who
>>> x = Myclass('Tom')
>>> y = Myclass('jerry')
>>> x.gender,x.name
('Male','tom')
>>> y.gender,y.name
('Male','jerry')
也就是说Python构造器,可以直接通过类进行赋值,而不需要从def 定义的参数先赋值后,在进行调用!
Python 析构器(解构器)
def def(self):
类的特殊属性
1,可以使用类的_dict_字典属性或Python内置的dir()函数来获取类的属性
dir(MyClass)
[‘doc’,‘init’,‘module’,‘gender’]MyClass.dict
C.name 类C 的名字(字符串)
C.doc 类C 的文档字符串
C.bases 类C 的所有父类构成的元组
C.dict 类C 的属性
C.module 类C 定义所在的模块(1.5版本新增)
C.class 实例C 对应的类(仅新式类中)
实例属性
1,实例仅拥有数据属性(严格意义上来说,方法是类属性)
·通常通过构造器"init"为实例提供属性
·这些数据属性独立于其它实例或类
·实例释放事时,其属性也将被清除
2,内建函数dir()或实例的特殊属性__dict__可用于查看实例属性
3,实例的特殊属性
Python类方法中可用的变量
1,方法的可用变量
·实例变量:指定变量名称及实例自身进行引用
self.变量名
self.name = who 实例变量
2,局部变量:方法内部创建的变量,可直接使用
def print(self) 为局部变量
3,类变量(也称静态变量):通过指定变量名与类名进行引用
类名。变量名
gender = ‘Male’ 类变量
4,全局变量:直接使用
In [58]: class c1():
…: d1 = ‘hello c1 class’
…: def init(self,x):
…: self.insdata = x
例子:
i1 = c1(50)
i1.d1 输出值 hello c1 class
i1.insdata 输出值 50
i2 = c1(100)
i2.d1 输出值 hello c1 class
i2.insdata 输出值 100
i1.d1 = 'heihei' 那么i1的调用变量的存储位置改变
i1.d1 输出值 heihei
而i2.d1 输出值 hello c1 class
c1.d1 = 'how old are you'
i1.d1 输出值 heihei
i2.d1 输出值 how old are you
继承
继承描述了基类的属性如何"遗传"给派生类
1,子类可以继承它的基类的任何属性,包括数据属性和方法
2,一个未指定基类的类,其默认有一个名为object的基类
3,Python 允许多重继承
创建子类
1,创建子类时,只需要在类名后跟一个或从其中派生的父类
2,class SubClassName(ParentClass1[,ParentClass2,…])
·‘optional class documentation string’
·class_suite
写法如下:
class parent(object):
gender = ‘Male’
def init(self,who):
self.name = who
class CClass(parent):
def displayInfo(self,who):
print self.gender,self.name
Python 类的继承和属性搜索
Python 中几乎所有属性的获取都可以使用"object.attribute(对象.属性)"的格式
1,不过,此表达式会在Python中启动搜索–搜索连续的树
class 语句会产生一个类对象,对class的调用会创建实例,实例自动连接至创建了这些实例的类
2,类连结至其超类的方式
·将超类列在类头部的括号内,其从左至右的顺序会决定树中的次序
·由下至上,由左至右
继承方法专用化
1,继承会先在子类寻找变量名,然后才查找超类,因此,子类可以对超类的属性重新定义来取代继承而来的行为
·子类可以完全取代从超类继承而来的属性
·也可以通过已覆盖的方法回调超类来扩展超类的方法
1)子类对超类的属性重新定义来取代继承而来的属性
例如
>>>class ParClass(object):
def setInfo(self,sex='Male'):
self.gender = sex
>>>class ChiClass(ParClass):
def setInfo(self,who):
self.name = who
因为子类中用相同的方法定义了setInfo,所以从而覆盖了父类的setInfo。
y = ParClass()
y.setInfo('Tom')
y.gender 输出 Tom
此种方法是可以进行对父类进行调用的!
2)通过已覆盖的方法回调超类来扩展超类的方法
例如
>>>class ParClass(object):
def setInfo(self,sex='Male'):
self.gender = sex
>>>class ChiClass(ParClass):
def setInfo(self,who):
self.name = who
ParClass.setInfo(self)
其中ParClass.setInfo 是对父类(超类)进行了回调,或者说来扩展超类!
类、实例和其它对象的内建函数
1,issubclass()
·布尔函数,判断一个类是否由另一个类派生(子类),语法:
issubclass(sub,sup)
2,isinstance()
·布尔函数,判断一个对象是否是给定类的实例,语法:
isinstance(obj1,class_obj2)
3,hasattr()
·布尔函数,判断一个对象是否拥有指定的属性,语法:
hasattr(obj,‘attr’)
·同类函数还有getattr(),setattr()和delattr()
4,super()
·在子类中找出其父类以便于调用其属性
·一般情况下仅能采用非绑定方式调用祖先类方法
·而super()可用于传入实例或类型对象,语法:
super(type[,obj])
运算符重载
运算符重载是指在方法中拦截内置的操作–当类的实例出现在内置操作中,Python会自动调用自定义的方法,并且返回自定义方法的操作结果
1,运算符重载让类拦截常规的Python运算
·类可重载所有Python表达式运算符
·类也可重载打印,函数调用,属性点号运算等内置运算
2,重载使类实例的行为像内置类型。
3,重载通过提供特殊名称的类方法实现。
运算符重载并非必需,并且通常也不是默认的
基于特殊的方法定制类
除了__init__和__del__之外,Python类支持使用许多的特殊方法
1,特殊方法都以双下划线开头和结尾,有些特殊方法有默认行为,没有默认行为的是为了留到需要的时候再实现
2,这些特殊方法是Python中用来扩充类的强大工具,它们可以实现
·模拟标准类型
·重载操作符
3,特殊方法允许类通过重载标准操作符+,*,甚至包括分段下标及映射操作[]来模拟标准类型