简体   繁体   English

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

[英]ValueError: list.remove(x): x not in list (But it is!)

I'm working through the O'Reilly book "Exploring Everyday Things in R and Ruby" and am trying to rewrite all of the Ruby code in Python. 我正在研究O'Reilly的书“探索R和Ruby中的日常事物”,并试图用Python重写所有Ruby代码。 The first example is a model for figuring out how many bathrooms a building needs. 第一个示例是一个模型,用于计算建筑物需要多少个浴室。 The code that I am working with is below. 我正在使用的代码如下。

When I run the example34.py file, however, I get the following error: 但是,当我运行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

I am new to Python, so I suspect this is an issue related to variable scope or some unknown (to me) property of Python. 我是Python的新手,所以我怀疑这是与变量范围或Python的某些未知属性有关的问题。 The strange thing is that after it breaks, running person in Person.population returns True, and the command Person.population.remove(person) succeeds in removing that person instance, so the person clearly is in the list. 奇怪的是,它打破后,运行person in Person.population返回True,命令Person.population.remove(person)成功地除去人的实例,所以这个人显然在列表中。

Any ideas? 有任何想法吗?

example34.py: 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: 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

You've encountered a simple bug in your code. 您在代码中遇到了一个简单的错误。

The rest room has a queue, to which Person objects are added for which there is no stall available. 洗手间有一个队列,其中添加了Person对象,没有可用的停顿。

The logic goes: 逻辑是:

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)

Note that either .occupy() removes a person from the Person.population list, or if there are no stalls available, then the person is added to self.queue and also removed from Person.population . 请注意, .occupy()将从Person.population列表中删除一个人,或者如果没有可用的档位,则将该人添加到self.queue将从Person.population删除。

The example34 code then processes that queue: 然后, 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))

So people are taken from the queue, and reentered into the restroom. 因此人们被从队列中带走,然后重新进入洗手间。 If any of the stalls are empty, unoccupied_facilities[0].occupy(person) tries to remove that person from Person.population again . 如果任何摊位都空了, unoccupied_facilities[0].occupy(person)尝试再次Person.population删除该人。 At this point the exception is raised, because that person is most definitely not in that list anymore. 在这一点上出现了例外,因为该人绝对不再在该列表中。

The solution is to not remove person from the population in two different places, or to re-add the person back into the population when processing the queue. 解决方案是不要在两个不同的位置将person从总体中移除,或者在处理队列时将人员重新添加到总体中。

Changing the queue processing code to: 将队列处理代码更改为:

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)

fixes the issue, for example: 解决此问题,例如:

$ 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]}

But just by looking at the stacktrace it clearly states ValueError: list.remove(x): x not in list . 但是仅通过查看stacktrace即可清楚地表明ValueError: list.remove(x): x not in list The person you are trying to remove is not in the list. person ,你正试图删除不在列表中。 So You need to catch this exception and handle it appropriately - 因此,您需要捕获此异常并进行适当处理-

#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.
...

Of course this code is not complete. 当然,这段代码并不完整。 It was put to merely highlight the use of try: except ValueError: usage. 它只是强调了try: except ValueError:的使用, try: except ValueError:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM