|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 漆雕古代 于 2016-2-22 16:20 编辑
定义两个类如下:
- class AA():
- a = 1
- def am(self,x):
- self.a = x
- class BB():
- def __init__(self):
- self.a = 1
- def am(self,x):
- self.a = x
复制代码
然后进行如下操作
会发现BB.a打不出来
应该区别仅仅在这里,一旦将类实例化以后就没有区别了吧,通过方法修改属性是没有区别的
这个结论是得到好几位鱼C前辈认可的
好的,现在各位请看,这段代码我之前已经发过,在那个贴中我在@Lnan95的帮助下找到了问题,但是如果以上的结论成立,请各位比较一下一下两段代码:(各位可以先跳过代码读完整个帖子,当然我建议还是先看看69-71行的代码,因为这是两串代码的唯一区别)
0:
- import random as r
- class Main:
- # 这里是我是希望通过1、2、3、4分别代表上下左右四个方向
- def getdirection(self):
- return r.randint(1,4)
- # 这里只是通过一个简单的函数确认 coordonnes 坐标的横纵坐标有没有超出范围
- # coordonnes 会在后面定义为一个元组代表坐标
- def valider_limite(self, coordonnes):
- for it in coordonnes:
- if it < 0 or it > 10:
- return 1
- return 0
-
- def direction_principe(self, direction, coordonnes, deplace): # direction是传入由本类第一个方法返回的1-4中的一个数字
- # coordoones是传入坐标的参数 list类(方便更改)
- # deplace是由后来的两个子类中的方法获得的可以行动的步数1或2
- # 分别对应如下
- # 1: y坐标+1
- # 2: y坐标-1
- # 3: x坐标+1
- # 4: x坐标-1
- # 注:横纵坐标分别是变量 coordonnes 的 [0] 和 [1]
- if direction == 1:
- coordonnes[1] += deplace
- # 一下这里是判断变化后的坐标有没有超出范围,如果超出将会以取两倍相反数的形式将坐标更换为正确的形式
- if self.valider_limite(coordonnes):
- coordonnes[1] -= 2*deplace
- elif direction == 2:
- coordonnes[1] -= deplace
- if self.valider_limite(coordonnes):
- coordonnes[1] += 2*deplace
- elif direction == 3:
- coordonnes[0] -= deplace
- if self.valider_limite(coordonnes):
- coordonnes[0] += 2*deplace
- else:
- coordonnes[0] += deplace
- if self.valider_limite(coordonnes):
- coordonnes[0] -= 2*deplace
- return coordonnes # 这里返回新的移动后的坐标
-
-
-
- class Turtle(Main):
- PV = 100 # PV 是乌龟的体力属性
- coordonnes = [r.randint(0, 10),r.randint(0, 10)] # coordonnes是乌龟初始随机生成的坐标
- # 第一个方法是返回随机的移动步数1或0,获取的数值将传入Main类中的过去新坐标的方法作为参数
- def getdeplace(self):
- return r.randint(1, 2)
- # 调用父类的方法获得新的坐标
- def deplace_action(self):
- self.coordonnes = self.direction_principe(self.getdirection(), # 父类的第一个方法用于获取随机方向
- self.coordonnes, # 乌龟现在的坐标
- self.getdeplace()) # 乌龟本回合随机前进的步数
- self.PV -= 1 # 获取新坐标后体力-1
- # 就是吃的方法
- def manger(self):
- self.PV += 20 # 吃一条鱼加20点PV
- if self.PV > 100: # 判断体力是否大于上限
- self.PV = 100
- class Fish(Main):
-
- deplace = 1 # 鱼的移动步数永远是1
- coordonnes = [r.randint(0, 10),r.randint(0, 10)] # 生成鱼的初始坐标 coordonnes
- def deplace_action(self):
- self.coordonnes = self.direction_principe(self.getdirection(), # 父类的第一个方法用于获取随机方向
- self.coordonnes, # 鱼儿现在的坐标
- self.deplace) # 鱼儿本回合前进的步数1
- # 此函数用于初始化十条实例化的鱼儿到一个列表
- def pret():
- fish = list()
- for it in range(10):
- new_fish = Fish()
- fish.append(new_fish)
- return fish
- def jeu_principe(): # 相当于就是主函数咯
- turtle = Turtle()
- fish = pret()
- count = 0 # 这个是我为了测试家的计算回合数的变量
- while 1:
- if turtle.PV == 0:
- print('乌龟眼前一黑。。。\n共经过了%d个回合' % count)
- break
- if len(fish) == 0:
- print('鱼儿全部被吃掉了。。。\n共经过了%d个回合' % count)
- break
-
- count += 1 # 这个是我为了测试家的计算回合数的变量
-
- if count % 10 == 0 or count == 1: # 第一回合执行,以后每隔十回合执行一次
- print('现在是第%d回合' % count)
- print('乌龟体力还剩下%dPV' % turtle.PV)
- print('鱼儿还剩下%d条' % len(fish))
- pos = turtle.deplace_action() # 乌龟先获得新坐标
- for each_one in fish: # 这一步让每一只鱼儿都获得新的坐标
- print('###',each_one.coordonnes,'###')
- each_one.deplace_action()
- print(turtle.coordonnes)
- for each_fish in fish[:]: ### [:]是我看了小甲鱼参考代码后改对的,之前一直报错
- # 这里就是判断乌龟的坐标和鱼儿的坐标是否重合
- if turtle.coordonnes == each_fish.coordonnes:
- turtle.manger()
- fish.remove(each_fish)
- # 以下两条是我测试用的,事实证明我如果不这样就发现不了这个问题。。。
- print('*'*50)
- if __name__ == '__main__':
- jeu_principe()
-
复制代码
1:- import random as r
- class Main:
- # 这里是我是希望通过1、2、3、4分别代表上下左右四个方向
- def getdirection(self):
- return r.randint(1,4)
- # 这里只是通过一个简单的函数确认 coordonnes 坐标的横纵坐标有没有超出范围
- # coordonnes 会在后面定义为一个元组代表坐标
- def valider_limite(self, coordonnes):
- for it in coordonnes:
- if it < 0 or it > 10:
- return 1
- return 0
-
- def direction_principe(self, direction, coordonnes, deplace): # direction是传入由本类第一个方法返回的1-4中的一个数字
- # coordoones是传入坐标的参数 list类(方便更改)
- # deplace是由后来的两个子类中的方法获得的可以行动的步数1或2
- # 分别对应如下
- # 1: y坐标+1
- # 2: y坐标-1
- # 3: x坐标+1
- # 4: x坐标-1
- # 注:横纵坐标分别是变量 coordonnes 的 [0] 和 [1]
- if direction == 1:
- coordonnes[1] += deplace
- # 一下这里是判断变化后的坐标有没有超出范围,如果超出将会以取两倍相反数的形式将坐标更换为正确的形式
- if self.valider_limite(coordonnes):
- coordonnes[1] -= 2*deplace
- elif direction == 2:
- coordonnes[1] -= deplace
- if self.valider_limite(coordonnes):
- coordonnes[1] += 2*deplace
- elif direction == 3:
- coordonnes[0] -= deplace
- if self.valider_limite(coordonnes):
- coordonnes[0] += 2*deplace
- else:
- coordonnes[0] += deplace
- if self.valider_limite(coordonnes):
- coordonnes[0] -= 2*deplace
- return coordonnes # 这里返回新的移动后的坐标
-
-
-
- class Turtle(Main):
- PV = 100 # PV 是乌龟的体力属性
- coordonnes = [r.randint(0, 10),r.randint(0, 10)] # coordonnes是乌龟初始随机生成的坐标
- # 第一个方法是返回随机的移动步数1或0,获取的数值将传入Main类中的过去新坐标的方法作为参数
- def getdeplace(self):
- return r.randint(1, 2)
- # 调用父类的方法获得新的坐标
- def deplace_action(self):
- self.coordonnes = self.direction_principe(self.getdirection(), # 父类的第一个方法用于获取随机方向
- self.coordonnes, # 乌龟现在的坐标
- self.getdeplace()) # 乌龟本回合随机前进的步数
- self.PV -= 1 # 获取新坐标后体力-1
- # 就是吃的方法
- def manger(self):
- self.PV += 20 # 吃一条鱼加20点PV
- if self.PV > 100: # 判断体力是否大于上限
- self.PV = 100
- class Fish(Main):
- def __init__(self):
- self.deplace = 1 # 鱼的移动步数永远是1
- self.coordonnes = [r.randint(0, 10),r.randint(0, 10)] # 生成鱼的初始坐标 coordonnes
- def deplace_action(self):
- self.coordonnes = self.direction_principe(self.getdirection(), # 父类的第一个方法用于获取随机方向
- self.coordonnes, # 鱼儿现在的坐标
- self.deplace) # 鱼儿本回合前进的步数1
- # 此函数用于初始化十条实例化的鱼儿到一个列表
- def pret():
- fish = list()
- for it in range(10):
- new_fish = Fish()
- fish.append(new_fish)
- return fish
- def jeu_principe(): # 相当于就是主函数咯
- turtle = Turtle()
- fish = pret()
- count = 0 # 这个是我为了测试家的计算回合数的变量
- while 1:
- if turtle.PV == 0:
- print('乌龟眼前一黑。。。\n共经过了%d个回合' % count)
- break
- if len(fish) == 0:
- print('鱼儿全部被吃掉了。。。\n共经过了%d个回合' % count)
- break
-
- count += 1 # 这个是我为了测试家的计算回合数的变量
-
- if count % 10 == 0 or count == 1: # 第一回合执行,以后每隔十回合执行一次
- print('现在是第%d回合' % count)
- print('乌龟体力还剩下%dPV' % turtle.PV)
- print('鱼儿还剩下%d条' % len(fish))
- pos = turtle.deplace_action() # 乌龟先获得新坐标
- for each_one in fish: # 这一步让每一只鱼儿都获得新的坐标
- print('###',each_one.coordonnes,'###')
- each_one.deplace_action()
- print(turtle.coordonnes)
- for each_fish in fish[:]: ### [:]是我看了小甲鱼参考代码后改对的,之前一直报错
- # 这里就是判断乌龟的坐标和鱼儿的坐标是否重合
- if turtle.coordonnes == each_fish.coordonnes:
- turtle.manger()
- fish.remove(each_fish)
- # 以下两条是我测试用的,事实证明我如果不这样就发现不了这个问题。。。
- print('*'*50)
- if __name__ == '__main__':
- jeu_principe()
-
复制代码
这两串代码只有在69-71行存在定义类属性的方式的区别,其他代码完全一样(目的都是完成37课课后作业动动手1)
但是请各位分别run一下这两段代码,我们会发现0号的代码十条鱼永远都会在同一个回合全部一起离奇死亡!而1号却可以正常运行
我研究了很久也不明白是怎么一回事,print了一下坐标发现十条鱼儿死的那个回合他们的坐标都不一样,乌龟是怎么一下吃了他们的?
如图:
是我的代码哪里还有什么问题吗?还是说开篇我说的那个结论是错的?
本帖最后由 小小大鱼 于 2016-2-22 10:29 编辑
这个问题要解释起来还真有点麻烦,我也是仔细想了好久才想明白的。(下面乌龟体力用完的情况不讨论,只讨论同时挂掉的情况)
但是说明:这是个人理解,不一定对,见谅!
1.上面我已经贴过类属性与实例属性不同之处,还以这为例:
- class AA():
- a = 1
- def am(self):
- self.a =2
- class BB():
- def __init__(self):
- self.a = 1
- def am(self):
- self.a = 3
- print(AA.a)#a为类属性
- #print(BB.a)#a为实例属性,只有将BB这个类实例化后才具有a属性,否则报错
- #实例化
- example1 = AA()
- example2 = BB()
- #因为AA本身只有类属性a,而没有实例属性self.a
- print(dir(AA))
- print(example1.a,example2.a)
- #当调用example1.a时,程序会先到example所属的类:AA中找一个名为'a'的属性,
- #如果有,则返回该值作为self.a(实像例属性)的初始值,否则出错
- #这里相当于为AA这个类创建了self.a这个实例属性,类似BB中的__init__定义的self.a(python中的第一次赋值视为变量的定义!)
复制代码
2.再回到你的代码:
也就是说在每次调用下面这个方法时,self.coordonnes.self.deplace都会重新赋值一次:
- def deplace_action(self):
- self.coordonnes = self.direction_principe(self.getdirection(),self.coordonnes,self.deplace)
复制代码
Turtle .Fish都是这样
副作用:在没有重新调用该方法之前,直接调用self.coordonnes,self.deplace一定与上一次调用此方法产生
的值相同
- print(turtle.coordonnes)#同样的道理,turtle.coordonnes的坐标是pos = turtle.deplace_action调用时产生的坐标self.coordonnes
复制代码
所以最后的判断:
- if turtle.coordonnes == each_fish.coordonnes:
复制代码
只有一种情况下会成立,就是调用each_fish.coordonnes时产生的坐标与pos = turtle.deplace_action产生的坐标相同,否则这个判断一直不成立,导致Turtle'精尽龟亡'。
此时更大的副作用来了:
因为:each_fish.coordonnes会对Fish类的self.coordonnes重新赋值,当后面再次使用each_fish.coordonnes时就会直接引用self.coordonnes,结果就是判断时所有的鱼的坐标完全相同
导致一旦turtle.coordonnes == each_fish.coordonnes就会'Kill All'
下面我在判断语句处加了几句,用作对比
- print(turtle.coordonnes)#同样的道理,turtle.coordonnes的坐标是pos = turtle.deplace_action调用时产生的坐标
- for each_fish in fish[:]: ### [:]是我看了小甲鱼参考代码后改对的,之前一直报错
- # 这里就是判断乌龟的坐标和鱼儿的坐标是否重合
- print(each_fish.coordonnes)#a.输出每条鱼的坐标,与后面b作对比
- if turtle.coordonnes == each_fish.coordonnes:
- print('坐标是:\n')
- print(turtle.coordonnes,each_fish.coordonnes)
- turtle.manger()
- fish.remove(each_fish)
- # 以下两条是我测试用的,事实证明我如果不这样就发现不了这个问题。。。
- print('*'*50)
- else:
- print(turtle.coordonnes,each_fish.coordonnes)#b.不管怎样都打印出来,与前面的a对比
复制代码
看运行结果:
@~风介~ @小甲鱼请多指教!
|
|