小甲鱼第37讲最后一题的疑问
本帖最后由 吕四毛 于 2021-3-8 18:23 编辑import random as r
legal_x =
legal_y =
class Turtle:
def __init__(self):
# 初始体力
self.power = 100
# 初始位置随机
self.x = r.randint(legal_x, legal_x)
self.y = r.randint(legal_y, legal_y)
def move(self):
# 随机计算方向并移动到新的位置(x, y)
new_x = self.x + r.choice()
new_y = self.y + r.choice()
# 检查移动后是否超出场景x轴边界
if new_x < legal_x:
self.x = legal_x - (new_x - legal_x)
elif new_x > legal_x:
self.x = legal_x - (new_x - legal_x)
else:
self.x = new_x
# 检查移动后是否超出场景y轴边界
if new_y < legal_y:
self.y = legal_y - (new_y - legal_y)
elif new_y > legal_y:
self.y = legal_y - (new_y - legal_y)
else:
self.y = new_y
# 体力消耗
self.power -= 1
# 返回移动后的新位置
return (self.x, self.y)
def eat(self):
self.power += 20
if self.power > 100:
self.power = 100
class Fish:
def __init__(self):
self.x = r.randint(legal_x, legal_x)
self.y = r.randint(legal_y, legal_y)
def move(self):
# 随机计算方向并移动到新的位置(x, y)
new_x = self.x + r.choice()
new_y = self.y + r.choice()
# 检查移动后是否超出场景x轴边界
if new_x < legal_x:
self.x = legal_x - (new_x - legal_x)
elif new_x > legal_x:
self.x = legal_x - (new_x - legal_x)
else:
self.x = new_x
# 检查移动后是否超出场景y轴边界
if new_y < legal_y:
self.y = legal_y - (new_y - legal_y)
elif new_y > legal_y:
self.y = legal_y - (new_y - legal_y)
else:
self.y = new_y
# 返回移动后的新位置
return (self.x, self.y)
turtle = Turtle()
fish = []
for i in range(10):
new_fish = Fish()
fish.append(new_fish)
while True:
if not len(fish):
print("鱼儿都吃完了,游戏结束!")
break
if not turtle.power:
print("乌龟体力耗尽,挂掉了!")
break
pos = turtle.move()
# 在迭代器中删除列表元素是非常危险的,经常会出现意想不到的问题,因为迭代器是直接引用列表的数据进行引用
# 这里我们把列表拷贝给迭代器,然后对原列表进行删除操作就不会有问题了^_^
for each_fish in fish[:]: #这里为什么用到了切片?fish[:] 和fish有什么不一样吗? fish[:]表示列表的全部内容,直接用fish不是一样的吗?
if each_fish.move() == pos:
# 鱼儿被吃掉了
turtle.eat()
fish.remove(each_fish)
print("有一条鱼儿被吃掉了...")
我在小甲鱼的书上找到了关于切片的描述:
注意:
列表切片并不会修改列表自身的组成结构和数据,它其实是为列表
创建一个新的拷贝(副本)并返回。
这里结合他上一句话我理解他的意思了,不对原列表直接删除,但是我测试了10000次的运行结果,发现fish[:] 和fish的结果基本没有区别。。有没有大哥可以举个例子说明一下,在迭代器中对列表删除元素会造成什么问题? 本帖最后由 jackz007 于 2021-3-8 18:50 编辑
for each_fish in fish[:]:
意思是参照 fish 的副本来进行循环,因为在循环中,需要删除 fish 中的元素,如果不这样操作,就有可能漏掉符合条件的元素。
请考察下面的代码
>>> a =
>>> for x in a:
if 3 <= x <= 5:
a . remove(x)
>>> a
>>>
这个代码的原意是删除 3、4、5三个元素,但是,结果,只删除了 3 和 5,4 就漏网了。
如果参照副本进行循环
>>> a =
>>> for x in a[:]:
if 3 <= x <= 5:
a . remove(x)
>>> a
>>>
这个结果就完全如我们所愿了。 jackz007 发表于 2021-3-8 18:49
意思是参照 fish 的副本来进行循环,因为在循环中,需要删除 fish 中的元素,如果不这样操作,就 ...
谢谢大哥的解答,但是我还是没有理解为什么4没有被删除呢? 我刚刚测试了一下
>>> a =
>>> for x in a:
if 3 <= x <= 5:
print(x)
3
4
5
我看到4被执行了,但是没有被删除掉..是什么原因导致的? 本帖最后由 jackz007 于 2021-3-8 20:48 编辑
吕四毛 发表于 2021-3-8 19:25
谢谢大哥的解答,但是我还是没有理解为什么4没有被删除呢? 我刚刚测试了一下
我看到4被执行了,但是没 ...
a =
for x in a:
if 3 <= x <= 5:
a . remove(x)
这个代码本来需要循环 8 次,x 依次枚举到列表 a 中索引为 0,1,2,3,4,5,6,7 的元素,当索引为 2 时,x = 3 ,3 被删除后,a 的索引被重排,下一次循环,x 该枚举索引为 3 的元素,如果未删除元素,那么, 毫无疑问,这个元素当然是4,但是,删除元素后,这个元素却变成了 5,就这样,3、5 被删除, 4 却 "偷偷" 漏了过去。 jackz007 发表于 2021-3-8 20:42
这个代码本来需要循环 8 次,x 依次枚举到列表 a 中索引为 0,1,2,3,4,5,6,7 的元素,当索引 ...
谢谢大哥!明白了!
页:
[1]