您的位置:首页 > 编程语言 > Python开发

python 第13章:面向对象编程

2016-11-15 18:40 246 查看
1. 类是对象的定义,而实例是“真正的产物”,它存放了类中所定义的对象的具体信息

方法:方法为类的属性,除了静态方法以外,方法必须由实例调用

self参数:它在所有的声明中都存在,代表实例本身,方法的调用通过self关联到类里

创建实例:靠继承来进行子类化是创建和定制新型类型的一种方式,新的类将保持已存在类所有的属性,不会影响到原来的类

2.面向对象编程

常用术语: 封装/接口:描述了对数据/信息进行隐藏的观念,它对数据属性提供接口和访问函数。

多态:多态的概念指出了对象如何通过他们共同的属性和动作来操作及访问,而不需要考虑他们的类。多态表明了动态绑定的存在,允许重载及运行时类型确定和验证

4.类

类属性:属性就是属于另一个对象的数据或者函数元素,可以通过我们熟悉的句点属性标识法来访问

4.1·类的数据属性

数据属性仅仅是所定义的类的变量。静态成员通常用来跟踪与类相关的值,大多数情况下,你会考虑用实例属性,而不是类属性。

4.2Methods

方法仅仅是一个作为类定义一部分定义的函数(这使得方法成为类属性),并且只能通过实例来调用(我并没有把静态方法和类方法当作方法,仅仅认为它们只是函数---独立于类对象)

4.3查看类的属性

dir(myclass) myclass.__dict__

13.5实例

13.5.1 初始化:通过调用类对象来创建实例

13.5.2__init__() 构造器方法

类被调用,实例化的第一步是创建实例对象。一旦对象创建了,python检查是否实现了__init__()方法、若没有:对实例不会施加特别的操作。

13.5.3__new__()构造器方法

实例化不可变对象

13.5.4__del__()解构器方法

python 具有垃圾回收机制,这个函数直到所有的引用都被清除掉后才会执行

13.6实例属性

设置实例的属性可以在实例创建后任意时间进行,也可以在能够访问实例的代码中进行。构造器__init()__是设置这些属性的关键点之一

能够在“运行时”创建实例属性,是python类的优秀特性之一。缺点是:属性在条件语句中创建,如果该条件语句块并未被执行,属性也就不存在。

__int__()不应该返回任何对象(应当为none)

13.6.2 查看实例属性

dir() __dict__ __class__

13.6.5 实例属性VS类属性

类属性可通过类或实例来访问。当然,通过实例访问一个类属性时,只是建立一个临时的类属性引用,当实例消失后,对应的类属性也消失

不推荐使用实例来访问类属性。虽然方法也被称为类属性,但方法特殊就特殊在于:它通过self参数绑定到了实例对象去了,所以方法通常要用到实例来调用,用类调用不行-----原因也挺简单的,方法中操作的是实例数据,一般很少操作类数据属性,所以要用实例来调用。

13.7 绑定和类调用

方法三要点:·1.方法仅仅是类内部定义的函数

2.方法只有在其属性拥有实例的时候,才能被调用

3.任何方法定义的第一个参数都是变量self

13.7.1调用绑定方法

通过实例来调用

13.7.2调用非绑定方法

继承时构造器的实现是调用非 绑定方法

13.8静态方法和类方法

并不推荐使用静态方法,一般来说,我们可以使用模块函数来达到目的。

13.9组合

让不同的类混合并加入其他类中去

13.10子类和派生

设计相同的类,但是有一些不同的功能的时候,派生是一种更好的方法

OOP的更强大的功能体现在能够使用一个已经定义好的类,扩展它或者对他进行修改,而不会影响系统中使用现存类的其他代码片段。

13.11继承

13.11.4多重继承

python允许子类继承多个基类,这种特性就是通常所说的多重继承。

在python2.2以前的版本,算法非常简单:深度优先,从左至右进行搜索,取得在子类中使用的属性。

新式类,广度优先,从左至右。

新式类有一个__mro__属性,告诉你查找顺序。

13.12.类、实例和其他对象的内建函数

13.12.1 issubclass()

issubclass()布尔函数判断一个类是另一个类的子类或者子孙类

issubclass(sub,sup)

13.12.2 isinstance()

isinstance()布尔函数判定一个对象是否是另一个给定类的实例

isinstance(obj1,obj2)

13.12.3 hasattr() getattr() setattr() delattr()

