鱼C论坛

 找回密码
 立即注册
查看: 2108|回复: 13

[已解决]关于类属性的问题

[复制链接]
发表于 2016-2-13 16:47:32 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 漆雕古代 于 2016-2-22 16:20 编辑

定义两个类如下:
  1. class AA():
  2.         a = 1
  3.         def am(self,x):
  4.                 self.a = x
  5. class BB():
  6.         def __init__(self):
  7.                 self.a = 1
  8.         def am(self,x):
  9.                 self.a = x
复制代码



然后进行如下操作
  1. print(AA.a)
  2. print(BB.a)
复制代码


会发现BB.a打不出来

应该区别仅仅在这里,一旦将类实例化以后就没有区别了吧,通过方法修改属性是没有区别的

这个结论是得到好几位鱼C前辈认可的


好的,现在各位请看,这段代码我之前已经发过,在那个贴中我在@Lnan95的帮助下找到了问题,但是如果以上的结论成立,请各位比较一下一下两段代码:(各位可以先跳过代码读完整个帖子,当然我建议还是先看看69-71行的代码,因为这是两串代码的唯一区别

0:
  1. import random as r


  2. class Main:
  3.     # 这里是我是希望通过1、2、3、4分别代表上下左右四个方向
  4.     def getdirection(self):
  5.         return r.randint(1,4)

  6.     # 这里只是通过一个简单的函数确认 coordonnes 坐标的横纵坐标有没有超出范围
  7.     #                           coordonnes 会在后面定义为一个元组代表坐标
  8.     def valider_limite(self, coordonnes):
  9.         for it in coordonnes:
  10.             if it < 0 or it > 10:
  11.                 return 1
  12.         return 0
  13.    
  14.     def direction_principe(self, direction, coordonnes, deplace):   # direction是传入由本类第一个方法返回的1-4中的一个数字
  15.                                                                     # coordoones是传入坐标的参数 list类(方便更改)
  16.                                                                     # deplace是由后来的两个子类中的方法获得的可以行动的步数1或2
  17.         # 分别对应如下
  18.         #           1:  y坐标+1
  19.         #           2:  y坐标-1
  20.         #           3:  x坐标+1
  21.         #           4:  x坐标-1
  22.         #   注:横纵坐标分别是变量 coordonnes 的 [0] 和 [1]
  23.         if direction == 1:
  24.             coordonnes[1] += deplace
  25.             # 一下这里是判断变化后的坐标有没有超出范围,如果超出将会以取两倍相反数的形式将坐标更换为正确的形式   
  26.             if self.valider_limite(coordonnes):
  27.                 coordonnes[1] -= 2*deplace
  28.         elif direction == 2:
  29.             coordonnes[1] -= deplace
  30.             if self.valider_limite(coordonnes):
  31.                 coordonnes[1] += 2*deplace
  32.         elif direction == 3:
  33.             coordonnes[0] -= deplace
  34.             if self.valider_limite(coordonnes):
  35.                 coordonnes[0] += 2*deplace
  36.         else:
  37.             coordonnes[0] += deplace
  38.             if self.valider_limite(coordonnes):
  39.                 coordonnes[0] -= 2*deplace
  40.         return coordonnes   # 这里返回新的移动后的坐标
  41.             
  42.    
  43.         
  44. class Turtle(Main):
  45.     PV = 100                                            # PV 是乌龟的体力属性
  46.     coordonnes = [r.randint(0, 10),r.randint(0, 10)]    # coordonnes是乌龟初始随机生成的坐标

  47.     # 第一个方法是返回随机的移动步数1或0,获取的数值将传入Main类中的过去新坐标的方法作为参数
  48.     def getdeplace(self):
  49.         return r.randint(1, 2)

  50.     # 调用父类的方法获得新的坐标
  51.     def deplace_action(self):
  52.         self.coordonnes = self.direction_principe(self.getdirection(),  # 父类的第一个方法用于获取随机方向
  53.                                                  self.coordonnes,       # 乌龟现在的坐标
  54.                                                  self.getdeplace())     # 乌龟本回合随机前进的步数
  55.         self.PV -= 1 # 获取新坐标后体力-1

  56.     # 就是吃的方法
  57.     def manger(self):
  58.         self.PV += 20       # 吃一条鱼加20点PV
  59.         if self.PV > 100:   # 判断体力是否大于上限
  60.             self.PV = 100

  61. class Fish(Main):
  62.    
  63.     deplace = 1                                         # 鱼的移动步数永远是1
  64.     coordonnes = [r.randint(0, 10),r.randint(0, 10)]    # 生成鱼的初始坐标 coordonnes
  65.     def deplace_action(self):
  66.         self.coordonnes = self.direction_principe(self.getdirection(),  # 父类的第一个方法用于获取随机方向
  67.                                                   self.coordonnes,      # 鱼儿现在的坐标
  68.                                                   self.deplace)         # 鱼儿本回合前进的步数1


  69. # 此函数用于初始化十条实例化的鱼儿到一个列表
  70. def pret():
  71.     fish = list()
  72.     for it in range(10):
  73.         new_fish = Fish()
  74.         fish.append(new_fish)
  75.     return fish

  76. def jeu_principe(): # 相当于就是主函数咯
  77.     turtle = Turtle()
  78.     fish = pret()
  79.     count = 0 # 这个是我为了测试家的计算回合数的变量

  80.     while 1:

  81.         if turtle.PV == 0:
  82.             print('乌龟眼前一黑。。。\n共经过了%d个回合' % count)
  83.             break
  84.         if len(fish) == 0:
  85.             print('鱼儿全部被吃掉了。。。\n共经过了%d个回合' % count)
  86.             break
  87.         
  88.         count += 1 # 这个是我为了测试家的计算回合数的变量
  89.         
  90.         if count % 10 == 0 or count == 1: # 第一回合执行,以后每隔十回合执行一次
  91.             print('现在是第%d回合' % count)
  92.             print('乌龟体力还剩下%dPV' % turtle.PV)
  93.             print('鱼儿还剩下%d条' % len(fish))

  94.         pos = turtle.deplace_action()    # 乌龟先获得新坐标
  95.         for each_one in fish:       # 这一步让每一只鱼儿都获得新的坐标
  96.             print('###',each_one.coordonnes,'###')
  97.             each_one.deplace_action()
  98.         print(turtle.coordonnes)
  99.         for each_fish in fish[:]: ### [:]是我看了小甲鱼参考代码后改对的,之前一直报错
  100.             # 这里就是判断乌龟的坐标和鱼儿的坐标是否重合
  101.             if turtle.coordonnes == each_fish.coordonnes:
  102.                 turtle.manger()
  103.                 fish.remove(each_fish)
  104.                 # 以下两条是我测试用的,事实证明我如果不这样就发现不了这个问题。。。
  105.                 print('*'*50)

  106. if __name__ == '__main__':
  107.     jeu_principe()
  108.             
复制代码


1:
  1. import random as r


  2. class Main:
  3.     # 这里是我是希望通过1、2、3、4分别代表上下左右四个方向
  4.     def getdirection(self):
  5.         return r.randint(1,4)

  6.     # 这里只是通过一个简单的函数确认 coordonnes 坐标的横纵坐标有没有超出范围
  7.     #                           coordonnes 会在后面定义为一个元组代表坐标
  8.     def valider_limite(self, coordonnes):
  9.         for it in coordonnes:
  10.             if it < 0 or it > 10:
  11.                 return 1
  12.         return 0
  13.    
  14.     def direction_principe(self, direction, coordonnes, deplace):   # direction是传入由本类第一个方法返回的1-4中的一个数字
  15.                                                                     # coordoones是传入坐标的参数 list类(方便更改)
  16.                                                                     # deplace是由后来的两个子类中的方法获得的可以行动的步数1或2
  17.         # 分别对应如下
  18.         #           1:  y坐标+1
  19.         #           2:  y坐标-1
  20.         #           3:  x坐标+1
  21.         #           4:  x坐标-1
  22.         #   注:横纵坐标分别是变量 coordonnes 的 [0] 和 [1]
  23.         if direction == 1:
  24.             coordonnes[1] += deplace
  25.             # 一下这里是判断变化后的坐标有没有超出范围,如果超出将会以取两倍相反数的形式将坐标更换为正确的形式   
  26.             if self.valider_limite(coordonnes):
  27.                 coordonnes[1] -= 2*deplace
  28.         elif direction == 2:
  29.             coordonnes[1] -= deplace
  30.             if self.valider_limite(coordonnes):
  31.                 coordonnes[1] += 2*deplace
  32.         elif direction == 3:
  33.             coordonnes[0] -= deplace
  34.             if self.valider_limite(coordonnes):
  35.                 coordonnes[0] += 2*deplace
  36.         else:
  37.             coordonnes[0] += deplace
  38.             if self.valider_limite(coordonnes):
  39.                 coordonnes[0] -= 2*deplace
  40.         return coordonnes   # 这里返回新的移动后的坐标
  41.             
  42.    
  43.         
  44. class Turtle(Main):
  45.     PV = 100                                            # PV 是乌龟的体力属性
  46.     coordonnes = [r.randint(0, 10),r.randint(0, 10)]    # coordonnes是乌龟初始随机生成的坐标

  47.     # 第一个方法是返回随机的移动步数1或0,获取的数值将传入Main类中的过去新坐标的方法作为参数
  48.     def getdeplace(self):
  49.         return r.randint(1, 2)

  50.     # 调用父类的方法获得新的坐标
  51.     def deplace_action(self):
  52.         self.coordonnes = self.direction_principe(self.getdirection(),  # 父类的第一个方法用于获取随机方向
  53.                                                  self.coordonnes,       # 乌龟现在的坐标
  54.                                                  self.getdeplace())     # 乌龟本回合随机前进的步数
  55.         self.PV -= 1 # 获取新坐标后体力-1

  56.     # 就是吃的方法
  57.     def manger(self):
  58.         self.PV += 20       # 吃一条鱼加20点PV
  59.         if self.PV > 100:   # 判断体力是否大于上限
  60.             self.PV = 100

  61. class Fish(Main):
  62.     def __init__(self):
  63.         self.deplace = 1                                         # 鱼的移动步数永远是1
  64.         self.coordonnes = [r.randint(0, 10),r.randint(0, 10)]    # 生成鱼的初始坐标 coordonnes
  65.     def deplace_action(self):
  66.         self.coordonnes = self.direction_principe(self.getdirection(),  # 父类的第一个方法用于获取随机方向
  67.                                                   self.coordonnes,      # 鱼儿现在的坐标
  68.                                                   self.deplace)         # 鱼儿本回合前进的步数1


  69. # 此函数用于初始化十条实例化的鱼儿到一个列表
  70. def pret():
  71.     fish = list()
  72.     for it in range(10):
  73.         new_fish = Fish()
  74.         fish.append(new_fish)
  75.     return fish

  76. def jeu_principe(): # 相当于就是主函数咯
  77.     turtle = Turtle()
  78.     fish = pret()
  79.     count = 0 # 这个是我为了测试家的计算回合数的变量

  80.     while 1:

  81.         if turtle.PV == 0:
  82.             print('乌龟眼前一黑。。。\n共经过了%d个回合' % count)
  83.             break
  84.         if len(fish) == 0:
  85.             print('鱼儿全部被吃掉了。。。\n共经过了%d个回合' % count)
  86.             break
  87.         
  88.         count += 1 # 这个是我为了测试家的计算回合数的变量
  89.         
  90.         if count % 10 == 0 or count == 1: # 第一回合执行,以后每隔十回合执行一次
  91.             print('现在是第%d回合' % count)
  92.             print('乌龟体力还剩下%dPV' % turtle.PV)
  93.             print('鱼儿还剩下%d条' % len(fish))

  94.         pos = turtle.deplace_action()    # 乌龟先获得新坐标
  95.         for each_one in fish:       # 这一步让每一只鱼儿都获得新的坐标
  96.             print('###',each_one.coordonnes,'###')
  97.             each_one.deplace_action()
  98.         print(turtle.coordonnes)
  99.         for each_fish in fish[:]: ### [:]是我看了小甲鱼参考代码后改对的,之前一直报错
  100.             # 这里就是判断乌龟的坐标和鱼儿的坐标是否重合
  101.             if turtle.coordonnes == each_fish.coordonnes:
  102.                 turtle.manger()
  103.                 fish.remove(each_fish)
  104.                 # 以下两条是我测试用的,事实证明我如果不这样就发现不了这个问题。。。
  105.                 print('*'*50)

  106. if __name__ == '__main__':
  107.     jeu_principe()
  108.             
复制代码


这两串代码只有在69-71行存在定义类属性的方式的区别,其他代码完全一样(目的都是完成37课课后作业动动手1)

但是请各位分别run一下这两段代码,我们会发现0号的代码十条鱼永远都会在同一个回合全部一起离奇死亡!而1号却可以正常运行


我研究了很久也不明白是怎么一回事,print了一下坐标发现十条鱼儿死的那个回合他们的坐标都不一样,乌龟是怎么一下吃了他们的?

如图: old_2016-02-13 (4).png

是我的代码哪里还有什么问题吗?还是说开篇我说的那个结论是错的?
最佳答案
2016-2-22 10:24:36
本帖最后由 小小大鱼 于 2016-2-22 10:29 编辑
漆雕古代 发表于 2016-2-22 01:43
对啊,两串代码唯一的区别就是那么几行,你知道为什么吗?

从打印出来的数据来看,十条鱼的坐标确实 ...


这个问题要解释起来还真有点麻烦,我也是仔细想了好久才想明白的。(下面乌龟体力用完的情况不讨论,只讨论同时挂掉的情况)
但是说明:这是个人理解,不一定对,见谅!
1.上面我已经贴过类属性与实例属性不同之处,还以这为例:
  1. class AA():
  2.         a = 1
  3.         def am(self):
  4.                 self.a =2
  5. class BB():
  6.         def __init__(self):
  7.                 self.a = 1
  8.         def am(self):
  9.                 self.a = 3

  10. print(AA.a)#a为类属性
  11. #print(BB.a)#a为实例属性,只有将BB这个类实例化后才具有a属性,否则报错

  12. #实例化
  13. example1 = AA()
  14. example2 = BB()
  15. #因为AA本身只有类属性a,而没有实例属性self.a
  16. print(dir(AA))
  17. print(example1.a,example2.a)
  18. #当调用example1.a时,程序会先到example所属的类:AA中找一个名为'a'的属性,
  19. #如果有,则返回该值作为self.a(实像例属性)的初始值,否则出错
  20. #这里相当于为AA这个类创建了self.a这个实例属性,类似BB中的__init__定义的self.a(python中的第一次赋值视为变量的定义!)
复制代码

2.再回到你的代码:
也就是说在每次调用下面这个方法时,self.coordonnes.self.deplace都会重新赋值一次:
  1. def deplace_action(self):
  2.         self.coordonnes = self.direction_principe(self.getdirection(),self.coordonnes,self.deplace)
复制代码

Turtle .Fish都是这样
副作用:在没有重新调用该方法之前,直接调用self.coordonnes,self.deplace一定与上一次调用此方法产生
的值相同
  1. print(turtle.coordonnes)#同样的道理,turtle.coordonnes的坐标是pos = turtle.deplace_action调用时产生的坐标self.coordonnes
复制代码

所以最后的判断:
  1. 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'
下面我在判断语句处加了几句,用作对比
  1. print(turtle.coordonnes)#同样的道理,turtle.coordonnes的坐标是pos = turtle.deplace_action调用时产生的坐标
  2.         for each_fish in fish[:]: ### [:]是我看了小甲鱼参考代码后改对的,之前一直报错
  3.             # 这里就是判断乌龟的坐标和鱼儿的坐标是否重合
  4.             print(each_fish.coordonnes)#a.输出每条鱼的坐标,与后面b作对比
  5.             if turtle.coordonnes == each_fish.coordonnes:
  6.                 print('坐标是:\n')
  7.                 print(turtle.coordonnes,each_fish.coordonnes)
  8.                 turtle.manger()
  9.                 fish.remove(each_fish)
  10.                 # 以下两条是我测试用的,事实证明我如果不这样就发现不了这个问题。。。
  11.                 print('*'*50)
  12.             else:
  13.                 print(turtle.coordonnes,each_fish.coordonnes)#b.不管怎样都打印出来,与前面的a对比
复制代码


看运行结果:
@~风介~ @小甲鱼请多指教!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-2-14 10:50:08 | 显示全部楼层
我反复尝试你的两段代码, 都没有出现你说的
在同一个回合全部一起离奇死亡

不过我猜测问题所在是Python的random模块产生的是伪随机数
至于那个类的属性和构造函数里面定义的属性是不是一回事, 你就不要纠结啦
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-2-21 14:32:59 | 显示全部楼层
本帖最后由 小小大鱼 于 2016-2-21 14:34 编辑

时间过去有点久啊,不知道解决没有?

1.代码略长,没看
2.希望对你有帮助
  1. class AA():
  2.         a = 1
  3.         def am(self,x):
  4.                 self.a = x
  5. class BB():
  6.         def __init__(self):
  7.                 self.a = 1
  8.         def am(self,x):
  9.                 self.a = x

  10. print(AA.a)#a为类属性
  11. #print(BB.a)#a为实例属性,只有将BB这个类实例化后才具有a属性,否则报错

  12. #实例化
  13. ex1 = AA()
  14. ex2 = BB()

  15. print(ex1.a)
  16. print(ex2.a)
  17. #以类名.属性名(AA.a)引用时,只能引用类属性 a=1
  18. #以实例名.属性名(ex1.a)引用时,优先引用实例属性self.a。前提:类属性名与实例属性名一样,这里都是a

  19. #通过方法修改属性
  20. #因为"#以实例名.属性名(ex1.a)引用时,优先引用实例属性self.a",所以用方法修改属性,很明显类属性并没有修改
  21. setattr(ex1,'a',20)
  22. setattr(ex2,'a',20)
  23. print(ex1.a)
  24. print(AA.a)
  25. print(ex2.a)
复制代码

运行结果:
  1. 1
  2. 1
  3. 1
  4. 20
  5. 1
  6. 20
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-2-21 19:51:14 | 显示全部楼层
小小大鱼 发表于 2016-2-21 14:32
时间过去有点久啊,不知道解决没有?

1.代码略长,没看

恩,谢谢,时间确实有点久了,不过确实还没有解决。因为hldh216说他的机子上没问题。。。所以我默认为只有我的机子有问题,不过如果你愿意测试一下当然再感谢不过了

另外,很感谢你的帮助,不过那些我很清楚,我的问题不在这里。。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-2-21 20:54:08 | 显示全部楼层
漆雕古代 发表于 2016-2-21 19:51
恩,谢谢,时间确实有点久了,不过确实还没有解决。因为hldh216说他的机子上没问题。。。所以我默认为只 ...

恩,我运行了下,确实有问题,10条鱼在同一回合挂掉了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-2-22 01:43:15 | 显示全部楼层
本帖最后由 漆雕古代 于 2016-2-22 01:45 编辑
小小大鱼 发表于 2016-2-21 20:54
恩,我运行了下,确实有问题,10条鱼在同一回合挂掉了


对啊,两串代码唯一的区别就是那么几行,你知道为什么吗?

从打印出来的数据来看,十条鱼的坐标确实都不一样啊。甚至最后同时挂掉那一回合也没有完全一样啊。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-2-22 01:44:27 | 显示全部楼层
hldh214 发表于 2016-2-14 10:50
我反复尝试你的两段代码, 都没有出现你说的
不过我猜测问题所在是Python的random模块产生的是伪随机数
至 ...

没有啊,小小大鱼测试了一下,十条鱼又在同一回合怪掉了。。。

你是不是测的时候十条鱼一条都没挂?总之第二种写法,要不就一只都不挂,要不就十只一起挂掉
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-2-22 10:24:36 | 显示全部楼层    本楼为最佳答案   
本帖最后由 小小大鱼 于 2016-2-22 10:29 编辑
漆雕古代 发表于 2016-2-22 01:43
对啊,两串代码唯一的区别就是那么几行,你知道为什么吗?

从打印出来的数据来看,十条鱼的坐标确实 ...


这个问题要解释起来还真有点麻烦,我也是仔细想了好久才想明白的。(下面乌龟体力用完的情况不讨论,只讨论同时挂掉的情况)
但是说明:这是个人理解,不一定对,见谅!
1.上面我已经贴过类属性与实例属性不同之处,还以这为例:
  1. class AA():
  2.         a = 1
  3.         def am(self):
  4.                 self.a =2
  5. class BB():
  6.         def __init__(self):
  7.                 self.a = 1
  8.         def am(self):
  9.                 self.a = 3

  10. print(AA.a)#a为类属性
  11. #print(BB.a)#a为实例属性,只有将BB这个类实例化后才具有a属性,否则报错

  12. #实例化
  13. example1 = AA()
  14. example2 = BB()
  15. #因为AA本身只有类属性a,而没有实例属性self.a
  16. print(dir(AA))
  17. print(example1.a,example2.a)
  18. #当调用example1.a时,程序会先到example所属的类:AA中找一个名为'a'的属性,
  19. #如果有,则返回该值作为self.a(实像例属性)的初始值,否则出错
  20. #这里相当于为AA这个类创建了self.a这个实例属性,类似BB中的__init__定义的self.a(python中的第一次赋值视为变量的定义!)
复制代码

2.再回到你的代码:
也就是说在每次调用下面这个方法时,self.coordonnes.self.deplace都会重新赋值一次:
  1. def deplace_action(self):
  2.         self.coordonnes = self.direction_principe(self.getdirection(),self.coordonnes,self.deplace)
复制代码

Turtle .Fish都是这样
副作用:在没有重新调用该方法之前,直接调用self.coordonnes,self.deplace一定与上一次调用此方法产生
的值相同
  1. print(turtle.coordonnes)#同样的道理,turtle.coordonnes的坐标是pos = turtle.deplace_action调用时产生的坐标self.coordonnes
复制代码

所以最后的判断:
  1. 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'
下面我在判断语句处加了几句,用作对比
  1. print(turtle.coordonnes)#同样的道理,turtle.coordonnes的坐标是pos = turtle.deplace_action调用时产生的坐标
  2.         for each_fish in fish[:]: ### [:]是我看了小甲鱼参考代码后改对的,之前一直报错
  3.             # 这里就是判断乌龟的坐标和鱼儿的坐标是否重合
  4.             print(each_fish.coordonnes)#a.输出每条鱼的坐标,与后面b作对比
  5.             if turtle.coordonnes == each_fish.coordonnes:
  6.                 print('坐标是:\n')
  7.                 print(turtle.coordonnes,each_fish.coordonnes)
  8.                 turtle.manger()
  9.                 fish.remove(each_fish)
  10.                 # 以下两条是我测试用的,事实证明我如果不这样就发现不了这个问题。。。
  11.                 print('*'*50)
  12.             else:
  13.                 print(turtle.coordonnes,each_fish.coordonnes)#b.不管怎样都打印出来,与前面的a对比
复制代码


看运行结果:
@~风介~ @小甲鱼请多指教!

fish1

fish1

fish2

fish2

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +2 收起 理由
漆雕古代 + 5 + 5 + 2 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-2-22 10:27:47 | 显示全部楼层
漆雕古代 发表于 2016-2-22 01:44
没有啊,小小大鱼测试了一下,十条鱼又在同一回合怪掉了。。。

你是不是测的时候十条鱼一条都没挂?总 ...

不是呀, 第一段代码结果有鱼挂的也有乌龟挂的

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
漆雕古代 + 5 + 5 + 3 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-2-22 16:10:25 | 显示全部楼层
小小大鱼 发表于 2016-2-22 10:24
这个问题要解释起来还真有点麻烦,我也是仔细想了好久才想明白的。(下面乌龟体力用完的情况不讨论,只 ...

真的是太感谢了!这个问题都快困扰我一个月而放弃了……

现在已经明白是怎么回事了!谢谢!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-2-22 16:22:58 | 显示全部楼层
本帖最后由 漆雕古代 于 2016-2-22 16:28 编辑
小小大鱼 发表于 2016-2-22 10:24
这个问题要解释起来还真有点麻烦,我也是仔细想了好久才想明白的。(下面乌龟体力用完的情况不讨论,只 ...


额,朋友,我又研究了一下,把代码后半部分这样改了改(其实也就是把你的方案加到原本的里面)

  1. import random as r


  2. class Main:
  3.     # 这里是我是希望通过1、2、3、4分别代表上下左右四个方向
  4.     def getdirection(self):
  5.         return r.randint(1,4)

  6.     # 这里只是通过一个简单的函数确认 coordonnes 坐标的横纵坐标有没有超出范围
  7.     #                           coordonnes 会在后面定义为一个元组代表坐标
  8.     def valider_limite(self, coordonnes):
  9.         for it in coordonnes:
  10.             if it < 0 or it > 10:
  11.                 return 1
  12.         return 0
  13.    
  14.     def direction_principe(self, direction, coordonnes, deplace):   # direction是传入由本类第一个方法返回的1-4中的一个数字
  15.                                                                     # coordoones是传入坐标的参数 list类(方便更改)
  16.                                                                     # deplace是由后来的两个子类中的方法获得的可以行动的步数1或2
  17.         # 分别对应如下
  18.         #           1:  y坐标+1
  19.         #           2:  y坐标-1
  20.         #           3:  x坐标+1
  21.         #           4:  x坐标-1
  22.         #   注:横纵坐标分别是变量 coordonnes 的 [0] 和 [1]
  23.         if direction == 1:
  24.             coordonnes[1] += deplace
  25.             # 一下这里是判断变化后的坐标有没有超出范围,如果超出将会以取两倍相反数的形式将坐标更换为正确的形式   
  26.             if self.valider_limite(coordonnes):
  27.                 coordonnes[1] -= 2*deplace
  28.         elif direction == 2:
  29.             coordonnes[1] -= deplace
  30.             if self.valider_limite(coordonnes):
  31.                 coordonnes[1] += 2*deplace
  32.         elif direction == 3:
  33.             coordonnes[0] -= deplace
  34.             if self.valider_limite(coordonnes):
  35.                 coordonnes[0] += 2*deplace
  36.         else:
  37.             coordonnes[0] += deplace
  38.             if self.valider_limite(coordonnes):
  39.                 coordonnes[0] -= 2*deplace
  40.         return coordonnes   # 这里返回新的移动后的坐标
  41.             
  42.    
  43.         
  44. class Turtle(Main):
  45.     PV = 100                                            # PV 是乌龟的体力属性
  46.     coordonnes = [r.randint(0, 10),r.randint(0, 10)]    # coordonnes是乌龟初始随机生成的坐标

  47.     # 第一个方法是返回随机的移动步数1或0,获取的数值将传入Main类中的过去新坐标的方法作为参数
  48.     def getdeplace(self):
  49.         return r.randint(1, 2)

  50.     # 调用父类的方法获得新的坐标
  51.     def deplace_action(self):
  52.         self.coordonnes = self.direction_principe(self.getdirection(),  # 父类的第一个方法用于获取随机方向
  53.                                                  self.coordonnes,       # 乌龟现在的坐标
  54.                                                  self.getdeplace())     # 乌龟本回合随机前进的步数
  55.         self.PV -= 1 # 获取新坐标后体力-1

  56.     # 就是吃的方法
  57.     def manger(self):
  58.         self.PV += 20       # 吃一条鱼加20点PV
  59.         if self.PV > 100:   # 判断体力是否大于上限
  60.             self.PV = 100

  61. class Fish(Main):
  62.     deplace = 1                                         # 鱼的移动步数永远是1
  63.     coordonnes = [r.randint(0, 10),r.randint(0, 10)]    # 生成鱼的初始坐标 coordonnes
  64.     def deplace_action(self):
  65.         self.coordonnes = self.direction_principe(self.getdirection(),  # 父类的第一个方法用于获取随机方向
  66.                                                   self.coordonnes,      # 鱼儿现在的坐标
  67.                                                   self.deplace)         # 鱼儿本回合前进的步数1


  68. # 此函数用于初始化十条实例化的鱼儿到一个列表
  69. def pret():
  70.     fish = list()
  71.     for it in range(10):
  72.         new_fish = Fish()
  73.         fish.append(new_fish)
  74.     return fish

  75. def jeu_principe(): # 相当于就是主函数咯
  76.     turtle = Turtle()
  77.     fish = pret()
  78.     count = 0 # 这个是我为了测试家的计算回合数的变量

  79.     while 1:

  80.         if turtle.PV == 0:
  81.             print('乌龟眼前一黑。。。\n共经过了%d个回合' % count)
  82.             break
  83.         if len(fish) == 0:
  84.             print('鱼儿全部被吃掉了。。。\n共经过了%d个回合' % count)
  85.             break
  86.         
  87.         count += 1 # 这个是我为了测试家的计算回合数的变量
  88.         
  89.         if count % 10 == 0 or count == 1: # 第一回合执行,以后每隔十回合执行一次
  90.             print('现在是第%d回合' % count)
  91.             print('乌龟体力还剩下%dPV' % turtle.PV)
  92.             print('鱼儿还剩下%d条' % len(fish))

  93.         pos = turtle.deplace_action()    # 乌龟先获得新坐标
  94.         for each_one in fish:       # 这一步让每一只鱼儿都获得新的坐标
  95.             print('###',each_one.coordonnes,'###')
  96.             each_one.deplace_action()
  97.         print(turtle.coordonnes)
  98.         for each_fish in fish[:]: ### [:]是我看了小甲鱼参考代码后改对的,之前一直报错
  99.             # 这里就是判断乌龟的坐标和鱼儿的坐标是否重合
  100.             if turtle.coordonnes == each_fish.coordonnes:
  101.                 turtle.manger()
  102.                 fish.remove(each_fish)
  103.                 # 以下两条是我测试用的,事实证明我如果不这样就发现不了这个问题。。。
  104.                 print('*'*50)
  105.             else:
  106.                 print('*****',each_fish.coordonnes,'*****')

  107. if __name__ == '__main__':
  108.     jeu_principe()
  109.             
复制代码


就是在每只鱼移动以前打印一次坐标,以及在与乌龟坐标进行对比后打印一次坐标,但是这两个坐标为什么会不一样呢?如图: 2016-02-22.png

这里*号打印的是比较时的坐标,#打印的是移动前的坐标

还劳烦解答一下困惑……
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-2-22 17:01:30 | 显示全部楼层
漆雕古代 发表于 2016-2-22 16:22
额,朋友,我又研究了一下,把代码后半部分这样改了改(其实也就是把你的方案加到原本的里面)

你提的是:print('###',each_one.coordonnes,'###')与print('*****',each_fish.coordonnes,'*****')
吧?
看:print('###',each_one.coordonnes,'###')后面是:each_one.deplace_action()
这个方法里面直接调用了self.coordonnes,self.deplace,而coordonnes = [r.randint(0, 10),r.randint(0, 10)]
结果就是重新定义了self.coordonnes直到下一次调用self.coordonnes之前这个值都不会变,这也是所有的鱼的
坐标相同的原因。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-2-22 18:58:41 | 显示全部楼层
小小大鱼 发表于 2016-2-22 17:01
你提的是:print('###',each_one.coordonnes,'###')与print('*****',each_fish.coordonnes,'*****')
吧 ...

不是直到下一次调用self.coordonnes后他的值都不会改变吗

但是他十条鱼每一只都调用了啊?为什么都没改变?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-2-22 19:32:21 | 显示全部楼层
漆雕古代 发表于 2016-2-22 18:58
不是直到下一次调用self.coordonnes后他的值都不会改变吗

但是他十条鱼每一只都调用了啊?为什么都没 ...

在执行一次:each_one.deplace_action时,会重新赋值self.coordonnes。在for循环里后面,从第一条鱼到最后一条鱼都只是引用self.coordonnes这个实例属性。而到下一次又会调用each_one.deplace_action方法,此时self.coordonnes又会被重新赋值一次。

2上次回答的最后一句“直到下一次调用self.coordonnes之前这个值都不会变,这也是所有的鱼的
坐标相同的原因。”里面的self.coordonnes,应该是each_one.deplace_action方法,上次是写错了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-28 20:11

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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