设为首页 收藏本站
查看: 1465|回复: 0

[经验分享] Python数据结构与算法--面向对象

[复制链接]

尚未签到

发表于 2015-4-20 06:28:49 | 显示全部楼层 |阅读模式
  前面已经讲过,Python是一种面向对象的编程语言. 面向对象编程语言中最重要的特征是允许程序员创建类建立数据模型来解决问题.
  我们之前利用抽象数据类型提供的逻辑来描述数据对象 (它的状态) 和功能 (它的方法). 通过构建类来实现抽象数据类型, 一个程序员可以发挥抽象处理的优势,同时提供详细的现实信息来解决问题.当我们想实现一个抽象数据类型的时候,我们将构建一个新的类.
  本文地址:http://www.iyunv.com/archimedes/p/python-datastruct-algorithm-class.html,转载请注明源地址。



一个分数类
  下面来看一个非常普通的例子,用来展示实现抽象数据类型的一个用户自定义类:Fraction(分数). 我们已经知道 Python 给我们提供了大量的类. 有很多可以适当地帮我们构建分数类型的数据对象.
  一个分数比如3/5包含两部分. 分子,可以为任何整数. 分母, 可以为除了0以外的任何整数.
  Fraction 类的方法应该能够让 Fraction 对象可以像其他的数值那样进行计算. 我们需要可以进行分数之间的 加, 减, 乘, 和 除 运算. 更进一步, 所有的方法应该返回最简分数.
  在 Python中, 我们定义一个类的名字还有一些方法,类似于定义一个函数,例如,







class Fraction:
#the methods go here
  提供了给我们定义方法的框架.第一个方法是所有类都要提供的构造器. 构造函数定义了类创建的方式. 要创建分数对象, 我们需要提供两部分的数据:分子和分母. 在 Python中, 构造函数使用 __init__ (两条下划线包围 init) ,如下所示:
Listing 2







class Fraction:
def __init__(self,top,bottom):
self.num = top
self.den = bottom
  注意到参数列表含有三个参数: (self, top, bottom). self 是一个引用对象自身的特殊的参数. 它通常作为第一个参数; 但是, 它从不在调用的时候传值. 之前已经讲过,分数包含两部分(分子和分母). 记号 self.num 在构造函数中被定义为 fraction 对象具有一个叫num 的内部数据对象. 同理, self.den 也是类似的目的.
  要实现 Fraction 类, 我们需要调用构造函数. 接着通过类名传递参数 (注意到我们从不直接调用__init__). 例如:







myfraction = Fraction(3,5)
  创建一个分数对象 myfraction 代表分数3/5 .


DSC0000.png
接着要做的事情就是给抽象数据类型实现方法. 首先, 意识到当我们要输出一个 Fraction 对象.







>>> myf = Fraction(3,5)
>>> print(myf)

  fraction 对象, myf, 并不知道怎样响应输出操作.  print 函数需要对象转换为可输出的字符串格式,这样才能输出. 唯一的选择 myf 必须显示变量实际的地址引用(自身的地址). 这不是我们想要的.
  有两种解决问题的办法. 一种是定义一种称为 show 的方法,可以将Fraction 对象作为一个字符串的形式打印. 我们可以实现如 Listing 3所示.假如我们按照前面讲的创建 Fraction 对象, 我们可以让它输出自身, 换句话说, 打印自身按照适当的格式. 不幸的是, 这通常不起作用. 为了使输出工作正常, 我们必须告诉 Fraction 类怎样将自身转换为字符串的格式.
Listing 3







def show(self):
print(self.num,"/",self.den)
>>> myf = Fraction(3,5)
>>> myf.show()
3 / 5
>>> print(myf)

  在 Python, 所有的类都提供但不是都适用的标准的方法. 其中之一, __str__,就是一个将对象转换为字符串的方法. 这个方法默认的实现是用来以字符串格式返回类实例的地址. 我们必须为这个方法提供一个“更好的”实现. 我们说这个新的方法重载前面的, 或者说重新定义了方法的行为.
  要实现这个,我们简单地定义一个名叫 __str__ 的方法并给出实现 如Listing 4. 这个定义除了使用特殊参数 self以外不需要其他的信息. 注意函数中的不同的实现办法.
Listing 4







def __str__(self):
return str(self.num)+"/"+str(self.den)
>>> myf = Fraction(3,5)
>>> print(myf)
3/5
>>> print("I ate", myf, "of the pizza")
I ate 3/5 of the pizza
>>> myf.__str__()
'3/5'
>>> str(myf)
'3/5'
>>>
  我们可以为我们的新 Fraction 类覆盖很多其他的方法. 其中一些最重要的是一些基础的算术运算操作. 我们可以创建两种 Fraction 对象,同时使用“+” 符号将它们相加 . 这时, 如果我们使两分数相加, 我们得到:



