首页 > 代码库 > python之基础篇(七)——类与面向对象
python之基础篇(七)——类与面向对象
防伪码:忘情公子著
面向对象编程(OOP)
程序 = 指令+数据
代码可以选择以指令为核心或以数据为核心进行编写。
两种范型:
以指令为核心:围绕“正在发生什么”进行编写
面向过程编程:程序具有一系列线性步骤。主体思想是代码作用于数据
以数据为核心:围绕“将影响谁”进行编写
面向对象编程(OOP):围绕数据及为数据严格定义的接口来组织程序,用数据控制对代码的访问
面向对象的核心概念
所有编程语言的最终目的都是提供一种抽象方法。
在机器模型("解空间"与"方案空间")与实际解决的问题模型("问题空间")之间,程序员必须建立一种联系。
面向过程:程序=算法+数据结构
面向对象:将问题空间中的元素以及它们在解空间中的表示物抽象为对象,并允许通过问题来描述问题而不是方案
可以把对象(实例)想象成一种新型变量,它保存着数据,但可以对自身的数据执行操作。
任何一个对象,其内部所能够施加的操作是特定的,是程序员事先定义好的,而这就称为数据的访问接口。
类型由状态集合(数据)和转换这些状态的操作集合组成。
类抽象:
类:定义了被多个同一类型对象共享的结构和行为(数据和代码)
类的数据和代码:即类的成员
数据:成员变量或实例变量
成员方法:简称为方法,是操作数据的代码,用于定义如何使用成员变量,因此一个类的行为和接口是通过方法来定义的
方法和变量:
私有:内部使用
公共:外部可见
类是抽象的,实例是具体的。
面向对象的程序设计方法
所有东西都是对象。
程序是一大堆对象的组合:
通过消息传递,各对象知道自己该做什么
消息:即调用请求,它调用的是从属于目标对象的一个方法
每个对象都有自己的存储空间,并可容纳其它对象。
通过封装现有对象,可以制作成新型对象。
每个对象都属于某一类型:
类型,也即类;
对象是类的实例;
类的一个重要特性为"能发什么样的消息给它"
同一个类的所有对象都能接收相同的消息。
对象的接口:
定义一个类后,可以根据需要实例化出多个对象。
如何利用对象完成真正有用的工作?
必须有一种办法能向对象发出请求,令其做一些事情。也就是方法函数
每个对象仅能接受特定的请求
能向对象发送的请求由其"接口"进行定义
对象的"类型"或"类"则规定了它的接口形式
类:将同一种具体的物事的共同特性抽象出来的表现
由状态和转换这些状态的操作组成
数据:变量,就是属性
方法:函数,操作变量引用的数据的代码
方法是类的组成部分,由类进行定义。数据,也就是属性也是由类进行定义的,但数据本身是在类被实例化成对象时由变量赋值得来的。
类间关系:
依赖("uses-a")
一个类的方法操纵另一个类的对象
聚合("has-a")
类A的对象包含类B的对象
继承("is-a")
描述特殊与一般关系
面向对象编程的原则
面向对象的模型机制有3个原则:封装、继承及多态
封装(Encapsulation)
隐藏实现方案细节
将代码及其处理的数据绑定在一起的一种编程机制,用于保证程序和数据不受外部干扰且不会被误用
继承(Inheritance)
一个对象获得另一个对象属性的过程就叫继承,用于实现按层分类的概念
一个深度继承的子类继承了类层次中它的每个祖先的所有属性
超类、基类、父类
子类、派生类
多态(Polymorphism)
允许一个接口被多个通用的类动作使用的特性,具体使用哪个动作与应用场合相关
"一个接口,多个方法"
用于为一组相关的动作设计一个通用的接口,以降低程序复杂性
为了实现同一个目的而定义的同一个接口,但背后却有多种不同的实现,能够自动判断调用哪一种实现的机制就称为多态。
In [1]: def plus(x,y): ...: print x + y ...: In [2]: plus(1,2) 3 In [3]: plus(‘abc‘,‘def‘) abcdef In [4]: plus([‘a‘,‘b‘],[‘c‘,‘d‘,‘e‘]) [‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘]
当x和y是数字时,实现的是两数字相加,得到的结果是它们之和;
当x和y是字符串时,实现的是字符串相连接;
当x和y是列表时,实现的是全并两个列表的元素
python类和实例
类是一种数据结构,可用于创建实例。
一般情况下,类封装了数据和可用于该数据的方法。
python类是一个可调用对象,即类对象。
python2.2之后,类是一种自定义类型,而实例则是声明某个自定义类型的变量。
实例初始化:
通过调用类来创建实例
instance = ClassName(args...)
类在实例化时可以使用__init__和__del__两个特殊的方法。
类定义的注意项:
定义类时会在内存中生成一个以类名为名的对象;
定义类时类中的代码并不会执行,只有当实例化成对象时才会被执行;
类被实例化成对象时方法也不会被执行,只有在对实例去调用这些方法时方法才会被执行
类包含两种对象:
类对象,类本身就是一种对象,是一种可以被调用的对象
实例对象:实例对象是实例化类而生成的对象。只能调用实例中的方法
python中创建类:
python使用class关键字创建类,语法格式如下:
class ClassName(bases): ‘class documentation string‘ class_suite
超类或基类(bases)是一个或多个用于继承的父类的集合。
类体可以包含:声明语句、类成员定义、数据属性、方法。
注意:
如果不存在继承关系,ClassName后面的"(bases)"可以不提供
类文档为可选
class语句的一般形式:
class ClassName(bases): data = value #定义类属性 def method(self,...): #定义类方法 self.member = value #定义实例属性
python中,class语句类似def,是可执行代码。直到运行class语句后类才会存在。
class语句内,任何赋值语句都会创建类属性。
每个实例对象都会继承类的属性并获得自己的名称空间。
python类方法及调用:
实例(对象)通常包含属性。
可调用的属性:方法
object.method()
数据属性
在面向对象编程(OOP)中,实例就像是带有"数据"的记录,而类是处理这些记录的"程序"。
通过实例调用方法相当于调用所属类的方法来处理当前实例。
类似instance.method(args...)会被自动转换为class.method(instance,args...)
因此,类中每个方法必须具有self参数,它隐含当前实例之意。
在方法内对self属性做赋值运算会产生每个实例自己的属性。
python规定,没有实例,方法不允许被调用,此即为"绑定"。
python类和实例的属性:
class语句中的赋值语句会创建类属性。
在类方法中对传给方法的特殊参数self进行赋值会创建实例属性
python构造器:
创建实例时,python会自动调用类中的__init__方法,以隐性地为实例提供属性。
__init__方法被称为构造器
如果类中没有定义__init__方法,实例创建之初仅是一个简单的名称空间
使用类的__dict__字典属性或python内置的dir()函数来获取类的属性。可以查看类所包含的属性和方法。
类的特殊属性:
C.__name__:类C的名字(字符串)
C.__doc__:类C的文档字符串
C.__bases__:类C的所有父类构成的元组
C.__dict__:类C的属性
C.__module__:类C定义所在的模块
C.__class__:实例C对应的类(仅新式类中)
实例属性:
实例仅拥有数据属性(严格意义上来说,方法是类属性)
通常通过构造器"__init__"为实例提供属性
这些数据属性独立于其它实例或类
实例释放时,其属性也将被清除
内建函数dir()或实例的特殊属性__dict__可用于查看实例属性
实例的特殊属性:
I.__class__:实例化I的类
I.__dict__:I的属性
python类方法中可用的变量:
方法的可用变量
实例变量:指定变量名称及实例自身进行引用
self.变量名
局部变量:方法内部创建的变量,可直接使用
类变量(也称静态变量):通过指定变量名与类名进行引用。对类变量的引用更改将影响所有实例对象
类名.变量名
全局变量:直接使用
python类的继承:
继承描述了基类的属性如何"遗传"给派生类。
子类可以继承它的基类的任何属性,包括数据属性和方法。
In [6]: class ParentClass(object): ...: ‘Parent Class‘ ...: gender = ‘Male‘ ...: def SetName(self,who): ...: self.name = who ...: In [7]: class ChildClass(ParentClass): ...: ‘ChildClass‘ ...: def DisplayInfo(self): ...: print self.gender,self.name ...: In [8]: x = ChildClass() In [9]: x.SetName(‘tom‘) In [10]: x.DisplayInfo() Male tom In [11]: dir(ParentClass) Out[11]: [‘SetName‘, ‘__class__‘, ‘__delattr__‘, ‘__dict__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘, ‘__hash__‘, ‘__init__‘, ‘__module__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘gender‘] In [12]: dir(ChildClass) Out[12]: [‘DisplayInfo‘, ‘SetName‘, ‘__class__‘, ‘__delattr__‘, ‘__dict__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘, ‘__hash__‘, ‘__init__‘, ‘__module__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘gender‘]
一个未指定基类的类,其默认有一个名为object的基类。
python允许多重继承。
创建子类:
创建子类时,只需要在类名后跟一个或多个从其中派生的父类
class SubClassName(ParentClass1 [, ParentClass2, ...]) ‘optional class documentation string‘ class_suite
python类的继承和属性搜索方式:
python中几乎所有属性的获取都可以用"object.attribute"的格式,不过此表达式会在python中启动搜索——搜索连续的树
class语句会产生一个类对象,对class的调用会创建实例,实例自动连结至创建了此实例的一个或多个类
类连结至其超类的方式
将超类列在类头部的括号内,其从左至右的顺序会决定树中的次序
由下至上,由左至右
继承方法专用化:
继承会先在子类寻找变量名,然后才查找超类,因此,子类可以对超类的属性重新定义来取代继承而来的行为
子类可以完全取代从超类继承而来的属性
也可以通过已覆盖的方法回调超类来扩展超类的方法
类、实例和其它对象的内建函数
issubclass()
布尔函数,判断一个类是否由另一个类派生,语法:
issubclass(sub,sup)
isinstance()
布尔函数,判断一个对象是否是给定类的实例,语法:
isinstance(obj1,class_obj2)
hasattr()
布尔函数,判断一个对象是否拥有指定的属性,语法:
hasattr(obj,‘attr‘)
同类的函数还有getattr()、setattr()和delattr()
super()
在子类中找出其父类以便于调用其属性
一般情况下仅能采用非绑定方式调用祖先类方法
而super()可用于传入实例或类型对象,语法:
super(type [, obj])
基于特殊的方法定制类:
除了__init__和__del__之外,python类支持使用许多的特殊方法。
特殊方法都以双下划线开头和结尾,有些特殊方法有默认行为,没有默认行为的是为了留到需要时再实现
这些特殊方法是python中用来扩充类的强大工具,它们可以实现:
模拟标准类型
重载操作符
特殊方法允许类通过重载标准操作符+、*,甚至包括分段下标及映射操作[]来模拟标准类型。
运算符重载:
运算符重载是指在方法中拦截内置的操作——当类的实例出现在内置操作中,python会自动调用自定义的方法,并且返回自定义方法的操作结果。
运算符重载让类拦截常规的python运算
类可重载所有python表达式运算符
类也可重载打印、函数调用、属性点号运算等内置运算
重载使类实例的行为像内置类型
重载通过提供特殊名称的类方法实现
常见的运算符重载方法有以下这些:
方法 | 重载 | 调用 |
__init__ | 构造函数 | 对象建立:X = Class(args) |
__del__ | 析构函数 | X对象收回 |
__add__ | 运算符+ | 如果没有_iadd_,X + Y,X += Y |
__or__ | 运算符| | 如果没有__ior__,X | Y,X |= Y |
__repr_,__str__ | 打印,转换 | print(x)、repr(x)、str(x) |
__call__ | 函数调用 | X(*args,**kargs) |
__getattr__ | 点号运算 | X.undefined |
__setattr__ | 属性赋值语句 | X.any = value |
__delattr__ | 属性删除 | del X.any |
__getattribute__ | 属性获取 | X.any |
__getitem__ | 索引运算 | x[key],x[i:j],没__iter__时的for循环和其他迭代器 |
__setitem__ | 索引赋值语句 | x[key] = value,x[i:j] = sequence |
__delitem__ | 索引和分片删除 | del x[key],del x[i:j] |
__len__ | 长度 | len(x),如果没有__bool__,真值测试 |
__bool__ | 布尔测试 | bool(x),真测试(在python2.6中叫做__nonzero__) |
__lt__,__gt__, __le__,__ge__, __eq__,__ne__ | 特定的比较 | x < y,x > y, x <= y,x >= y, x == y,x != y(在python2.6中只有__cmp__) |
__radd__ | 右侧加法 | Other + x |
__iadd__ | 实地(增强的)加法 | x += y (or else __add__) |
__iter__,__next__ | 迭代环境 | I=iter(x),next(I);for loops,in if no __contains__,all comprehensions,map(E,X),其他(__next__在python2.6中称为next) |
__contains__ | 成员关系测试 | item in x(任何可迭代的) |
__index__ | 整数值 | hex(x),bin(x),oct(x),0[x],0[x:](替代python2中的__oct__、__hex__) |
__enter__,__exit__ | 环境管理器 | with obj as var: |
__get__,__set__, __delete__ | 描述符属性 | x.attr,x.attr = value,del x.attr |
__new__ | 创建 | 在__init__之前创建对象 |
python中的可调用对象
python中的可调用对象有三种:__call__()
函数
内置函数
自定义函数
def
lambda
类
类方法
方法是在类中定义的函数,这些函数通常以self为第一个参数,而且必须有这个参数。所以说它是一种特殊的可调用对象。
方法有三种:
实例方法:通过实例调用的方法,也称作绑定方法
类方法:把类本身当做一个对象进行操作的方法,也称作非绑定方法
静态方法:打包在类中的函数,它不能使得一个实例或者类作为对象作为定义参数。这种方法只能由类自己使用。
函数的属性:
__doc__:函数文档
__name__:函数名
__dict__:属性字典,返回此函数所支持的属性、方法列表
__code__:字节编译以后的代码
__globals__:全局命名空间的字典
内置函数的属性:
__doc__:内置函数文档
__name__:内置函数名
__self__:调用此内置函数的实例
方法的属性:
__doc__:方法文档
__name__:方法名
__class__:方法所属的类
__func__:实现该方法的函数对象
__self__:调用此方法的实例
类的属性:
__doc__:类文档
__name__:类名
__bases__:基类
__dict__:属性字典,返回此类所支持的属性、方法列表
__module__:定义了当前类的模块名称
实例的属性:
__class__:创建此实例的类
__dict__:属性字典,返回了此实例所支持的属性、方法列表
本文出自 “忘情居” 博客,请务必保留此出处http://itchentao.blog.51cto.com/5168625/1888859
python之基础篇(七)——类与面向对象