2

我正在阅读 O'Reilly 的书“Exploring Everyday Things in R and 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 的变量范围或某些未知(对我而言)属性有关的问题。奇怪的是,在它中断之后,runningperson in Person.population返回 True,并且命令Person.population.remove(person)成功删除了那个 person 实例,所以这个 person 显然列表中。

有任何想法吗?

示例 34.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)

厕所.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
4

2 回答 2

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]}
于 2013-07-22T13:09:41.600 回答
0

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

#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:用法。

于 2013-07-22T12:30:53.797 回答