python学习——初始面向对象
一、讲在前面
编程的世界中有三大体系,面向过程、面向函数和面向对象编程。而面向过程的编程就包括了面向函数编程,接下来说一下面向对象。假如 ,你现在是一家游戏公司的开发人员,现在需要你开发一款叫做<人狗大战>的游戏,你就思考呀,人狗作战,那至少需要2个角色,一个是人, 一个是狗,且人和狗都有不同的技能,比如人拿棍打狗, 狗可以咬人,怎么描述这种不同的角色和他们的功能呢?你搜罗了自己掌握的所有技能,写出了下面的代码来描述这两个角色。👇
1 # 人狗角色定制
2
3 def person(name,sex,age,job):
4 data = {
5 'name':name,
6 'sex':sex,
7 'age':age,
8 'job':job
9 }
10 return data
11
12 def dog(name,kind):
13 data = {
14 'name':name,
15 'kind':kind
16 }
17 return data
上面两个方法相当于造了两个模子,游戏里的每个人和每条狗都拥有相同的属性。游戏开始,你根据一个人或一只狗传入的具体信息来塑造一个具体的人或者狗,怎么生成呢?
1 def person(name,sex,age,job): 2 data = { 3 'name':name, 4 'sex':sex, 5 'age':age, 6 'job':job 7 } 8 return data 9 10 def dog(name,kind): 11 data = { 12 'name':name, 13 'kind':kind 14 } 15 return data 16 17 p1 = person('liulonghai','male',18,'student') 18 d1 = dog('luosy','哈士奇') 19 print(p1) 20 print(d1) 21 22 # 输出: 23 {'name': 'liulonghai', 'sex': 'male', 'age': 18, 'job': 'student'} 24 {'name': 'luosy', 'kind': '哈士奇'}
两个角色对象生成了,狗和人还有不同的功能呀,狗会咬人,人会打狗,对不对? 怎么实现呢。。。想到了, 可以每个功能再写一个函数,想执行哪个功能,直接调用就ok了,对吗?
1 def person(name,sex,age,job): 2 data = { 3 'name':name, 4 'sex':sex, 5 'age':age, 6 'job':job 7 } 8 return data 9 10 def dog(name,kind): 11 data = { 12 'name':name, 13 'kind':kind 14 } 15 return data 16 17 p1 = person('liulonghai','male',18,'student') 18 d1 = dog('luosy','哈士奇') 19 # print(p1) 20 # print(d1) 21 22 # # 输出: 23 # {'name': 'liulonghai', 'sex': 'male', 'age': 18, 'job': 'student'} 24 # {'name': 'luosy', 'kind': '哈士奇'} 25 26 def bark(d): 27 return '{} 汪汪汪的咬'.format(d1['name']) 28 29 def fighting(p): 30 return '{} 飞奔在人狗大战的战场上'.format(p1['name']) 31 32 print(bark(d1)) 33 print(fighting(p1)) 34 35 # 输出: 36 luosy 汪汪汪的咬 37 liulonghai 飞奔在人狗大战的战场上
上面的功能实现的简直是完美!但是仔细玩耍一会,你就不小心干了下面这件事。👇
1 def person(name,sex,age,job): 2 data = { 3 'name':name, 4 'sex':sex, 5 'age':age, 6 'job':job 7 } 8 return data 9 10 def dog(name,kind): 11 data = { 12 'name':name, 13 'kind':kind 14 } 15 return data 16 17 p1 = person('liulonghai','male',18,'student') 18 d1 = dog('luosy','哈士奇') 19 20 def bark(d): 21 return '{} 汪汪汪的咬!'.format(d['name']) 22 23 def fighting(p): 24 return '{} 飞驰在人狗大战的战场上!'.format(p['name']) 25 26 print(bark(p1)) 27 print(fighting(d1)) 28 29 # 输出: 30 liulonghai 汪汪汪的咬! 31 luosy 飞驰在人狗大战的战场上!
事实 上,从你写的代码上来看,这并没出错。很显然,人是不能调用狗的功能的,但在你的程序例没有做限制,如何在代码级别实现这个限制呢?
1 def person(name,sex,age,job): 2 def fighting(p): 3 return '{} 飞驰在人狗大战的战场上'.format(p['name']) 4 5 data = { 6 'name':name, 7 'sex':sex, 8 'age':age, 9 'job':job 10 } 11 return data 12 13 def dog(name,kind): 14 def bark(d): 15 return '{} 汪汪汪的咬'.format(d['name']) 16 17 data = { 18 'name':name, 19 'kind':kind 20 } 21 return data 22 23 p1 = person('liulonghai','male',18,'student') 24 d1 = dog('luosy','哈士奇')
你是如此的机智,这样就实现了限制人只能用人自己的功能啦。刚刚你用的这种编程思想其实就是简单的面向对象编程,我们创造了两个模子表示游戏里所有的人和狗之后,剩下的狗叫或者人战斗对于这两个模子来说就不重要了。具体人和狗之间的交互就等着你去使用了。假如你和狗打起来了,这时候你是走路还是拿棍子打狗就由你自己决定了。那你的每一个决定可能都影响着你这场游戏的输赢。这也是不确定的。和我们之前写代码按部就班的走,最终都会实现我们要完成的事情不太一样了。
尽管如此,我们也只完成了这个游戏非常小的一部分。还有很多功能都没有实现。刚才你只是阻止了两个完全 不同的角色 之前的功能混用, 但有没有可能 ,同一个种角色,但有些属性是不同的呢? 比如 ,大家都打过cs吧,cs里有警察和恐怖份子,但因为都 是人, 所以你写一个角色叫 person(), 警察和恐怖份子都 可以 互相射击,但警察不可以杀人质,恐怖分子可以,这怎么实现呢? 你想了想说,简单,只需要在杀人质的功能里加个判断,如果是警察,就不让杀不就ok了么。 没错, 这虽然 解决了杀人质的问题,但其实你会发现,警察和恐怖分子的区别还有很多,同时又有很多共性,如果在每个区别处都单独做判断,那得累死。
你想了想又说, 那就直接写2个角色吧, 反正 这么多区别, 我的哥, 不能写两个角色呀,因为他们还有很多共性 , 写两个不同的角色,就代表相同的功能也要重写了,是不是?
二、面向过程VS面向对象
面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西:👇
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的属性和方法),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙互相缠斗着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取。
面向对象的程序设计:👇
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点是:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。
在python 中面向对象的程序设计并不是全部。面向对象编程可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
了解一些名词:类、对象、实例、实例化
类:具有相同特征的一类事物(人、狗、老虎)
对象/实例:具体的某一个事物(隔壁阿花、楼下旺财)
实例化:类——>对象的过程(这在生活中表现的不明显,我们在后面再慢慢解释)
三、初始类和对象
python中一切皆对象,类型的本质就是类,你已经使用了很长时间的类了。
1 print(type({})) 2 d = {'name':'liulonghai','age':18,'job':'student'} 3 print(d) 4 print(isinstance(d,dict)) 5 print() 6 7 lst = [1,2,3,4,5] 8 print(lst) 9 print(isinstance(lst,list)) 10 print(type([])) 11 print() 12 13 print(type(())) 14 tup = (1,2,3,4,5) 15 print(tup) 16 print(isinstance(tup,tuple)) 17 print() 18 19 print(type('')) 20 s = 'abcde' 21 print(s) 22 print(isinstance(s,str)) 23 24 # 输出: 25 <class 'dict'> 26 {'name': 'liulonghai', 'age': 18, 'job': 'student'} 27 True 28 29 [1, 2, 3, 4, 5] 30 True 31 <class 'list'> 32 33 <class 'tuple'> 34 (1, 2, 3, 4, 5) 35 True 36 37 <class 'str'> 38 abcde 39 True
不管你相不相信,通过以上的代码你应该知道了,其中你平时用的 (lst,s,dct,tup等等),他们其实都是对象,而(list str tuple dict)都是一个类,之前的变量都是类的实例化对象。
在python中,用变量表示特征,用函数表示技能,因而具有相同特征和技能的一类事物就是‘类’,对象是则是这一类事物中具体的一个。
其实非常好理解,比如说 人 👈 这肯定是一个类,比如说 👉‘liulonghai’ 具体到个体了,所以是对象,再比如说,狗(类),二狗(对象)。。。
四、类的相关知识
4.1 类的声明
在这之前回忆一下函数的声明
1 # 函数的声明 2 3 def 函数名(): 4 '''注释内容''' 5 函数体
类的声明如下 👇
''' class 类名: '类的文档字符串' 类体 ''' #我们创建一个类 class FirstClass: pass
声明了一个简单的人类
1 class Person: 2 role = 'person' 3 def __init__(self,name,sex,age): 4 self.name = name 5 self.sex = sex 6 self.age = age 7 8 def fighting(self): 9 print('{} 为学习而奋斗'.format(p.name)) 10 11 p = Person('liulonghai','male',18) 12 p.fighting() 13 14 # 输出: 15 liulonghai 为学习而奋斗
4.2 类的两种作用(属性引用和实例化)
属性引用(类名.属性)。
class Person: #定义一个人类 role = 'person' #人的角色属性都是人 def fighting(self): #人都可以走路,也就是有一个走路方法 print("person is fighting...") print(Person.role) #查看人的role属性 print(Person.fighting) #引用人的走路方法,注意,这里不是在调用 # 输出: person <function Person.fighting at 0x000001F74EEB32F0>
实例化:类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征。
class Person: # 定义一个人类 role = 'person' # 人的角色属性都是人 def __init__(self, name): self.name = name # 每一个角色都有自己的昵称; def fighting(self): # 人都可以奋斗,也就是有一个方法 print("person is fighting...") print(Person.role) # 查看人的role属性 print(Person.fighting) # 引用人的奋斗方法,注意,这里不是在调用 # 输出: person <function Person.fighting at 0x0000023D7423D598>
实例化的过程就是类——>对象的过程
原本我们只有一个Person类,在这个过程中,产生了一个egg对象,有自己具体的名字、攻击力和生命值。
语法:对象名 = 类名(参数)
l = Person('liulonghai') ''' 类名()就等于在执行Person.__init__() 执行完__init__()就会返回一个对象。这个对象类似一个字典,存着属于这个人本身的一些属性和方法。 '''
查看属性&调用方法
print(l.name) #查看属性直接 对象名.属性名 print(l.fighting()) #调用方法,对象名.方法名()
关于self:在实例化时自动将对象/实例本身传给__init__的第一个参数,你也可以给他起个别的名字,但是正常人都不会这么做,因为一般情况下默认用self。
类属性的补充
一:我们定义的类的属性到底存到哪里了?有两种方式查看 dir(类名):查出的是一个名字列表 类名.__dict__:查出的是一个字典,key为属性名,value为属性值 二:特殊的类属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中)
五、对象的相关知识
回到咱们的人狗大战:现在我们需要对我们的类做出一点点改变,人类除了可以走路等等,狗类也一样,还应该具备一些攻击技能。
class Dog: def __init__(self,name,life_value,aggr): self.name = name self.life_value = life_value self.aggr = aggr def bite(self,person): person.life_value -= self.aggr return person.life_value # return '{0} 汪汪汪的咬了{1}一下,{1}完全无视它'.format(self.name,p['name']) class Person: def __init__(self,name,aggr,life_value): self.name = name self.aggr = aggr self.life_value = life_value def attack(self,dog): dog.life_value -= self.life_value return dog.life_value # return '{0} 飞起一脚踢了{1}一下,{1}完了'.format(self.name, d['name']) p = Person('liulonghai',100,1000) d = Dog('二狗',10,1) print(p.life_value) print(d.life_value) print(p.attack(d)) print(d.bite(p)) # 输出: 1000 10 -990 999
对象是关于类而实际存在的一个例子,即实例
对象/实例只有一种作用:属性引用
print(p.life_value) print(p.name) print(p.aggr) print(d.life_value) print(d.name) print(d.aggr) # 输出: 1000 liulonghai 100 10 二狗 1
当然了,你也可以引用一个方法,因为方法也是一个属性,只不过是一个类似函数的属性,我们也管它叫动态属性。引用动态属性并不是执行这个方法,要想调用方法和调用函数是一样的,都需要在后面加上括号,如果有实例的话还需要进行传值。
我知道在类里说,你可能还有好多地方不能理解。那我们就用函数来解释一下这个类,对象到底是个啥,你偷偷的用这个理解就好了,不要告诉别人
1 def Person(*args,**kwargs): 2 self = {} 3 def attack(self,dog): 4 dog['life_value'] -= self['aggressivity'] 5 6 def __init__(name,aggr,life_value): 7 self['name'] = name 8 self['aggr'] = aggr 9 self['life_value'] = life_value 10 self['attack'] = attack 11 12 __init__(*args,**kwargs) 13 return self 14 15 l = Person('liulonghai',100,1000) 16 print(l['name']) 17 print(l['aggr']) 18 print(l['life_value']) 19 20 # 输出: 21 liulonghai 22 100 23 1000
面向对象小结——定义及调用的固定模式
class 类名: def __init__(self,参数1,参数2): self.对象的属性1 = 参数1 self.对象的属性2 = 参数2 def 方法名(self):pass def 方法名2(self):pass 对象名 = 类名(1,2) #对象就是实例,代表一个具体的东西 #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法 #括号里传参数,参数不需要传self,其他与init中的形参一一对应 #结果返回一个对象 对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 即可 对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
练习一:在终端输出如下信息
小明,10岁,男,上山去砍柴
小明,10岁,男,开车去贵阳
小明,10岁,男,最爱去图书馆
老李,90岁,男,上山去砍柴
老李,90岁,男,开车去北京
老李,90岁,男,最爱去健身
1 class XiaoMing: 2 def __init__(self,name,age,sex): 3 self.name = name 4 self.age = age 5 self.sex = sex 6 def kancai(self): 7 return '{},{},{},上山去砍柴'.format(self.name,self.age,self.sex) 8 9 def driver(self): 10 return '{},{},{},开车去贵阳'.format(self.name,self.age,self.sex) 11 12 def study(self): 13 return '{},{},{},最爱去图书馆'.format(self.name,self.age,self.sex) 14 15 16 class LaoLi: 17 def __init__(self, name, age, sex): 18 self.name = name 19 self.age = age 20 self.sex = sex 21 22 def kancai(self): 23 return '{},{},{},上山去砍柴'.format(self.name,self.age,self.sex) 24 25 def driver(self): 26 return '{},{},{},开车去北京'.format(self.name,self.age,self.sex) 27 28 def exercise(self): 29 return '{},{},{},最爱去健身'.format(self.name,self.age,self.sex) 30 31 小明 = XiaoMing('小明','10岁','男') 32 老李 = LaoLi('老李','90岁','男') 33 34 print(小明.kancai()) 35 print(小明.driver()) 36 print(小明.study()) 37 print(老李.kancai()) 38 print(老李.driver()) 39 print(老李.exercise()) 40 41 # 输出: 42 小明,10岁,男,上山去砍柴 43 小明,10岁,男,开车去贵阳 44 小明,10岁,男,最爱去图书馆 45 老李,90岁,男,上山去砍柴 46 老李,90岁,男,开车去北京 47 老李,90岁,男,最爱去健身
练习二:在终端输出如下信息
小明,10岁,男,上山去砍柴
小明,10岁,男,开车去北京
小明,10岁,男,最爱去图书馆
老李,90岁,男,上山去砍柴
老李,90岁,男,开车去北京
老李,90岁,男,最爱去图书馆
1 class Person: 2 def __init__(self,name,age,sex,): 3 self.name = name 4 self.age = age 5 self.sex = sex 6 7 def cutting(self): 8 return '{},{},{},上山去砍柴'.format(self.name,self.age,self.sex) 9 10 def driving(self): 11 return '{},{},{},开车去北京'.format(self.name,self.age,self.sex) 12 13 def studing(self): 14 return '{},{},{},最爱去图书馆'.format(self.name,self.age,self.sex) 15 16 p1 = Person('小明','10岁','男') 17 p2 = Person('老李','90岁','男') 18 19 print(p1.cutting()) 20 print(p1.driving()) 21 print(p1.studing()) 22 print(p2.cutting()) 23 print(p2.driving()) 24 print(p2.studing()) 25 26 # 输出: 27 小明,10岁,男,上山去砍柴 28 小明,10岁,男,开车去北京 29 小明,10岁,男,最爱去图书馆 30 老李,90岁,男,上山去砍柴 31 老李,90岁,男,开车去北京 32 老李,90岁,男,最爱去图书馆
六、对象之间的交互
现在我们已经有一个人类和狗了,通过给人类一些具体的属性我们就可以拿到一个实实在在的人。但是狗就不能打人了,只能咬人,所以我们给狗一个bite方法。有了狗类,我们还实例化一只实实在在的狗出来。然后人和狗就可以打架了。现在我们就来让他们打一架吧!
1 class Dog: 2 def __init__(self,name,life_value,aggr): 3 self.name = name 4 self.life_value = life_value 5 self.aggr = aggr 6 7 def bite(self,person): 8 person.life_value -= self.aggr 9 print('{0} 汪汪汪的咬了{1}一下,{1}完全无视它,请看下面{1}的生命值,哈哈哈'.format(self.name,person.name)) 10 11 return person.life_value 12 13 class Person: 14 def __init__(self,name,aggr,life_value): 15 self.name = name 16 self.aggr = aggr 17 self.life_value = life_value 18 19 def attack(self,dog): 20 dog.life_value -= self.life_value 21 print('{0} 飞起一脚踢了{1}一下,{1}完了,请看下面{1}的生命值...'.format(self.name, dog.name)) 22 23 return dog.life_value 24 25 p = Person('海哥',100,10000) 26 d = Dog('二狗',10,1) 27 print('二狗的生命值',d.life_value) 28 p.attack(d) 29 print('二狗的生命值变成了',d.life_value) 30 print() 31 print('海哥的生命值',p.life_value) 32 d.bite(p) 33 print('海哥的生命值毫无变化',p.life_value) 34 35 # 输出: 36 二狗的生命值 10 37 海哥 飞起一脚踢了二狗一下,二狗完了,请看下面二狗的生命值... 38 二狗的生命值变成了 -9990 39 40 海哥的生命值 10000 41 二狗 汪汪汪的咬了海哥一下,海哥完全无视它,请看下面海哥的生命值,哈哈哈 42 海哥的生命值毫无变化 9999
上面的人狗大战其实就是对象之间的交互。下面再来个例子帮你理解面向对象。
1 from math import pi 2 3 class Circle: 4 def __init__(self,radius): 5 self.radius = radius 6 7 def area(self): 8 return pi*self.radius**2 9 10 def perimeter(self): 11 return 2*pi*self.radius 12 13 yuan = Circle(5) 14 print('圆的面积为',yuan.area()) 15 print('圆的周长为',yuan.perimeter()) 16 17 # 输出: 18 圆的面积为 78.53981633974483 19 圆的周长为 31.41592653589793
七、类命名空间与对象、实例的命名空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
而类有两种属性:静态属性和动态属性
静态属性就是直接在类中定义的变量
动态属性就是定义在类中的方法
其中类的数据属性是共享给所有对象的
p = Person('海哥',1000,10000) print(id(p.role)) print(id(Person.role)) # 输出: 1653393036824 1653393036824
而类的动态属性是绑定到所有对象的
p = Person('海哥',1000,10000) d = Dog('二狗',10,1) print(p.attack) print(Person.attack) print(d.bite) print(Dog.bite) # 输出: <bound method Person.attack of <__main__.Person object at 0x000002878BC70F98>> <function Person.attack at 0x000002878CCBD730> <bound method Dog.bite of <__main__.Dog object at 0x000002878BC713C8>> <function Dog.bite at 0x000002878CCBD620>
所以其中人类的attack方法和狗类的bite方法都是和实例化对象绑定的。
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
八、面向对象的组合用法
软件重用的重要方式除了继承之外还有另外一种方式,即:组合(也叫重载)
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合 👇
1 class Weapon: 2 def deat_dog(self,obj): 3 obj.life_value -= 500 4 5 class Dog: 6 def __init__(self,name,life_value): 7 self.name = name 8 self.life_value = life_value 9 10 class Person: 11 def __init__(self,name,life_value): 12 self.name = name 13 self.life_value = life_value 14 self.weapon = Weapon() 15 16 p = Person('海哥',1000) 17 d = Dog('二狗',500) 18 19 print('二狗的生命值为',d.life_value) 20 p.weapon.deat_dog(d) 21 print('二狗的生命值变成了',d.life_value) 22 23 # 输出: 24 二狗的生命值为 500 25 二狗的生命值变成了 0
1 class Weapon: 2 def deat_dog(self,obj): 3 obj.life_value -= 500 4 5 class Dog: 6 def __init__(self,name,life_value): 7 self.name = name 8 self.life_value = life_value 9 10 class Person: 11 def __init__(self,name,life_value,weapon): 12 self.name = name 13 self.life_value = life_value 14 self.weapon = weapon 15 16 p = Person('海哥',1000,Weapon()) 17 d = Dog('二狗',500) 18 19 print('二狗的生命值为',d.life_value) 20 p.weapon.deat_dog(d) 21 print('二狗的生命值变成了',d.life_value) 22 23 # 输出: 24 二狗的生命值为 500 25 二狗的生命值变成了 0
上面的代码其中就有组合,就是在人的类中以武器类作为人类的对象的数据属性。就是类的组合。
圆环是由两个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是内部圆的周长加上外部圆的周长。这个时候,我们就首先实现一个圆形类,计算一个圆的周长和面积。然后在"环形类"中组合圆形的实例作为自己的属性来用 👇
1 from math import pi 2 3 class Circle: 4 def __init__(self,radius): 5 self.radius = radius 6 7 def area(self): 8 return pi * self.radius ** 2 9 10 def perimiter(self): 11 return 2 * pi * self.radius 12 13 class Ring: 14 def __init__(self,radius_outside,radius_inside): 15 self.outside_circle = Circle(radius_outside) 16 self.inside_circle = Circle(radius_inside) 17 18 def area(self): 19 return self.outside_circle.area() - self.inside_circle.area() 20 21 def perimiter(self): 22 return self.outside_circle.perimiter() + self.inside_circle.perimiter() 23 24 ring = Ring(10,5) 25 print('环形的周长为',ring.perimiter()) 26 print('环形的面积为',ring.area()) 27 28 # 输出: 29 环形的周长为 94.24777960769379 30 环形的面积为 235.61944901923448
1 from math import pi 2 3 class Circle: 4 def __init__(self,radius): 5 self.radius = radius 6 7 def primeter(self): 8 return pi * self.radius * 2 9 10 def area(self): 11 return pi * self.radius ** 2 12 13 class Ring: 14 def __init__(self,outside_r,inside_r): 15 self.outside_r = outside_r 16 self.inside_r = inside_r 17 18 def primeter(self): 19 return self.outside_r.primeter() + self.inside_r.primeter() 20 21 def area(self): 22 return self.outside_r.area() - self.inside_r.area() 23 24 ring = Ring(Circle(10),Circle(5)) 25 print(ring.primeter()) 26 print(ring.area()) 27 28 # 输出: 29 94.24777960769379 30 235.61944901923448
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教师有生日,教python课程。
1 class Birth: 2 def __init__(self,year,month,day): 3 self.year = year 4 self.month = month 5 self.day = day 6 7 class Course: 8 def __init__(self,name,price,period): 9 self.name = name 10 self.price = price 11 self.period = period 12 13 class Teacher: 14 def __init__(self,name,gender,birth,course): 15 self.name = name 16 self.gender = gender 17 self.birth = birth 18 self.course = course 19 def teaching(self): 20 return 'teaching' 21 22 teacher = Teacher('罗老师','male', 23 Birth('2018','11','27'), 24 Course('python',18000,'three month') 25 ) 26 print('未来{}的生日是!'.format(teacher.name), 27 teacher.birth.year, 28 teacher.birth.month, 29 teacher.birth.day 30 ) 31 print('未来的{}教{},{}赚了{}块钱!'.format( 32 teacher.name, 33 teacher.course.name, 34 teacher.course.period, 35 teacher.course.price) 36 ) 37 38 # 输出: 39 未来罗老师的生日是! 2018 11 27 40 未来的罗老师教python,three month赚了18000块钱!
1 class Birth: 2 def __init__(self,year,month,day): 3 self.year = year 4 self.month = month 5 self.day = day 6 7 class Course: 8 def __init__(self,name,price,period): 9 self.name = name 10 self.price = price 11 self.period = period 12 13 class Teacher: 14 def __init__(self,name1,gender,year,month,day,name2,price,period): 15 self.name = name1 16 self.gender = gender 17 self.birth = Birth(year,month,day) 18 self.course = Course(name2,price,period) 19 def teaching(self): 20 return 'teaching' 21 22 ##teacher = Teacher('罗老师','male', 23 ## Birth('2018','11','27'), 24 ## Course('python',18000,'three month') 25 26 teacher = Teacher('罗老师','male','2018','11','28','python',180000,'three month') 27 28 print('未来{}的生日是!'.format(teacher.name), 29 teacher.birth.year, 30 teacher.birth.month, 31 teacher.birth.day 32 ) 33 print('未来的{}教{},{}赚了{}块钱!'.format( 34 teacher.name, 35 teacher.course.name, 36 teacher.course.period, 37 teacher.course.price) 38 ) 39 40 # 输出: 41 未来罗老师的生日是! 2018 11 28 42 未来的罗老师教python,three month赚了180000块钱!
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好。
组合的两种方式:
1.在__init__方法里面组合
2.在外面组合
不管组合的形式怎么变,总之范围都是由较小的类到较大的类,而且只要是组合就一定是至少两个类之间的事情。
九、初识面向对象小结
定义一个人类 👇
1 class Person: 2 role = 'person' 3 def __init__(self,name,gender,aggr,life_value,money): 4 self.name = name 5 self.gender = gender 6 self.aggr = aggr 7 self.life_value = life_value 8 self.money = money 9 10 def fighting(self,dog): 11 dog.life_value -= self.aggr
定义了一个狗类 👇
1 class Dog: 2 role = 'dog' 3 def __init__(self,name,aggr,life_value): 4 self.name = name 5 self.aggr = aggr 6 self.life_value = life_value 7 8 def bite(self,person): 9 person.life_value -= self.aggr
又定义了一个武器类
1 class Warpon: 2 def __init__(self,name,price,aggr,life_value): 3 self.name = name 4 self.price = price 5 self.aggr = aggr 6 self.life_value = life_value 7 8 def update(self,obj): 9 obj.money -= self.price 10 obj.aggr += self.aggr 11 obj.life_value += self.life_value 12 13 def beat(self,obj): 14 obj.life_value -= 500
对以上的对象进行测试交互
1 p = Person('海哥','male',500,500,1000) 2 d = Dog('二狗',100,100) 3 w = Warpon('打狗棒',200,100,100) 4 5 if p.money >= w.price: 6 w.update(p) 7 p.weapon = w 8 9 print('{}的生命值为{},攻击力为{},金钱是{}'.format(p.name,p.life_value,p.aggr,p.money)) 10 print('{}的生命值为{}'.format(d.name,d.life_value)) 11 p.fighting(d) 12 print('{0}搞了{1}一下,{1}的生命值变成了{2}'.format(p.name,d.name,d.life_value)) 13 p.weapon.beat(d) 14 print('{0}被{1}用{2}搞了一下,顿时{0}的生命值掉了{3},还剩{4}的生命值,好悲催' 15 .format(d.name,p.name,w.name,w.aggr,d.life_value))
按照这种思路一点一点的设计类和对象,最终你完全可以实现一个对战类游戏。人狗大战完整代码如下:👇
1 class Person: 2 role = 'person' 3 def __init__(self,name,gender,aggr,life_value,money): 4 self.name = name 5 self.gender = gender 6 self.aggr = aggr 7 self.life_value = life_value 8 self.money = money 9 10 def fighting(self,dog): 11 dog.life_value -= self.aggr 12 13 class Dog: 14 role = 'dog' 15 def __init__(self,name,aggr,life_value): 16 self.name = name 17 self.aggr = aggr 18 self.life_value = life_value 19 20 def bite(self,person): 21 person.life_value -= self.aggr 22 23 class Warpon: 24 def __init__(self,name,price,aggr,life_value): 25 self.name = name 26 self.price = price 27 self.aggr = aggr 28 self.life_value = life_value 29 30 def update(self,obj): 31 obj.money -= self.price 32 obj.aggr += self.aggr 33 obj.life_value += self.life_value 34 35 def beat(self,obj): 36 obj.life_value -= 500 37 38 p = Person('海哥','male',500,500,1000) 39 d = Dog('二狗',100,100) 40 w = Warpon('打狗棒',200,100,100) 41 42 if p.money >= w.price: 43 w.update(p) 44 p.weapon = w 45 46 print('{}的生命值为{},攻击力为{},金钱是{}'.format(p.name,p.life_value,p.aggr,p.money)) 47 print('{}的生命值为{}!'.format(d.name,d.life_value)) 48 p.fighting(d) 49 print('{0}搞了{1}一下,{1}的生命值变成了{2}!'.format(p.name,d.name,d.life_value)) 50 p.weapon.beat(d) 51 print('{0}被{1}用{2}搞了一下,顿时{0}的生命值掉了{3},还剩{4}的生命值,好悲催!' 52 .format(d.name,p.name,w.name,w.aggr,d.life_value)) 53 54 # 输出: 55 海哥的生命值为600,攻击力为600,金钱是800 56 二狗的生命值为100! 57 海哥搞了二狗一下,二狗的生命值变成了-500! 58 二狗被海哥用打狗棒搞了一下,顿时二狗的生命值掉了100,还剩-1000的生命值,好悲催!
ok 这就是今天面向对象的初识。