>>> f1 = Fraction(1,4)
>>> f2 = Fraction(1,2)
>>> f1+f2
Traceback (most recent call last):
File "", line 1, in -toplevel-
f1+f2
TypeError: unsupported operand type(s) for +:
'instance' and 'instance'
  如果你仔细观察错误信息, 你将发现问题是: “+” 操作符不能理解Fraction 操作.
  我们可以通过给 Fraction 类提供重载的加法函数来实现. 在 Python, 这种方法称为 __add__ 同时需要两个参数. 第一个参数, self,  第二个参数是另一个操作数. 例如,







f1.__add__(f2)
  当 Fraction  f1 加 Fraction f2. 可以写成标准的形式:f1+f2.
  两个分数必须有相同的分母才能直接相加. 使它们分母相同最简单的方法是通分: DSC0001.jpg ,具体实现如 Listing 5. 加法函数返回了一个新的 Fraction 对象.
  Listing 5



def __add__(self,otherfraction):
newnum = self.num * otherfraction.den + self.den*otherfraction.num
newden = self.den * otherfraction.den
return Fraction(newnum,newden)


>>> f1=Fraction(1,4)
>>> f2=Fraction(1,2)
>>> f3=f1+f2
>>> print(f3)
6/8
>>>
  上面的加法函数看起来实现了我们期望的, 但是还可以更完美. 注意到 6/8 是正确的结果,但是却不是以 “最简项” 的形式展示的. 最好的表达式为3/4. 为了使我们的结果为最简项的形式, 我们需要一个辅助函数才化简分数. 这个函数可以求出最大公约数, 或者称为 GCD. 可以通过分子和分母的最大公约数来达到化简分数的目的.
  计算最大公约数最著名的算法要数 Euclid算法,原理我就不详细指明了,很简单。实现如下:



>>> def gcd(m, n):
while m % n != 0:
oldm = m
oldn = n
m = oldn
n = oldm % oldn
return n
>>> print gcd(20, 10)
10
  这样我们就可以化简任何的分数了,代码如下: (Listing 6).
  Listing 6



def __add__(self,otherfraction):
newnum = self.num*otherfraction.den + self.den*otherfraction.num
newden = self.den * otherfraction.den
common = gcd(newnum,newden)
return Fraction(newnum//common,newden//common)


>>> f1=Fraction(1,4)
>>> f2=Fraction(1,2)
>>> f3=f1+f2
>>> print(f3)
3/4
DSC0002.png
  我们的 Fraction 对象现在有两个非常重要的方法,如上图所示. 一些需要新增进我们的实例类 Fraction 的方法是:允许两个分数进行比较. 假如我们有两个 Fraction 对象, f1 和f2. f1==f2 将得到True 假如他们指向同一个对象. 即使分子分母都相同,但是不满足条件依然将不相等. 这被称为 shallow equality (如下图).
DSC0003.png
  我们可以创建 deep equality (如上图)–通过值相等来判断, 不同于引用–通过覆盖 __eq__ 方法.  __eq__ 是另一个存在于所有类中标准方法. __eq__ 方法比较两个对象当值相等的时候返回 True ,否则返回 False.
  在 Fraction 类中, 我们实现了 __eq__ 方法通过常规比较方法来比较分数 (see Listing 7). 值得注意的是还有其他的方法可以覆盖. 例如,  __le__ 方法提供了小于等于功能.
  Listing 7



def __eq__(self, other):
firstnum = self.num * other.den
secondnum = other.num * self.den
return firstnum == secondnum
  完整的 Fraction 类的代码如下所示:



def gcd(m,n):
while m%n != 0:
oldm = m
oldn = n
m = oldn
n = oldm%oldn
return n
class Fraction:
def __init__(self,top,bottom):
self.num = top
self.den = bottom
def __str__(self):
return str(self.num)+"/"+str(self.den)
def show(self):
print(self.num,"/",self.den)
def __add__(self,otherfraction):
newnum = self.num*otherfraction.den + \
self.den*otherfraction.num
newden = self.den * otherfraction.den
common = gcd(newnum,newden)
return Fraction(newnum//common,newden//common)
def __eq__(self, other):
firstnum = self.num * other.den
secondnum = other.num * self.den
return firstnum == secondnum
x = Fraction(1,2)
y = Fraction(2,3)
print(x+y)
print(x == y)
  运行结果:

7/6
False
  您还可能感兴趣:
  Python基础(10)--数字
  Python基础(9)--正则表达式
  Python基础(8)--文件
  Python基础(7)--函数
  Python基础(6)--条件、循环
  Python基础(5)--字典
  Python基础(4)--字符串
  Python基础(3)--列表和元组
  Python基础(2)--对象类型
  Python基础(1)--Python编程习惯与特点

  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-58581-1-1.html 上篇帖子: 【循序渐进学Python】11.常用标准库 下篇帖子: 谁说Python性能差的?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表