我有以下测试
def test_employees_not_arround_for_more_than_3_rounds(self):
self.game_object.generate_workers()
people_in_list_turn_1 = self.game_object.employees[:]
self.game_object.next_turn()
self.game_object.generate_workers()
self.game_object.next_turn()
self.game_object.generate_workers()
self.game_object.next_turn()
for employee in people_in_list_turn_1:
self.assertFalse(employee in self.game_object.employees)
基本上,它会生成随机数量的工作人员并将其添加到我的game_object.employees
列表中。
当我调用game_object.next_turn
函数时,每个员工都有一个turns_unemployed
变量来保存他们失业的轮数,一旦达到3,工人就会从game_object.employees
列表中删除共
以下是game_object.py的实现代码:
def generate_workers(self):
workersToAdd = range(random.randrange(1,8))
for i in workersToAdd:
self.__employees.append(Employee())
def next_turn(self):
self.__current_turn += 1
self.__call_employees_turn_function()
self.__remove_workers_unemployed_for_3_rounds()
def __call_employees_turn_function(self):
for employee in self.employees:
employee.turn()
def __remove_workers_unemployed_for_3_rounds(self):
for employee in self.employees:
if employee.turns_unemployed >= 3:
self.employees.remove(employee)
我已经有一个测试,当turns_unemployed
被调用时,检查employee.turn()
变量实际上增加了1,所以我知道它有效...
在这里真正让我感到困惑的是,我的测试只有50%的时间用于运行它,我无法弄清楚为什么......任何人都会看到任何可能导致任何差异的事情?
顺便说一下,运行Python 3.2.2
答案 0 :(得分:4)
您正在__remove_workers_unemployed_for_3_rounds
中对项目进行迭代时从列表中删除项目,因此循环会跳过您希望删除的项目。您需要迭代列表的副本。
def __remove_workers_unemployed_for_3_rounds(self):
for employee in self.employees[:]:
if employee.turns_unemployed >= 3:
self.employees.remove(employee)
示例:
每回合生成2名新员工。在第4回合,你有2名员工要删除(列表中的两个)。您开始迭代并删除第一个。该列表现在只有五个项目,但迭代继续并查看第二个项目。问题是第二项不再是第二名员工,而是第三项。第二名员工将留在列表中,您的测试将失败。只有在第一个回合中只生成一名员工时,您的测试才有效。
答案 1 :(得分:3)
def generate_workers(self):
workersToAdd = range(random.randrange(1,8))
for i in workersToAdd:
self.__employees.append(Employee())
但是当你稍后迭代它们时,你会使用一个名为employees的列表,即
def __call_employees_turn_function(self):
for employee in self.employees:
employee.turn()
def __remove_workers_unemployed_for_3_rounds(self):
for employee in self.employees:
if employee.turns_unemployed >= 3:
self.employees.remove(employee)
但我不知道这是否与您的问题有关,因为我看不到您的其余代码 - 我甚至不确定这些是否属于同一类。您应该发布可以获得的最小的完整代码 - 这样人们可以实际运行代码并为自己重现问题。
答案 2 :(得分:3)
不要修改您正在迭代的容器。
保持副本迭代也是一个丑陋的黑客攻击,如果你必须非常准确地了解对象身份与对象相等,它可能会让你绊倒。它也只是简单的混乱。
有一种更简单的方法:采用函数式编程方法。使用规则“从原始容器中不符合要删除条件的所有内容”创建一个新容器,然后开始使用该容器而不是原始容器。
def __remove_workers_unemployed_for_3_rounds(self):
self.employees = filter(lambda e: e.turns_unemployed < 3, self.employees)
# Or with a list comprehension:
# self.employees = [e for e in self.employees if e.turns_unemployed < 3]
# if you find that more readable.