如何更改用户定义类的实例列表中的元素属性?

时间:2011-05-17 19:16:44

标签: python

我正在尝试遍历列表, workerl 我定义的类的实例 worker ,并基于其中一个类属性 isemployed ,抓住其中的5个并在其上调用一个函数, fire()。我尝试了很多不同的方法,但是我要么陷入无休止的循环中,要么得到错误的值。

请让我知道我做错了什么,代码如下,我需要帮助的部分用粗体评论,但其他提示也很受欢迎。谢谢!

from random import choice
import sys

class Population:
    """total population of workers"""
    workerl = []
    workers = 0
    g_rate = 1
    y = 0
    ui = 0
    c = 5

    def __init__(self, ui, workers):
        # probability of a worker becoming unemployed
        # low in booms, high in recessions, could be a proxy for i
        self.ui = ui
        self.workers = workers
        self.workerl = []
        for i in range(workers):
            x = Worker()
            self.workerl.append(x)
        for i in range(workers / 10.):
            self.workerl[i].fire()

    def countEmployed(self):
        """displays number of employed workers in a population"""
        employed = 0
        for worker in self.workerl:
            if worker.isemployed == True:
                employed = employed + 1
        return employed

    def countUnemployed(self):
        """displays number of unemployed workers in a population"""
        unemployed = 0
        for worker in self.workerl:
            if worker.isemployed == False:
                unemployed = unemployed + 1
        return unemployed   

    def employedl(self):
        employedl = []
        for worker in self.workerl:
            if worker.isemployed:
                employedl.append(worker)
        return employedl

    def unemployedl(self):
        unemployedl = []
        for worker in self.workerl:
            if worker.isemployed == False:
                unemployedl.append(worker)
        return unemployedl

    def lookingl(self):
        lookingl = []
        for worker in self.workerl:
            if worker.islooking:
                lookingl.append(worker)
        return employedl


    def advance(self, time):
        """advances the population units of time"""

        # updates assets
        for worker in self.workerl:
            if worker.isemployed == True:
                worker.assets = worker.assets + worker.salary
            else:
                worker.assets = worker.assets + self.ui - self.c        

        #calculates current y
        tmp_y = 0
        for worker in self.workerl:
            tmp_y = worker.assets + tmp_y
        self.y = tmp_y

        # fires some workers, random turnover
        # THIS IS THE PART I NEED HELP WITH
        # as discussed above, i need to pick 5 workers from workerl
        # where isemployed == True
        # and then call their fire() method


        # makes job search decisions for unemployed
        jobs = self.y / 10
        jobseekers = 0
        for worker in self.workerl:
            if worker.islooking:
                jobseekers =+ 1

        if jobs/jobseekers > 1:
            d = 1
        elif jobs/jobseekers < 0:
            d = 0
        else:
            d = jobs / jobseekers

        for worker in self.workerl:
            if worker.isemployed == False:
                if ((d * 5 + (1 - d) * (self.ui - self.c)) > self.ui):
                    worker.look()
                else:
                    worker.unlook()

        # hires some workers
        jobcount = jobs
        if d == 1:
            for worker in self.workerl:
                if worker.islooking:
                    worker.hire()
        elif d == 0:
            pass
        else:
            for i in range(jobs):
                if self.workerl[i].islooking:
                    self.workerl[i].hire()


        #calculates growth rate, updates y
        tmp2_y = 0
        for worker in self.workerl:
            tmp2_y = worker.assets + tmp2_y
        self.g_rate = (tmp_y / self.y) + 1.
        self.y = tmp_y


# population as an array of workers     
class Worker:
    """a worker in a population"""
    isemployed = True
    islooking = False
    assets = 0

    salary = choice(range(10))

    def fire(self):
        self.isemployed = False
        self.islooking = True

    def hire(self):
        self.isemployed = True
        self.islooking = False

    def look(self):
        self.islooking = True

    def unlook(self):
        self.islooking = False


def main():

    x = Population(int(sys.argv[1]), int(sys.argv[2]))  
    x.advance(1)
    print x.countEmployed()
    print x.countUnemployed()
    print x.y

main()  

2 个答案:

答案 0 :(得分:0)

您正在寻找的是random.choice功能。它允许您从列表中选择随机选择的值。以下是它的工作原理:

class Population:
    employee_list = []
    ...

    # Create a set that will contain the unique indices  of newly fired employees
    fired_indices = set()

    # Keep count of how many we have fired      
    fired_count = 0
    while fired_count < 5:
        # Because we are using index numbers for bookkeeping, we need to chose from
        # the list of indexes not the list of employees
        # The xrange is much more efficient if we have large lists
        i = random.choice( xrange( len( employee_list ) ) )

        # Selection criteria -> employed and not already fired in *this* round
        if employee_list[i].employed and i not in fired_indices:
            employee_list[i].employed = false
            fired_indices.add( i )
            fired_count += 1

这种方法的问题在于可以多次选择同一个工人(我认为你不想这样做),并且必须继续拒绝他作为一个有效的选择。您可能还会选择许多已经失业的工人,然后再找到不工作的工人。这些冗余会给选择循环增加额外的迭代,从而导致效率下降。

如果您在Population类中有两个单独的列表,这可以更有效地工作。你可以有一份就业工人名单和一份失业人员名单。如果您保留两个单独的列表,那么选择将非常简单。您可以避免选择已经失业的工人,并且可以使用random.sample从列表中选择k个唯一选择。这是一个例子:

class Population:
    employed_list = []
    unemployed_list = []
    ...

    fired_indices = random.sample( xrange( len( employed_list ) ) ) 
    for i in fired_indices:
        fired_employee = employed_list.pop( i )
        unemployed_list.append( fired_employee )
    ...

当然,如果你是列表推导的粉丝,你可以一行完成:

 unemployed_list.extend( [ employed_list.pop( i ) for i in random.sample( xrange( len( employed_list ) ) ] )

希望这会有所帮助。在模块上使用dir()方法来查看它们是否具有您可能正在寻找的有用内容总是一个好主意:

>>> dir( random )
['BPF', 'LOG4', 'NV_MAGICCONST', 'RECIP_BPF', 'Random', 'SG_MAGICCONST', 'SystemRandom', 'TWOPI', 'WichmannHill', '_BuiltinMethodType', '_MethodType', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '_acos', '_cos', '_e', '_exp', '_hexlify', '_inst', '_log', '_pi', '_random', '_sin', '_sqrt', '_test', '_test_generator', '_urandom', '_warn', 'betavariate', '**choice**', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'jumpahead', 'lognormvariate', 'normalvariate', 'paretovariate', 'randint', 'random', 'randrange', '**sample**', 'seed', 'setstate', 'shuffle', 'uniform', 'vonmisesvariate', 'weibullvariate']

答案 1 :(得分:0)

你选择这样的随机样本:

import random

for worker in random.sample(self.employedl(), k=5): # pick 5
    worker.fire()

顺便说一下,你可以用列表推导来减少你的代码,即:

def employedl(self):
    return [worker for worker in self.workerl if worker.isemployed]