python day 18 面向对象之交互,命名空间作用域,组合
对象的相关知识
回到咱们的人狗大战:现在我们需要对我们的类做出一点点改变人类除了可以走路之外,还应该具备一些攻击技能。
1 class Person: # 定义一个人类 2 role = 'person' # 人的角色属性都是人 3 4 def __init__(self, name, aggressivity, life_value): 5 self.name = name # 每一个角色都有自己的昵称; 6 self.aggressivity = aggressivity # 每一个角色都有自己的攻击力; 7 self.life_value = life_value # 每一个角色都有自己的生命值; 8 9 def attack(self,dog): 10 # 人可以攻击狗,这里的狗也是一个对象。 11 # 人攻击狗,那么狗的生命值就会根据人的攻击力而下降 12 dog.life_value -= self.aggressivit
对象是关于类而实际存在的一个例子,即实例
对象/实例只有一种作用:属性引用
1 egg = Person('egon',10,1000) 2 print(egg.name) 3 print(egg.aggressivity) 4 print(egg.life_value)
当然了,你也可以引用一个方法,因为方法也是一个属性,只不过是一个类似函数的属性,我们也管它叫动态属性。
引用动态属性并不是执行这个方法,要想调用方法和调用函数是一样的,都需要在后面加上括号
1 print(egg.attack)
我知道在类里说,你可能还有好多地方不能理解。那我们就用函数来解释一下这个类呀,对象呀到底是个啥,你偷偷的用这个理解就好了,不要告诉别人
1 def Person(*args,**kwargs): 2 self = {} 3 def attack(self,dog): 4 dog['life_value'] -= self['aggressivity'] 5 6 def __init__(name,aggressivity,life_value): 7 self['name'] = name 8 self['aggressivity'] = aggressivity 9 self['life_value'] = life_value 10 self['attack'] = attack 11 12 __init__(*args,**kwargs) 13 return self 14 15 egg = Person('egon',78,10) 16 print(egg['name'])
面向对象小结——定义及调用的固定模式
1 class 类名: 2 def __init__(self,参数1,参数2): 3 self.对象的属性1 = 参数1 4 self.对象的属性2 = 参数2 5 6 def 方法名(self):pass 7 8 def 方法名2(self):pass 9 10 对象名 = 类名(1,2) #对象就是实例,代表一个具体的东西 11 #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法 12 #括号里传参数,参数不需要传self,其他与init中的形参一一对应 13 #结果返回一个对象 14 对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 即可 15 对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
1 练习一:在终端输出如下信息 2 3 小明,10岁,男,上山去砍柴 4 小明,10岁,男,开车去东北 5 小明,10岁,男,最爱大保健 6 老李,90岁,男,上山去砍柴 7 老李,90岁,男,开车去东北 8 老李,90岁,男,最爱大保健 9 老张…
对象之间的交互
现在我们已经有一个人类了,通过给人类一些具体的属性我们就可以拿到一个实实在在的人。
现在我们要再创建一个狗类,狗就不能打人了,只能咬人,所以我们给狗一个bite方法。
有了狗类,我们还要实例化一只实实在在的狗出来。
然后人和狗就可以打架了。现在我们就来让他们打一架吧!
创建一个狗类
1 class Dog: # 定义一个狗类 2 role = 'dog' # 狗的角色属性都是狗 3 4 def __init__(self, name, breed, aggressivity, life_value): 5 self.name = name # 每一只狗都有自己的昵称; 6 self.breed = breed # 每一只狗都有自己的品种; 7 self.aggressivity = aggressivity # 每一只狗都有自己的攻击力; 8 self.life_value = life_value # 每一只狗都有自己的生命值; 9 10 def bite(self,people): 11 # 狗可以咬人,这里的狗也是一个对象。 12 # 狗咬人,那么人的生命值就会根据狗的攻击力而下降 13 dog.life_value -= self.aggressivit
实例化一只实实在在的二哈
1 ha2 = Dog('二愣子','哈士奇',10,1000) #创造了一只实实在在的狗ha2
交互 egon打ha2一下
1 print(ha2.life_value) #看看ha2的生命值 2 egg.attack(ha2) #egg打了ha2一下 3 print(ha2.life_value) #ha2掉了10点血
完整的代码
1 class Person: # 定义一个人类 2 role = 'person' # 人的角色属性都是人 3 4 def __init__(self, name, aggressivity, life_value): 5 self.name = name # 每一个角色都有自己的昵称; 6 self.aggressivity = aggressivity # 每一个角色都有自己的攻击力; 7 self.life_value = life_value # 每一个角色都有自己的生命值; 8 9 def attack(self,dog): 10 # 人可以攻击狗,这里的狗也是一个对象。 11 # 人攻击狗,那么狗的生命值就会根据人的攻击力而下降 12 dog.life_value -= self.aggressivity 13 14 class Dog: # 定义一个狗类 15 role = 'dog' # 狗的角色属性都是狗 16 17 def __init__(self, name, breed, aggressivity, life_value): 18 self.name = name # 每一只狗都有自己的昵称; 19 self.breed = breed # 每一只狗都有自己的品种; 20 self.aggressivity = aggressivity # 每一只狗都有自己的攻击力; 21 self.life_value = life_value # 每一只狗都有自己的生命值; 22 23 def bite(self,people): 24 # 狗可以咬人,这里的狗也是一个对象。 25 # 狗咬人,那么人的生命值就会根据狗的攻击力而下降 26 people.life_value -= self.aggressivity 27 28 egg = Person('egon',10,1000) #创造了一个实实在在的人egg 29 ha2 = Dog('二愣子','哈士奇',10,1000) #创造了一只实实在在的狗ha2 30 print(ha2.life_value) #看看ha2的生命值 31 egg.attack(ha2) #egg打了ha2一下 32 print(ha2.life_value) #ha2掉了10点血
1 from math import pi 2 3 class Circle: 4 ''' 5 定义了一个圆形类; 6 提供计算面积(area)和周长(perimeter)的方法 7 ''' 8 def __init__(self,radius): 9 self.radius = radius 10 11 def area(self): 12 return pi * self.radius * self.radius 13 14 def perimeter(self): 15 return 2 * pi *self.radius 16 17 18 circle = Circle(10) #实例化一个圆 19 area1 = circle.area() #计算圆面积 20 per1 = circle.perimeter() #计算圆周长 21 print(area1,per1) #打印圆面积和周长
类命名空间与对象、实例的命名空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
而类有两种属性:静态属性和动态属性
- 静态属性就是直接在类中定义的变量
- 动态属性就是定义在类中的方法
其中类的数据属性是共享给所有对象的
1 >>>id(egg.role) 2 4341594072 3 >>>id(Person.role) 4 4341594072
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
面向对象的组合用法
软件重用的重要方式除了继承之外还有另外一种方式,即:组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
1 class Weapon: 2 def prick(self, obj): # 这是该装备的主动技能,扎死对方 3 obj.life_value -= 500 # 假设攻击力是500 4 5 class Person: # 定义一个人类 6 role = 'person' # 人的角色属性都是人 7 8 def __init__(self, name): 9 self.name = name # 每一个角色都有自己的昵称; 10 self.weapon = Weapon() # 给角色绑定一个武器; 11 12 egg = Person('egon') 13 egg.weapon.prick() 14 #egg组合了一个武器的对象,可以直接egg.weapon来使用组合类中的所有方法
圆环是由两个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是内部圆的周长加上外部圆的周长。
这个时候,我们就首先实现一个圆形类,计算一个圆的周长和面积。然后在"环形类"中组合圆形的实例作为自己的属性来用
1 from math import pi 2 3 class Circle: 4 ''' 5 定义了一个圆形类; 6 提供计算面积(area)和周长(perimeter)的方法 7 ''' 8 def __init__(self,radius): 9 self.radius = radius 10 11 def area(self): 12 return pi * self.radius * self.radius 13 14 def perimeter(self): 15 return 2 * pi *self.radius 16 17 18 circle = Circle(10) #实例化一个圆 19 area1 = circle.area() #计算圆面积 20 per1 = circle.perimeter() #计算圆周长 21 print(area1,per1) #打印圆面积和周长 22 23 class Ring: 24 ''' 25 定义了一个圆环类 26 提供圆环的面积和周长的方法 27 ''' 28 def __init__(self,radius_outside,radius_inside): 29 self.outsid_circle = Circle(radius_outside) 30 self.inside_circle = Circle(radius_inside) 31 32 def area(self): 33 return self.outsid_circle.area() - self.inside_circle.area() 34 35 def perimeter(self): 36 return self.outsid_circle.perimeter() + self.inside_circle.perimeter() 37 38 39 ring = Ring(10,5) #实例化一个环形 40 print(ring.perimeter()) #计算环形的周长 41 print(ring.area()) #计算环形的面积
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python课程
1 class BirthDate: 2 def __init__(self,year,month,day): 3 self.year=year 4 self.month=month 5 self.day=day 6 7 class Couse: 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 teach(self): 20 print('teaching') 21 22 p1=Teacher('egon','male', 23 BirthDate('1995','1','27'), 24 Couse('python','28000','4 months') 25 ) 26 27 print(p1.birth.year,p1.birth.month,p1.birth.day) 28 29 print(p1.course.name,p1.course.price,p1.course.period) 30 ''' 31 运行结果: 32 27 33 python 28000 4 months 34 '''
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
初识面向对象小结
定义一个人类
1 class Person: # 定义一个人类 2 role = 'person' # 人的角色属性都是人 3 4 def __init__(self, name, aggressivity, life_value, money): 5 self.name = name # 每一个角色都有自己的昵称; 6 self.aggressivity = aggressivity # 每一个角色都有自己的攻击力; 7 self.life_value = life_value # 每一个角色都有自己的生命值; 8 self.money = money 9 10 def attack(self,dog): 11 # 人可以攻击狗,这里的狗也是一个对象。 12 # 人攻击狗,那么狗的生命值就会根据人的攻击力而下降 13 dog.life_value -= self.aggressivity
定义一个狗类
1 class Dog: # 定义一个狗类 2 role = 'dog' # 狗的角色属性都是狗 3 4 def __init__(self, name, breed, aggressivity, life_value): 5 self.name = name # 每一只狗都有自己的昵称; 6 self.breed = breed # 每一只狗都有自己的品种; 7 self.aggressivity = aggressivity # 每一只狗都有自己的攻击力; 8 self.life_value = life_value # 每一只狗都有自己的生命值; 9 10 def bite(self,people): 11 # 狗可以咬人,这里的狗也是一个对象。 12 # 狗咬人,那么人的生命值就会根据狗的攻击力而下降 13 people.life_value -= self.aggressivity
接下来,又创建一个新的兵器类。
1 class Weapon: 2 def __init__(self,name, price, aggrev, life_value): 3 self.name = name 4 self.price = price 5 self.aggrev = aggrev 6 self.life_value = life_value 7 8 def update(self, obj): #obj就是要带这个装备的人 9 obj.money -= self.price # 用这个武器的人花钱买所以对应的钱要减少 10 obj.aggressivity += self.aggrev # 带上这个装备可以让人增加攻击 11 obj.life_value += self.life_value # 带上这个装备可以让人增加生命值 12 13 def prick(self, obj): # 这是该装备的主动技能,扎死对方 14 obj.life_value -= 500 # 假设攻击力是500
测试交互
1 lance = Weapon('长矛',200,6,100) 2 egg = Person('egon',10,1000,600) #创造了一个实实在在的人egg 3 ha2 = Dog('二愣子','哈士奇',10,1000) #创造了一只实实在在的狗ha2 4 5 #egg独自力战"二愣子"深感吃力,决定穷毕生积蓄买一把武器 6 if egg.money > lance.price: #如果egg的钱比装备的价格多,可以买一把长矛 7 lance.update(egg) #egg花钱买了一个长矛防身,且自身属性得到了提高 8 egg.weapon = lance #egg装备上了长矛 9 10 print(egg.money,egg.life_value,egg.aggressivity) 11 12 print(ha2.life_value) 13 egg.attack(ha2) #egg打了ha2一下 14 print(ha2.life_value) 15 egg.weapon.prick(ha2) #发动武器技能 16 print(ha2.life_value) #ha2不敌狡猾的人类用武器取胜,血槽空了一半
按照这种思路一点一点的设计类和对象,最终你完全可以实现一个对战类游戏。
课堂训练代码:
1 class Person: 2 role = 'person' # 静态属性 3 def __init__(self,name,sex,hp,ad): 4 self.name = name # 对象属性 属性 5 self.sex = sex 6 self.hp = hp #血量 7 self.ad = ad #攻击力 8 def attack(self,d): 9 d.hp -= self.ad 10 print('%s攻击了%s,%s掉了%s点血'%(self.name,d.name,d.name,self.ad)) 11 12 class Dog: 13 def __init__(self,name,kind,hp,ad): 14 self.name = name 15 self.kind = kind 16 self.hp = hp 17 self.ad = ad 18 def bite(self,p): 19 p.hp -= self.ad 20 print('%s咬了%s一口,%s掉了%s点血' % (self.name, p.name, p.name, self.ad)) 21 22 alex = Person('a_sb','不详',1,5) 23 boss_jin = Person('金老板','女',20,50) 24 teddy = Dog('笨笨','teddy',50,10) 25 teddy.bite(alex) 26 print(alex.hp) 27 boss_jin.attack(teddy) 28 print(teddy.hp) 29 30 # alex.attack() # Person.attack(alex) 31 # boss_jin.attack() # Person.attack(boss_jin) 32 33 # 人和狗 34 # 4个技能 玩家可以选择技能
1 class Person: 2 # role = 'person' # 静态属性 3 # def __init__(self,name,sex,hp,ad): 4 # self.name = name # 对象属性 属性 5 # self.sex = sex 6 # self.hp = hp 7 # self.ad = ad 8 # def attack(self): 9 # self.hobby = 'girl' 10 # print('%s发起了一次攻击'%self.name) 11 # 12 # alex = Person('a_sb','不详',1,5) 13 # alex.attack() # Person.attack(alex) 14 # alex.age = 81 15 # # alex --> Person 16 # # Person实例化了alex 17 # print(alex.__dict__) 18 19 # alex.name #alex 指向我自己的内存空间 在自己的内存空间里找到name 20 # alex.attack #alex 先找自己的内存空间 再找到类对象指针 再根据类对象指针找到类 再通过类找到attack 21 # 对象的内存空间里: 只存储对象的属性,而不存储方法和静态属性 22 # 方法和静态属性都存储在类的内存空间中 23 # 为了节省内存,让多个对象去共享类中的资源 24 25 26 # class Person: 27 # role = 'person' # 静态属性 28 # def __init__(self,name,sex,hp,ad): 29 # self.name = name # 对象属性 属性 30 # self.sex = sex 31 # self.hp = hp 32 # self.ad = ad 33 # self.attack = 'hahaha' 34 # def attack(self): 35 # print('%s发起了一次攻击'%self.name) 36 # 37 # alex = Person('a_sb','不详',1,5) 38 # boss_jin = Person('金老板','女',50,20) 39 # print(alex.role) 40 # print(boss_jin.role) 41 # alex.role = 'dog' 42 # print(alex.role) 43 # print(boss_jin.role) # dog or ? person 44 45 46 47 # class Person: 48 # role = 'person' # 静态属性 49 # def __init__(self,name,sex,hp,ad): 50 # self.name = name # 对象属性 属性 51 # self.sex = sex 52 # self.hp = hp 53 # self.ad = ad 54 # self.attack = 'hahaha' 55 # def attack(self): 56 # print('%s发起了一次攻击'%self.name) 57 # 58 # alex = Person('a_sb','不详',1,5) 59 # boss_jin = Person('金老板','女',50,20) 60 # print(alex.role) 61 # print(boss_jin.role) 62 # alex.role = 'dog' 63 # print(alex.role) 64 # 模拟人生 65 # class Person: 66 # money = 0 67 # def __init__(self,name): 68 # self.name = name 69 # def work(self): 70 # print(self.name,'工作,赚了1000块钱') 71 # Person.money += 1000 72 # 73 # father = Person('father') 74 # mother = Person('mother') 75 # mother.work() 76 # father.work() 77 # print(Person.money) 78 79 80 # 写一个类 完成一个功能 : 可以统计这个类有几个对象 81 # class Foo: 82 # count = 0 83 # def __init__(self): 84 # Foo.count += 1 85 # f1 = Foo() 86 # f2 = Foo() 87 # f3 = Foo() 88 # f4 = Foo() 89 # f5 = Foo() 90 # print(Foo.count) # 91 92 93 94 # class Person: 95 # money = [1] 96 # def __init__(self,name): 97 # self.name = name 98 # def work(self): 99 # print(self.name,'工作,赚了1000块钱') 100 # self.money[0] += 1000 101 # 102 # father = Person('father') 103 # mother = Person('mother') 104 # mother.work() 105 # father.work() 106 # print(Person.money) # 2000 or 0? 107 108 # class Person: 109 # money = [0] 110 # def __init__(self,name): 111 # self.name = name 112 # def work(self): 113 # print(self.name,'工作,赚了1000块钱') 114 # Person.money = [Person.money[0] + 1000] 115 # 116 # father = Person('father') 117 # mother = Person('mother') 118 # mother.work() 119 # father.work() 120 # print(Person.money) 121 122 # 对象属性是独有的,静态属性和方法是共享的 123 # 对象使用名字:先找自己内存空间中的,再找类的内存空间中的 124 # 类名.静态变量名 :对于静态属性的修改,应该使用类名直接修改
1 圆 2 # 计算圆的周长 2 pi r 3 # 计算圆的面积 pi r**2 4 # 5个圆 5 # 1,3,5,7,9 6 from math import pi 7 class Circle: 8 def __init__(self,r): 9 self.r = r 10 def cal_area(self): 11 ''' 12 计算圆面积的方法 13 :return:返回值是float数据类型的面积 14 ''' 15 return pi*self.r**2 16 def cal_perimeter(self): 17 ''' 18 计算圆周长的方法 19 :return:返回值是float数据类型的周长 20 ''' 21 return pi * self.r * 2 22 for i in range(1,10,2): 23 c1 = Circle(i) 24 print(c1.cal_area()) 25 print(c1.cal_perimeter()) 26 # 类 属性 和 方法 27 # 半径 28 # 计算面积 计算周长 29 # 程序的解耦 30 # 当计算的规模足够大的时候 我们应该在编码的过程当中让操作尽量原子化 31 # 尽量用返回值来代替print 32 33 # 面向对象的基础 34 35 # 用面向对象的思想 36 # 1.博客上的练一练 37 # 2.计算圆环的面积和周长 38 # 3.默写 交互 39 # 4.校园管理系统第一步























浙公网安备 33010602011771号