hasattr()函数是boolean型的,它的目的就是为了决定一个对象是否有一个特定的属性,一般用于访问某属性前先做一个检查。

getattr()和setattr()函数相应的取得和赋值给对象的属性,getattr()会在你试图读取一个不存在的属性时,引发AttributeError异常,

除非给出那个可选的默认参数。setattr()将要么加入一个新的属性,要么取代一个已存在的属性。而delattr()函数会从一个对象中删除属性。

13.12.4 dir()

dir()列出一个模块所有属性的信息

13.12.5 super()

super()函数的目的就是找出相应的父类。

13.12.6 vars()

vars内建函数与dir()相似,只是给定的对象参数必须要有一个__dict()__的属性

13.16新式类的高级特性

13.16.3 特殊方法__getattribute__()

python类有一个名为__getattr__()的特殊方法,它仅当属性不能在实例的__dict__或它的类(类的__dict__),或者祖先类(其__dict__)中找到时,才被调用。

__getattribute__的作用是:当属性被访问时,它就一直都可以被调用,而不局限于不能找到的情况。

13.16.5

元类可以认为元类的实例是类,元类一般用于创建类(类工厂)

__metaclass__属性:如果类中有__metaclass__属性就用来创建类,没有就在父类中查找

13.18练习

13-1 程序设计。请列举一些面向对象编程与传统旧的程序设计形式相比的先进之处。

易维护,增加代码重复利用率,效率高、易扩展

13-2函数和方法的比较。函数和方法之间的区别是什么?

函数是一段代码。通过名字调用,它能将一些数据传递进去进行处理,然后返回一些数据。也可以

没有返回值

方法也是一段代码,也通过名字来调用,但它跟一个对象相关联,方法和函数大致上是相同的,但有2个主要的不同

之处:

1.方法中的数据是隐式传递的

2.方法可以操作类内部的数据

13-3

13-3. 对类进行定制。写一个类,用来将浮点数值转换为金额。在本练习里,我们使用美国货币,但读者也可以自选任意货币。
基本任务: 编写一个dollarize()函数,它以一个浮点数值作为输入,返回一个字符串形式的金额数。比如说:dollarize(1234567.8901) ==> ‘$1,234,567.89.dollarize()返回的金额数里应该允许有逗号(比如1,000,000),和美元的货币符号。如果有负号,它必须出现在美元符号的左边。完成这项工作后,你就可以把它转换成一个有用的类,名为MoneyFmt。

#-*-coding:utf-8-*-
class MoneyFmt(object):
def __init__(self, value=0.0):
self.value=float(value)
def update(self, value=None):
self.value = float(value)
def __str__(self):
if self.value>0:
sign = '$'
else:
sign = '-$'
return sign + str(round(abs(self.value), 2))
def __repr__(self):
return repr(self.value)
def __nonzero__(self):
return self.value!=0

cash = MoneyFmt(1234567.8901)
print cash

13-4 用户注册。建立一个用户数据库(包括登录名、密码和上次登录时间戳)类(参考练习7-5和9-12),来管理一个系统,该系统要

求用户在登录后才能访问某些资源。这个数据库类对用户进行管理,并在实例化操作时加载之前保存的用户信息,提供访问函数来添加或更新数据库的信息。在数据修改后,数据库会在垃圾回收时将新信息保存到磁盘。

import shelve
import os
import time

class UserData(object):
def __init__(self,dbfile):
self.db={}
if os.path.exists(dbfile):
self.db=shelve.open(dbfile,'r')
self.dbfile=dbfile
def __del__(self):
data = shelve.open(self.dbfile,'c')
data.update(self.db)
data.close()
def update(self,name,password):
self.db[name] = [password,time.time()]
def delete(self,name):
self.db.pop(name)
def login(self,name,password):
if self.db.get(name,none)[0]==password:
self.db[name][1]=time.time()
return True
else:
return False
def listall(self):
for name in self.db:
print name,self.db[name][0],time.ctime(self.db[name][1])

13-5几何. 创建一个由有序数值对(x, y) 组成的Point 类,它代表某个点的X 坐标和Y 坐标。X 坐标和Y 坐标在实例化时被传递给构造器,如果没有给出它们的值,则默认为坐标的原点。

#-*-coding:utf-8-*-
class Point(object):
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def __str__(self):
return "(%d,%d)" %(self.x,self.y)

__repr__=__str__

m=Point(4,5)
print m

