ValueError:list.remove(x):x不在列表中(但它是!)

时间:2013-07-22 12:24:05

标签: python python-2.7

我正在阅读O'Reilly的书“探索R和Ruby中的日常事物”,并试图用Python重写所有Ruby代码。第一个例子是用于确定建筑物需要多少浴室的模型。我正在使用的代码如下。

但是,当我运行example34.py文件时,出现以下错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "example34.py", line 39, in <module>
    new_restroom.enter(queue.pop(0))
  File "restroom.py", line 21, in enter
    unoccupied_facilities[0].occupy(person)
  File "restroom.py", line 46, in occupy
    Person.population.remove(person)
ValueError: list.remove(x): x not in list

我是Python的新手,所以我怀疑这是与Python的变量范围或某些未知(对我来说)属性相关的问题。奇怪的是,在它中断之后,运行person in Person.population返回True,并且命令Person.population.remove(person)成功删除了该人员实例,因此该人明显 在列表中。< / p>

有什么想法吗?

example34.py:

from restroom import *  # imports the model

# Simulation script 1

frequency = 3  # how many times a person goes to the restroom within the period
facilities_per_restroom = 3
use_duration = 1  # measured in ticks
population_range = range(100, 110, 10)  # Creates an array from 10 to 600 by 10s

# Stores data for printing later
data = {}

# Loops for each population size in the above range
for population_size in population_range:
    # Starts each loop fresh
    Person.population = []
    # Creates the population of people
    Person.population = [
        Person(frequency, use_duration) for
        each in range(population_size)]
    # Creates the key for this population size
    data[population_size] = []
    #Create the restroom
    new_restroom = Restroom(facilities_per_restroom)
    # Iterate over the period
    for each in range(duration):
        # Records the queue size at this tick
        data[population_size].append(len(new_restroom.queue))
        # Create a temporary queue so that we can sort people between the
        # facilities and the restroom queue for this "tick"
        queue = list(new_restroom.queue)
        # Clear the queue to prepare for sorting
        new_restroom.queue = []
        # Take each person from the temporary queue and try adding
        # them a facility
        while bool(queue):
            # De-queue the person at the front of the line, place in an
            # unoccupied facility or, if none, back to the restroom queue
            new_restroom.enter(queue.pop(0))

        # for each person in the population, check if they need to go
        for person in Person.population:
            if person.need_to_go():
                new_restroom.enter(person)
        new_restroom.tick()

print(data)

restroom.py:

from random import randint
duration = 9 * 60  # minutes


class Restroom(object):

    def __init__(self, facilities_per_restroom=3):
        # Start with an empty queue
        self.queue = []
        # The facilities in this restroom
        self.facilities = []
        # Creates the facilities
        self.facilities = ([Facility() for each in
                            range(facilities_per_restroom)])

    def enter(self, person):
        unoccupied_facilities = [
            facility for facility in self.facilities
            if facility.occupied() == 0]
        if unoccupied_facilities:
            unoccupied_facilities[0].occupy(person)
        else:
            self.queue.append(person)
            Person.population.remove(person)

    def tick(self):
        [each.tick() for each in self.facilities]
        [f.tick for f in self.facilities]


class Facility(object):
    def __init__(self):
        self.occupier = None  # no one is occupying this facility at the start
        self.duration = 0  # how long the facility has been occupied

    def occupied(self):
        return 1 if (self.occupier is not None) else 0

    def occupy(self, person):
        # if the facility is unoccupied, add the person. Else, return false.
        if not self.occupied():
            self.occupier = person
            self.duration = 1
            #remove the person from the population since
            # they're in a facility now
            Person.population.remove(person)
            return 1  # return true
        else:
            return 0  # Return false

    def vacate(self):
        Person.population.append(self.occupier)
        self.occupier = None

    def tick(self):
        # if the facility is occupied and they've been
        # there longer than the use duration, have them leave
        if self.occupied() and (self.duration > self.occupier.use_duration):
            self.vacate()
            self.duration = 0
        elif self.occupied():
            # If occupied, increment the time
            self.duration += 1


class Person(object):

    #Class variable for storing the entire population
    population = []

    def __init__(self, frequency=4, use_duration=1):
        # Number of times a person uses the facilities per day
        self.frequency = frequency
        # How long each person uses the facilities
        self.use_duration = use_duration

    def need_to_go(self):

        return randint(1, duration) <= self.frequency

2 个答案:

答案 0 :(得分:2)

您的代码中遇到了一个简单的错误。

休息室有一个队列,添加了Person对象,没有可用的档位。

逻辑是:

def enter(self, person):
    unoccupied_facilities = [
        facility for facility in self.facilities
        if facility.occupied() == 0]
    if unoccupied_facilities:
        unoccupied_facilities[0].occupy(person)
    else:
        self.queue.append(person)
        Person.population.remove(person)

请注意,.occupy()Person.population列表中删除某个人,或者如果没有可用的档位,则此人将被添加到self.queue已从Person.population中删除。

然后example34代码处理该队列:

queue = list(new_restroom.queue)
# Clear the queue to prepare for sorting
new_restroom.queue = []
# Take each person from the temporary queue and try adding
# them a facility
while bool(queue):
    # De-queue the person at the front of the line, place in an
    # unoccupied facility or, if none, back to the restroom queue
    new_restroom.enter(queue.pop(0))

所以人们从队列中被带走,重新进入洗手间。如果任何档位为空,unoccupied_facilities[0].occupy(person)会尝试再次从Person.population 中删除该人。此时会引发异常,因为该人在该列表中肯定

解决方案是从两个不同位置的群体中删除person,或者在处理队列时将人员重新添加回群体中。

将队列处理代码更改为:

while bool(queue):
    # De-queue the person at the front of the line, place in an
    # unoccupied facility or, if none, back to the restroom queue
    person = queue.pop(0)
    Person.population.append(person)
    new_restroom.enter(person)

解决了这个问题,例如:

$ python2.7 example34.py 
{100: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0]}

答案 1 :(得分:0)

但是通过查看堆栈跟踪,它清楚地表明了ValueError: list.remove(x): x not in list。您尝试删除的person不在列表中。所以你需要捕获这个异常并适当地处理它 -

#some loop, get the person to be removed
...
try:
    Person.population.remove(person)
except ValueError:
    pass #silently continue. Either that person is already removed or is not present.
...

当然这段代码并不完整。它只是强调使用try: except ValueError:用法。