Day 09 类:面向对象的程序设计
Python其实是一种面向对象的编程(Object Oriented Programming),在Python中所有的数据类型皆是对象,当然Python也允许程序设计师自创数据类型,这种自创的数据类型就是本章的主题——类(class)。
9.0 类的定义与使用
类的定义语法如下:
class Classname() #Python风格建议类名第一个字母大写
statement1
......
statementn
9.0.1 定义类
class Banks():
"""定义银行类"""
bankname = "CCB" # 定义属性
def motto(self): # 定义方法
return "建设现代生活"
userbank = Banks() # 定义对象userbank
print("目前服务银行是 {}".format(userbank.bankname))
print("银行的服务理念是 {}".format(userbank.motto()))
目前服务银行是CCB
银行的服务理念是建设现代生活
从上述执行结果可以发现我们成功地存取了Banks类内的属性与方法。
当我们建立一个对象后,这个对象就可以像其他Python对象一样,当作列表、元组、字典或集合元素使用,也可以将此对象当作函数的参数传送,或是将此对象当作函数的回传值。
9.0.2 类的构造函数
建立类很重要的一个工作是初始化整个类,所谓的初始化类是在类内建立一个初始化方法 (method),这是一个特殊方法,当在程序内定义这个类的对象时将自动执行这个方法。初始化方法 有一个固定名称是 __ init ( )通常又将这类初始化的方法称构造函数(constructor)。在初始化的方法内可以执行—些属性变量设定。
class Banks():
"""定义银行类"""
bankname = "CCB"
def __init__(self, uname, money):
self.name = uname #name是Banks类的属性
self.balance = money #balance是Banks类的属性
def get_balace(self):
return self.balance
hungbank = Banks("hung" ,100)
print(hungbank.name.title(),"存款余额是 ", hungbank.get_balace())
Hung 存款余额是 100
上述程序第11行定义Banks类的 hungbank 对象时,Banks类会自动启动 __ init ()初始化函数,在这个定义中self是必需的,同时须放在所有参数的最前面(相当于最左边),Python在初始时会自动传入这个参数Self,代表的是类本身的对象。
在这个Banks类的__ init (self, uname, money)方法中,有另外2个参数uname和money,第11行定义Banks类的 hungbank 对象时,需要传递这两个参数分别给uname和 money
# 增加执行存款与提款功能,类建立完成后,我们随时可以使用多个对象引用这个类的属性与函数。
class Banks():
"""定义银行类"""
bankname = "CCB" # 定义属性
def __init__(self, uname, money): # 定义初始化方法
self.name = uname # 设定存款者姓名
self.balance = money # 设定所存的钱
def save_money(self,money): # 设计存款方法
self.balance += money # 执行存款
print("存款 ",money," 完成 ")
def withdraw_money(self,money): # 设计提款方法
self.balance -= money # 执行提款
print("提款 ", money, " 完成 ")
def get_balace(self): # 获得存款余额
print(self.name.title(),"目前余额: ", self.balance)
hungbank = Banks("hung" ,100) # 定义对象hungbank
johnbank = Banks("john" ,300) # 定义对象john
hungbank.get_balace() # 查询hung余额
johnbank.get_balace() # 查询john余额
hungbank.save_money(300) # hung存款300
johnbank.withdraw_money(200) # john取款200
hungbank.get_balace()
johnbank.get_balace()
Hung 目前余额: 100
John 目前余额: 300
存款 300 完成
提款 200 完成
Hung 目前余额: 400
John 目前余额: 100
9.1 类的访问权限:封装
学习了类,我们知道上述程序中的对象hung可以直接引用类内的属性,像这种类内的属性可以让外部引用的称公有(public)属性,可以让外部引用的方法称公有方法。
理论上,Python提供了私有属性与方法的概念,这个概念又称封装(encapsulation)。
9.1.1 私有属性
实际上,我们可以用语句 “ hungbank.balance =1000000 ” 在类的外部直接修改存款余额,这并没有经过Banks类内的save_money方法的存钱动作,整个余额就从0元增至1000000元!
为了确保类内的属性的安全,其实有必要限制外部无法直接获取类内的属性值;于是私有属性(private attribute)的概念产生了,应用方法是在属性名称前面增加 (两个下划线,两个下划线中间并没有空格)
# 封装
class Banks():
"""定义银行类"""
def __init__(self, uname): # 定义初始化方法
self.__name = uname # 设定存款者姓名
self.__balance = 0 # 设定开户金额0元
self.__bankname = "CCB" # 定义银行名称
def save_money(self,money): # 设计存款方法
self.__balance += money # 执行存款
print("存款 ",money," 完成 ")
def withdraw_money(self,money): # 设计提款方法
self.__balance -= money # 执行提款
print("提款 ", money, " 完成 ")
def get_balace(self): # 获得存款余额
print(self.__name.title(),"目前余额: ", self.__balance)
hungbank = Banks("hung") # 定义对象hungbank
hungbank.get_balace()
hungbank.__balance = 100000 #类外修改存款金额
hungbank.get_balace()
Hung 目前余额: 0
Hung 目前余额: 0
上述程序第22行hung尝试修改存款余额,但从输出结果可以知道修改失败,因为执行结果的存款余额是0。
但是hung是个Python高手,他知道可以用其他方式设定或取得私有属性。
对象名称._类名称__私有属性 # 即hungbank._Banks__balance
>>>hungbank._Banks__balance = 100000
>>>hungbank.get_balace()
Hung 目前余额: 100000
实质上因为私有属性可以被外界调用,所以设定私有属性名称时须格外小心。
9.1.2 私有方法
类有私有属性,也有私有方法(private method),它的概念与私有属性类似,定义时在方法前面增加_ _即可,理论上是类外的程序无法调用,实质上不排除一些像Hung的Python高手存在,类外依旧可以调用此私有方法。
最近Hung和John想来中国旅游,于是他们准备把美元换成美元RMB,但是在换汇时银行会针对客户对银行的贡献规定不同的汇率与手续费,这个部分是客户无法得知的,碰上这类应用就很适合以私有方法处理换汇程序。
#私有方法
class Banks():
"""定义银行类"""
def __init__(self, uname): # 定义初始化方法
self.__name = uname # 设定存款者姓名
self.__balance = 0 # 设定开户金额0元
self.__bankname = "CCB" # 定义银行名称
self.__rate = 7.21 # 预设美金与人名币换汇的比例
self.__service_change = 0.01# 换汇的服务费用
def save_money(self, money): # 设计存款方法
self.__balance += money # 执行存款
print("存款 ", money, " 完成 ")
def withdraw_money(self, money): # 设计提款方法
self.__balance -= money # 执行提款
print("提款 ", money, " 完成 ")
def get_balace(self): # 获得存款余额
print(self.__name.title(), "目前余额: ", self.__balance)
def usa_2_rmb(self, usa_d): # 美金换rmb的方法
self.result = self.__cal_rate(usa_d)
return self.result
def __cal_rate(self,usa_d): # 私有方法计算汇率
return int(usa_d * self.__rate*(1 - self.__service_change))
hungbank = Banks("hung")
usdallor = 100
print(usdallor," 美金可以兑换 ", hungbank.usa_2_rmb(usdallor),"RMB")
100 美金可以兑换 713 RMB
如果类外直接调用私有方法会产生错误,
>>> hungbank.__cal_rate(50)
Traceback (most recent call last):
File "C:/Users/hp-pc/Desktop/同步文件夹/30DaysPython/30DaysPython_env/Day09(Object)/Day09_object.py", line 98, in <module>
hungbank.__cal_rate(50)
AttributeError: 'Banks' object has no attribute '__cal_rate'
破解私有方法也类似破解私有属性:
>>> hungbank._Banks__cal_rate(50)
50 美金可以兑换 356 RMB
9.1.2 从存取属性值看Python风格property()
从上节学习中,我们可以了解到,封装可以通过私有属性和私有方法来保护数据,防止数据被外部强行修改。属于python风格的操作将在这一小节介绍。
新式属性 =property(getter [setter [ , fdel [ , doc ] ]])
getter是获取属性的函数,setter是设定属性的函数,fdel是删除属性值函数,doc是属性描述,
回传的是新属性,未来可以由此新属性获取私有属性的内容。
程序实例:
class Score():
def __init__(self,score):
self.__score = score
def getsscore(self):
print("inside the getscore")
return self.__score
def setscore(self,score):
print("inside the setscore")
self.__score = score
sc = property(getsscore , setscore) # Python 风格
stu = Score(0)
print(stu.sc)
stu.sc = 80
print(stu.sc)
inside the getscore
0
inside the setscore
inside the getscore
80
上述14行相等于执行getscore(),第15行相当于执行setscore()。
9.1.3 装饰器@property
延续前一节,我们可以使用装饰器@property。首先将getscore(),setscore()方法名称全部改为sc(),然后在sc()方法前加上下列装饰器:
@property:放在getter方法前
@sc.setter:放在setter方法前
程序实例
class Score():
def __init__(self,score):
self.__score = score
@property
def sc(self):
print("inside the getscore")
return self.__score
@sc.setter
def sc(self,score):
print("inside the setscore")
self.__score = score
stu1 = Score(0)
print(stu.sc)
stu1.sc = 80
print(stu.sc)
inside the getscore
0
inside the setscore
inside the getscore
80
上述只是将sc特性应用在Score类内的属性 score,其实这个概念可以扩充至一般程序设计。
9.1.4 方法与属性的类别
严格设计Python面向对象程序时,又可将类的方法分为实例方法与属性、类方法与属性。如上例stu1即类score实例化的对象。
先前所述的皆是实例方法与属性,使用时须建立此类的实例对象,然后由对象调用。实例方法与属性的特色是有self,属性开头是self,同时所有方法的第一个参数是self,这些是建立类对象时,属于对象的部分。
类方法前面则是@classmethod,所不同的是第一个参数习惯是用cls。类方法与属性不需要实例化,它们可以由类本身直接调用。另外,类属性会随时被更新。(程序应用如下)
class Counter():
counter = 0 # 类属性,可以由类本身调用
def __init__(self):
Counter.counter += 1 # 更新指标
@classmethod
def show_counter(cls): # 类方法,可以由类本身调用
print("class method")
print("counter = ",cls.counter) # 也可以用Counter.counter调用
print("counter = ",Counter.counter)
one = Counter()
two = Counter()
three = Counter()
Counter.show_counter()
"""
class method
counter = 3
counter = 3
"""
9.1.5 静态方法
静态方法是由@staticmethod开头,不需原先的self或cls参数,这只是碰巧存在类的函数,与类方法和实例方法没有绑定关系,这个方法也是由类名称直接调用。
class Pizza():
@staticmethod
def demo():
print("I like Pizza")
Pizza.demo()
I like Pizza
9.2 类的继承
如果设计了类后续发现,这些类没法满足当前新的需求,虽然可以直接修改类,但是程序会显得更复杂。也可以重新设计这些类,但是我们需要维护更多的程序。那么有没有什么高效的方式呢?
使用继承!也就是延续使用旧类,设计拥有新属性和新方法的子类继承旧类。
中被继承的类称父类(parent class)、基类(base class) 或超类(super class),继承的类称子类(child class)或衍生类(derived class)。类继承的最大优点是许多父类的公有方法或属性,在子类中不用重新设计,可以直接引用。
https://s1.ax1x.com/2023/08/29/pPdYLqg.png
方法如下:
class BaseClassName(): # 先定义父类
Base Class的内容
class DeriveClassName(BaseClassName): # 再定义子类
Derived Class的内容
9.2.1 如何获得父类的私有属性
基于保护原因,基本上类定义外是无法直接取得类内的私有属性,即使是它的子类也无法直接读取,如果真要取得可以使用return方式,回传私有属性内容。
class Banks():
"""定义银行类"""
def __init__(self):
self.__banktitle = "CCB"
def gettitle(self):
return self.__banktitle
class chonqing_banks(Banks):
# 定义CCB重庆两江分行
pass
liangjiangbank = chonqing_banks() # 定义对象CCB重庆两江分行
print("我存款的银行是:", liangjiangbank.gettitle())
我存款的银行是: CCB
子类(chonqing_banks)从父类(Banks)中获取私有属性(self.__banktitle)
9.2.2 子类与父类有相同名称的属性
如题,子类的属性与方法名称和父类重复,这种情况,Python会先找寻子类是否有这个名称,如果有则先使用,如果没有则使用父类的名称内容。
class Person():
def __init__(self,name):
self.name = name
class Teacher(Person):
def __init__(self,name):
self.name = name+ "老师"
the_man = Person("张小北")
the_teacher = Teacher("张小北")
print(the_man.name)
print(the_teacher.name)
张小北
张小北老师
上述子类与父类有相同的属性(name),但是衍生类对象将使用自己的属性
9.2.3 子类与父类有相同名称的方法
同9.2.2,Python会先找寻子类是否有这个名称,如果有则先使用,如果没有则使用父类的名称内容。
class Banks():
"""定义银行类"""
def __init__(self, uname, money): # 定义初始化方法
self.bankname = "CCB"
self.name = uname # 设定存款者姓名
self.balance = money # 设定所存的钱
self.__address = "China"
def save_money(self,money): # 设计存款方法
self.balance += money # 执行存款
print("存款 ",money," 完成 ")
def withdraw_money(self,money): # 设计提款方法
self.balance -= money # 执行提款
print("提款 ", money, " 完成 ")
def get_balace(self): # 获得存款余额
print(self.name.title(),"目前余额: ", self.balance)
def get_add(self):
return self.__address
class Chonqing_Branch(Banks):
# 定义CCB重庆两江分行
def __init__(self,uname,money):
self.bankname = "CCB - LiangjiangChonqin Branch"
self.__address = "中国重庆市黄山大道中段58号B3幢"
def get_add(self):
return self.__address
jamesbank = Banks("James",100)
print("Jame存钱的地址为:",jamesbank.get_add())
hungbank = Chonqing_Branch("Hung",100)
print("Hung存钱的地址为:",hungbank.get_add())
Jame存钱的地址为: China
Hung存钱的地址为: 中国重庆市黄山大道中段58号B3幢
我们修改了bank程序,在这个例子汇中,我们发现父类与子类均有get_add()函数(即显示银行地址函数),第20行的get_add()函数属于Banks父类,第29行 def get_add()属于子类Chonqing_Branch(重庆两江分行)。
32行实例化的是Banks父类对象,所以33行会触发20行的get_add()函数;而34行实例化的是Chonqing_Branch子类的对象,故35行出发的是29行的get_add()函数。
上述方法就是面向对象的<a id="9.2.3多型">多型(polymorphism)</a>,但是多型不一定是有父子关系的类。
9.2.4 子类引用父类的方法
子类引用父类的方法时必须要用super()
就上个例程,我们发现,如果hung想存钱,我可不可以直接在39行写下hungbank.save_money(100),帮助hung在两江分行存100元呢?此时程序会报错:
self.balance += money # 执行存款
AttributeError: 'Chonqing_Branch' object has no attribute 'balance'
很显然,此时的子类并不能直接使用父类的方法。此时我们需要使用super(),即在25行下插入super().init(uname,money)即可。
9.2.5 三代同堂的类与取得父类的属性super()
下列是一个三代同堂的程序,在这个程序中有祖父(Grandfather)类,它的子类是父亲(Father),父亲类的子类定义为Ivan类。那么我们知道Ivan类super()方法可以轻松取得父类(Father)的属性,可是要取得祖父类的属性时就会碰上困难。
解决方式是使用在Father类与Ivan类的 init ()方法中增加下列设定,即可解决上述难题:
super().__init__()
class Ivan(Father):
"""Ivan的资产"""
def __init__(self):
super().__init__()
self.ivanmoney = 3000
def getinfo3(self):
print("Ivan's information")
def get_money(self):
print("\nIvan资产:",self.ivanmoney,
"\n父亲资产:",self.fathermoney,
"\n祖父资产:", self.grandfathermoney)
ivan = Ivan()
ivan.getinfo3() # 从Ivan中获得
ivan.getinfo2() # Ivan -> Father
ivan.getinfo1() # Ivan -> Father -> Grandfather
ivan.get_money() # 资产明细
Ivan's information
Father's information
Grandfather's information
Ivan资产: 3000
父亲资产: 8000
祖父资产: 10000
9.2.6 兄弟属性的取得
假设有一个父亲(Father)类,这个父亲类有2个子类分别是Ivan类和Ira类,如果Ira类想取得Ivan类的属性Ivanmoney,可以使用下列方法。
在9.2.5的例程中修改:在14行后添加兄弟类Ira类,
class Ira(Father):
"""Ira 的资产"""
def __init__(self):
self.iramoney = 5000
super().__init__()
def getinfo3(self):
print("Ira's information")
def get_money(self):
print("\nIvan资产:",self.iramoney,
"\n父亲资产:",self.fathermoney,
"\n祖父资产:", self.grandfathermoney,
"\nIvan资产:", Ivan().ivanmoney)
ira = Ira()
ira.get_money()
Ivan资产: 5000
父亲资产: 8000
祖父资产: 10000
Ivan资产: 3000
9.2.7 认识Python类方法中的self参数
类的方法并没有self参数。将用一个简单实例讲解self参数的概念。
class Person():
def interest(self):
print("Smiling is my interest")
hung = Person()
hung.interest()
Smiling is my interest
其实第6行相当于把hung当作是self参数,然后传递给Person类的interest()方法。各位也可以用下列方式获得相同的输出。
Person.interest(hung),结果是相同的。
9.3 多型
其实我们在9.2.3中已经见过多型的用例了,那其实就是多型的基本概念。
class Dogs(Animals):
"""Dog 类 是Animals 的子类"""
def __init__(self , dog_name):
super().__init__(dog_name.title())
def action(self):
return "汪汪汪!"
class Monkeys():
"""Monkeys 类 是其他类"""
def __init__(self,monkey_name):
self.name = "My monkey" + monkey_name.title()
def which(self):
return self.name
def action(self):
return "荡秋千"
def doing(obj):
print(obj.which(), "在", obj.action())
my_cat = Animals("lucy")
doing(my_cat)
my_dog = Dogs("gimi")
doing(my_dog)
my_monkey = Monkeys("taylor")
doing(my_monkey)
My petLucy 在 Zzz~
My petGimi 在 汪汪汪!
My monkeyTaylor 在 荡秋千
https://s1.ax1x.com/2023/08/29/pPdYTRP.png
9.4 多重继承
在面向对象的程序设计中’也常会发生一个类继承多个类的应用,此时子类也同时继承了多个类的方法。这种情况,如果多个父类拥有相同名称的方法时,应该先执行哪一个父类的方法呢?
多重继承的语法结构
class 类名称(父类1, 父类2, ..., 父类n):
类内容
多个父类拥有相同名称的方法,程序实例
class Grandfather():
""" 定义祖父类 """
def action1(self):
print("Grandfather")
class Father(Grandfather):
""" 定义父亲类 """
def action2(self): # 定义action2()
print("Father")
class Uncle(Grandfather):
""" 定义叔父类 """
def action2(self): # 定义action2()
print("Uncle")
class Ivan(Father, Uncle):
""" 定义Ivan类 """
def action3(self):
print("Ivan")
ivan = Ivan()
ivan.action3() # 顺序 Ivan
ivan.action2() # 顺序 Ivan -> Father
ivan.action1() # 顺序 Ivan -> Father -> Grandfather
Ivan
Father
Grandfather
这个程序Ivan类继承了Father和Uncle类,其中Father和Uncle类同时拥有action2()方法,那么实例化Ivan类的对象ivan后,ivan.action2()究竟是执行哪一个action2()方法的?可以观察到,是执行Father类的方法。(可以这么理解吗?当存在相同方法时,22代码中继承顺序谁在前就先执行谁的方法)
9.4.1 super()应用在多重继承的问题
super()可以继承父类的方法,先看看可能产生的问题。
class A():
def __init__(self):
print('class A')
class B():
def __init__(self):
print('class B')
class C(A,B):
def __init__(self):
super().__init__()
print('class C')
x = C()
class A
class C
如果用C去继承A和B,我们发现实例化对象x后,C类的第二个参数类B没有被启动。
实Python使用super()的多重继承时,在此算是协同作业(co-operative),我们必须在基类也增加super()设定,才可以正常使用。
修改如下:
class A():
def __init__(self):
super().__init__()
print('class A')
class B():
def __init__(self):
super().__init__()
print('class B')
class C(A,B):
def __init__(self):
super().__init__()
print('class C')
x = C()
class B
class A
class C
上述我们得到的所有类的初始化方法 init ()均被启动了,这个概念很重要。因为我们如果在最初化方法中想要子类继承所有父类的属性时,全部的父类必须均被启动。
9.5 type 与 instance
一个大型程序可能由许多人合作完成,想了解某个对象变量的数据类型或是所属类关系时,可以使用本节所述的方法。
9.5.1 type()
这个函数先前已经使用许多次了,可以使用type()函数得到某一对象变量的类。
class Grandfather():
""" 定义祖父类 """
pass
class Father(Grandfather):
""" 定义父亲类 """
pass
class Ivan(Father):
""" 定义Ivan类 """
def fn(self):
pass
grandfather = Grandfather()
father = Father()
ivan = Ivan()
print("grandfather对象类型: ", type(grandfather))
print("father对象类型 : ", type(father))
print("ivan对象类型 : ", type(ivan))
print("ivan对象fn方法类型 : ", type(ivan.fn))
grandfather对象类型: <class '__main__.Grandfather'>
father对象类型 : <class '__main__.Father'>
ivan对象类型 : <class '__main__.Ivan'>
ivan对象fn方法类型 : <class 'method'>
由上述程序可以得到类的对象类型是class,同时会列出“ main .类的名称 ”。如果是类内的方法,同时也列出method方法。
9.5.2 isinstance()
isinstance()函数可以回传对象的类是否属于某—类,它包含2个参数,语法如下:
isinstance(对象,类) # 回传True或False
9.6 特殊属性
设计Python程序时,若是看到 xx 类的字符串就要特别留意了,这是系统保留的变量或属性参数,我们可以使用dir()列出Python目前环境的变量、属性、方法。
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
9.6.1 文件字符串 doc
Python鼓励程序设计师在设计函数或类时,尽量为函数或类增加文件的批注,即使用 doc 特殊属性列出此文件批注。
def getMax(x, y):
'''文件字符串实例
建议x, y是整数
这个函数将传回较大值'''
if int(x) > int(y):
return x
else:
return y
print(getMax(2, 3)) # 打印较大值
print(getMax.__doc__) # 打印文件字符串docstring
3
文件字符串实例
建议x, y是整数
这个函数将传回较大值
9.6.2 name 属性
如果你是Python程序设计师,一定会经常在程序末端看到下列语句:
if __name__ == '__main__'
doSomething
初学Python时,笔者照上述撰写,程序一定可以执行,当时不晓得意义,现在觉得应该要告诉读者。如果上述程序是自己执行,那么_ name 就一定是 main _ 。
# Day10_property.py
print("Day10_property.py module name = ",__name__)
# out: Day10_property.py module name = __main__
关于它的应用:
# Day10_test1.py
Import Day10_property
print("Day10_property.py module name = ",__name__)
# out: Day10_property.py module name = Day10_property
当“Day10property.py”文件通过第二行代码被import到另一个程序时, name _是本身的文件名“Day10property”,而不再是 main _了。
所以_ name _ 可以判别这个程序是自己执行或是被其他程序import导入当成模块使用。
9.7 类的特殊方法
9.7.1 str ()的方法
这是类的特殊方法,可以协助返回易读取的字符串。
class Name:
def __init__(self, name):
self.name = name
a = Name('Hung')
print(a)
#out:<__main__.Name object at 0x000001D85882C100>
上述在没有定义 str_ _方法下,我们获得了一个不太容易阅读的结果。
class Name:
def __init__(self, name):
self.name = name
def __str__(self):
return f"{self.name}"
a = Name('Hung')
print(a)
#out:Hung
虽然有了 str_ _方法的帮助,得到了一个适合阅读的结果。但对于上面程序而言,我们在Python Shell窗口输入a,将一样获得不容易阅读的结果。
#out:<__main__.Name object at 0x000001D85882C100>
9.7.2 repr ()方法
上述原因是’如果只是在Python Shell窗口输入类变量a,系统是调用 repr ()方法做响应,为了获得容易阅读的结果,我们也须定义此方法。
class Name:
def __init__(self, name):
self.name = name
def __str__(self):
return f"{self.name}"
__repr__ = __str__
a = Name('Hung')
print(a)
#out:Hung
9.7.3 iter ()方法
建立类的时候也可以将类定义成一个迭代对象,类似list或tuple供for…in循环内使用,这 时类须设计next()方法,取得下一个值,直到达到结束条件,可以使用raise StopIteration终止继续。
class Fib():
def __init__(self,max):
self.max = max
def __iter__(self):
self.a = 0
self.b = 1
return self
def __next__(self):
fib = self.a
if fib > self.max:
raise StopIteration
self.a,self.b = self.b,self.a + self.b
return fib
for i in Fib(100):
print(i)
0
1
1
2
3
5
8
13
21
34
55
89
9.7.4 eq ()方法
假设我们想要了解2个字符串或其他内容是否相同,依照之前的知识可以使用下列方式设计。
程序实例:设计检查字符串是否相等。
class City():
def __init__(self,name):
self.name = name
def euqals(self,city2):
return self.name.upper() == city2.name.upper()
one = City("Zhejiang")
two = City("zhejiang")
three = City("Chongqin")
print(one.euqals(two))
print(one.euqals(three))
True
False
现在我们将 equals 方法改为 eq (),可以参考下列实例。
class City():
def __init__(self,name):
self.name = name
def __eq__(self, city2):
return self.name.upper() == city2.name.upper()
one = City("Zhejiang")
two = City("zhejiang")
three = City("Chongqin")
print(one == two)
print(one == three)
True
False
上述是类的特殊方法,主要是了解内容是否相同,下列是拥有这类特色的其他系统方法。
逻辑方法 |
说明 |
eq (self,other) |
self == other #等于 |
ne (self,other) |
self != other #不等于 |
lt (self,other) |
self < other #小于 |
gt (self,other) |
self > other #大于 |
le (self,other) |
self <= other #小于等于 |
ge (self,other) |
self >= other #大于等于 |
数学方法 |
说明 |
add (self,other) |
self + other#加法 |
sub (self,other) |
self - other#减法 |
mul (self,other) |
self X other#乘法 |
floordiv (self,other) |
self // other#整数除法 |
truediv (self,other) |
self / other#除法 |
mod (self,other) |
self % other#取余 |
9.8 小测试
T9.8.1 设计一个Geometric类,这个类主要设定color是Green。另外设计—个 Circle类,这个类有getRadius()可以获得半径,setRadius()可以设定半径,getDiameter()可以取得直径,getPerimeter()可以取得圆周长, getArea()可以取得面积,getColor()可以取得颜色。
class Geometric():
def __init__(self):
self.color = "Green"
self.pi = 3.1415926
class Circle(Geometric):
def __init__(self,radius):
super().__init__()
self.__radius = radius
def setRadius(self,radius):
self.__radius = radius
def getRadius(self):
return self.__radius
def getDiameter(self):
return self.__radius*2
def getPerimeter(self):
return 2*self.pi*self.__radius
def getArea(self):
return self.pi*self.__radius**2
def getColor(self):
return self.color
A = Circle(5)
print("圆形的颜色 : ", A.getColor())
print("圆形的半径 : ", A.getRadius())
print("圆形的直径 : ", A.getDiameter())
print("圆形的圆周 : ", A.getPerimeter())
print("圆形的面积 : ", A.getArea())
A.setRadius(10)
print("圆形的直径 : ", A.getDiameter())
"""
圆形的颜色 : Green
圆形的半径 : 5
圆形的直径 : 10
圆形的圆周 : 31.415926
圆形的面积 : 78.539815
圆形的直径 : 20
"""