13-6. 几何. 创建一个直线/直线段类。除主要的数据属性:一对坐标值(参见上一个练习)外,它还具有长度和斜线属性。你需要覆盖__repr__()方法(如果需要的话,还有__str__()方法),使得
代表那条直线(或直线段)的字符串表示形式是由一对元组构成的元组,即,((x1, y1), (x2, y2)).

#-*-coding:utf-8-*-
import math
class Point(object):
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def __str__(self):
return "(%d,%d)" %(self.x,self.y)

__repr__=__str__

class Line(object):
def __init__(self,x1=0,y1=0,x2=0,y2=0):
self.p1=Point(x1,y1)
self.p2=Point(x2,y2)
def __str__(self):
return"(%s,%s)" %(str(self.p1),str(self.p2))
def slope(self):
k=(self.p1.y-self.p2.y)/(self.p1.x-self.p2.x)
return k
def length(self):
l=math.sqrt((self.p1.y-self.p2.y)**2+(self.p1.x-self.p2.x)**2)
return l

m=Line(2,3,4,5)
print m
print m.slope()
print m.length()


13-7数据类。提供一个time 模块的接口,允许用户按照自己给定时间的格式,比如:“MM/DD/YY,” “MM/DD/YYYY,” “DD/MM/YY,” “DD/MM/ YYYY,” “Mon DD, YYYY,” 或是标准
的Unix 日期格式:“Day Mon DD, HH:MM:SS YYYY” 来查看日期。你的类应该维护一个日期值,并用给定的时间创建一个实例。如果没有给出时间值,程序执行时会默认采用当前的系统时间。还包
括另外一些方法:update() 按给定时间或是默认的当前系统时间修改数据值 display() 以代表时间格式的字符串做参数,并按照给定时间的格式显示:
'MDY' ==> MM/DD/YY
'MDYY' ==> MM/DD/YYYY
'DMY' ==> DD/MM/YY
'DMYY' ==> DD/MM/YYYY
'MODYY' ==> Mon DD, YYYY

import time

class TimeFmt(object):

def __init__(self, time=time.time()):
self.__time = time

def update(self, time=time.time()):
self.__time = time

def display(self, fmt=None):
fmtdb = {}
fmtdb['MDY'] = '%m/%d/%y'
fmtdb['MDYY'] = '%m/%d/%Y'
fmtdb['DMY'] = '%d/%m/%y'
fmtdb['DMYY'] = '%d/%m/%Y'
fmtdb['MODYY'] = '%m %d, %Y'
if fmt in fmtdb:
t = time.localtime(self.__time)
print time.strftime(fmtdb[fmt], t)
else:
print time.ctime(self.__time)

13-8 实现一个堆栈类,类中应该有push()和pop()方法,还有一个isempty()方法,如果堆栈是空的,返回布尔值1,否则返回0。

class stack(object):
def __init__(self):
self.ls=[]
def push(self,i):
self.ls.append(i)
def pop(self):
if not self.isempty():
self.ls.pop()
def isempty(self):
return len(self.ls)==0
def peek(self):
return self.ls[-1]
def __str__(self):
return str(self.ls)
__repr__=__str__
sta=stack()
sta.push(1)
sta.push(3)
print sta
sta.pop()
print sta
sta.push(5)
print sta
print sta.peek()

13-9.队列类。实现一个队列类,这个类必须支持下面几种方法:enqueue()在队列的尾部加入一个新的元素,dequeue()在队列的头部取出一个元素,返回它并且把它从列表中删除。\

#-*-coding:utf-8-*-
class queue(object):
def __init__(self):
self.ls=[]
def __str__(self):
return str(self.ls)
def enqueue(self,i):
self.ls.append(i)
def dequeue(self):
self.ls.pop(0)

QE=queue()
QE.enqueue(5)
QE.enqueue(7)
print QE
QE.dequeue()
print QE

13-10堆栈和队列。编写一个类,定义一个能够同时具有堆栈(FIFO)和队列(LIFO)操作行为的数据结构。这个类和Perl 语言中数组相像。需要实现四个方法:
shift() 返回并删除列表中的第一个元素,类似于前面的dequeue()函数。
unshift() 在列表的头部"压入"一个新元素
push() 在列表的尾部加上一个新元素,类似于前面的enqueue()和push()方法。
pop() 返回并删除列表中的最后一个元素,与前面的pop()方法完全一样。

按照13-8和13-9做就行
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: