虽然在Python早期循环结束?

时间:2014-03-10 20:50:34

标签: python loops while-loop

出于某种原因,我的while循环在两次尝试后停止,我无法弄清楚出了什么问题...... 它应该是一个蚂蚁农场,你可以选择繁殖和制作新的蚂蚁等。 我只是不明白为什么它会停止...... 这是我的代码:

import random

class Colony(object):
    workerAnts = 0
    list = []
    temp = []
    foodAmount = 10
    def breedWorker(self):
        if Colony.foodAmount < 5:
             print "Sorry! You do not have enough food to create a new worker ant!"
        else:
                Colony.foodAmount -= 5
                Colony.workerAnts += 1
                Colony.list.append("ant")
    def step(self):
        number = 'ant'
        for number in Colony.list:
            a = Ant()
            a.forage()
            if Colony.foodAmount > 0:
                Colony.foodAmount -= 1
            if Colony.foodAmount < len(Colony.list):
                for number in Colony.list[Colony.foodAmount+1:]:
                    Ant.health -= 1
    def purge(self):
        number = 'ant'
        for number in Colony.list:
            if Ant.health > 0:
                Colony.temp.append("ant")
        Colony.list = Colony.temp       

class Ant(object):  
    health = 10
    def forage(self):
        if Ant.health == 0:
            Colony.workerAnts -= 1
        if random.randint(0,100) > 95:
            Ant.health = 0
            print "Ant has died from a horrible accident!"
            Colony.workerAnts -= 1
        elif random.randint(0,100) < 40:
            newFood = random.randint(1,5)
            print "Ant has found %s food!!" % newFood
            Colony.foodAmount += newFood    
        elif random.randint(0,100) < 5:
            Ant.health = 10
            Colony.foodAmount += 10
            print "You've found sweet nectar! Your ant has returned to full health and has brought 10 food back to the colony!"
        else:
            print "Ant returned empty-handed!"
def main():
    queen = Colony()
    queen2 = Ant()
    while queen.workerAnts > 0 or queen.foodAmount >= 5:
        print "========================================================"
        print """
        Your colony has %s ants and %s food, Your Majesty.\nWhat would you like to do?\n0: Do nothing.\n1: Breed worker. (Costs 5 food.)""" % (queen.workerAnts, queen.foodAmount)
        answer = int(raw_input(">"))

        if answer != 1 and answer != 0:
            print "Sorry, invalid input!"
        if answer == 0:
            queen.step()
            queen.purge()
        if answer == 1:
            print "Breeding Worker..." 
            queen.breedWorker()
            queen.step()
            queen.purge()

    if queen.workerAnts <= 0 and queen.foodAmount < 5:
        print "I'm sorry! Your colony has died out!"

4 个答案:

答案 0 :(得分:1)

  1. 您没有构造函数(__init__(self, ...))并且没有初始化对象的属性
  2. 在您通过self.property调用此对象属性的方法中,而不是由Classname.property调用;在python中,你明确地将实例或类对象传递给方法,按照惯例,它们应该是'self',例如,'cls'代表类。
  3. 如果要在Ant对象中使用任何Colony属性,反之亦然,则需要显式传递引用,并将其存储为属性。最明智的做法是通过调用ants.append(Ant(self))来创建来自Colony的Ant; Ant的构造函数应该有签名`def init (self,colony):'

答案 1 :(得分:0)

您使Ant.health成为一个类变量(在所有Ant实例之间共享)。

一旦蚂蚁的健康状况变为0,他们就会死亡。

这是一个改进版本。以下代码兼容Python 2和3,我认为修复了所有错误!

import random
import sys

if sys.hexversion < 0x3000000:
    # Python 2.x
    inp = raw_input
    rng = xrange
else:
    # Python 3.x
    inp = input
    rng = range

def get_int(prompt, lo=None, hi=None):
    """
    Prompt until an integer value in [lo..hi] is entered, then return it
    """
    while True:
        try:
            val = int(inp(prompt))
            if (lo is None or lo <= val) and (hi is None or val <= hi):
                return val
        except ValueError:
            pass

class InsufficientFoodError(Exception):
    pass

class Colony:
    def __init__(self, workers=0, food=10):
        self.food = food + Ant.cost * workers
        self.ants = []
        for i in rng(workers):
            self.add_ant()

    def add_ant(self):
        try:
            self.ants.append(Ant(self))
        except InsufficientFoodError as e:
            print(e)

    def step(self):
        # all ants eat, then all ants forage:
        for ant in self.ants:
            ant.eat()
        for ant in self.ants:
            ant.forage()
        # bring out yer dead!
        self.ants = [ant for ant in self.ants if ant.is_alive()]

    def add_food(self, amount):
        self.food += amount

    def take_food(self, amount):
        amt = min(amount, self.food)
        self.food -= amt
        return amt

    def num_ants(self):
        return len(self.ants)

class Ant:  
    cost = 5
    max_health = 10

    def __init__(self, colony):
        # try to get enough food to produce an ant
        food = colony.take_food(Ant.cost)
        if food < Ant.cost:
            # Failed! return any taken food and throw an error
            colony.add_food(food)
            raise InsufficientFoodError('The colony does not have enough food to make a new Ant')
        else:
            # Success!
            self.colony = colony
            self.health = Ant.max_health

    def eat(self):
        if self.health > 0:
            self.health -= 1 - self.colony.take_food(1)
            if self.health == 0:
                print("An ant starved to death.")

    def forage(self):
        if self.is_alive():
            dice = random.randint(0, 100)
            if dice <= 5:
                self.health = Ant.max_health
                self.colony.add_food(10)
                print("You've found sweet nectar! Your ant has returned to full health and has brought 10 food back to the colony!")
            elif dice <= 40:
                found_food = random.randint(1, 5)
                self.colony.add_food(found_food)
                print("Ant has found {} food!".format(found_food))
            elif dice <= 95:
                print("Ant returned empty-handed!")
            else:
                self.health = 0
                print("Ant has died from a horrible accident!")

    def is_alive(self):
        return self.health > 0

def main():
    colony = Colony()

    while True:
        print(
           "========================================================\n"
           "\n"
           "Your colony has {ants} ants and {food} food, Your Majesty.\n"
           "What would you like to do?\n"
           "  1: Do nothing\n"
           "  2: Breed worker (costs {cost} food)"
           .format(ants=colony.num_ants(), cost=Ant.cost, food=colony.food)
        )
        opt = get_int("> ", 1, 2)

        if opt == 2:
            print("Breeding Worker...")
            colony.add_ant()

        colony.step()

        if colony.num_ants() == 0 and colony.food < Ant.cost:
            print("I'm sorry! Your colony has died out!")
            break

if __name__=="__main__":
    main()

答案 2 :(得分:0)

嗯,这是因为def purge(self)中的以下行:

    Colony.list = Colony.temp

第一次运行purge()时,它会使Colony.listColony.temp指向内存中的同一个数组。因此,当您第二次运行purge()时,您会进入一个无限循环,for number in Colony.list:执行Colony.temp.append("ant"),这实际上会增加Colony.list,并且循环永不退出,因为它总会有一个新成员。

在python中,for循环为给定对象创建迭代器(如果它还不是迭代器)。在每次迭代中,python都会调用迭代器的next()方法(在本例中为列表)。如果next()无法产生新值来迭代,则会引发StopIteration,并且循环退出。不用担心,for语句会自动为您处理此异常。在您的情况下,Colony.list.next()始终会找到一个新值(因为您刚刚附加到它上面),并且永远不会到达终点。

要修复代码,请尝试切片。这意味着复制了数组,而不是将两个名称指向同一个数组:

    Colony.list = Colony.temp[:]

答案 3 :(得分:0)

这个答案有点偏,但似乎它将是一个有价值的知识。 这里的一个大问题是你的课程以不合需要的方式使用。

类的主要优点是保存变量/函数的实例,这样您就可以对它们进行多次独立分组。

通过调用Colony.<var>,您正在更改基类(或超级)类变量的var。如果你只想拥有一个殖民地,这是有效的......但是如果你想要两个,那该怎么办?还是三个!还是一百万!!?

注意当您没有输入self作为类函数的第一个参数时,如何收到错误?您需要意识到的是,您正在将类的实例作为第一个参数传递。这就是类如何知道要使用的变量分组。

说我们有一个班级Antzilla

class Antzilla:
    antvar = "antzilla var"
    def PrintSuperAntvar(self):
        print Antzilla.antvar

    def PrintInstanceOfAntvar(self):
        print self.antvar

请注意PrintSuperAntvar调用基本var并且PrintInstanceOfAntvar打印Antzilla的实例

如果我az1并更改az1.antvar,则不会更改Antzilla.antvar值。

az1 = Antzilla()
az1.antvar = "new var"


az1.PrintSuperAntvar()
>>> antzilla var
az1.PrintInstanceOfAntvar()
>>> new var

我现在可以创建一个具有原始起始值的新Antzilla实例,因为我从未更改过基类值

az2 = Antzilla()
az2.PrintSuperAntvar()
>>> antzilla var
az2.PrintInstanceOfAntvar()
>>> antzilla var

但是,如果您要更改此超级值,则会看到新的Antzilla以此新值开头,但已更改的Antzilla仍保持不变。

Antzilla.antvar = "newest var"
az3 = Antzilla()
az3.PrintSuperAntvar()
>>> newest var
az3.PrintInstanceOfAntvar()
>>> newest var

az1.PrintSuperAntvar()
>>> new var

观看!!! 注意我们致电az2时会发生什么!

az2.PrintSuperAntvar()
>>> newest var

az2永远不会从超级变量中更改,因此当我们将Antzilla.antvar"antzilla var"更改为"newest var"时,az2将继续坚持超级值。

我们如何避免这种冲突!?它很简单!

只需在您的类中添加构造函数复制超值,或将新值添加到自己的变量中。 如果存在,则在您创建新的__init__实例

时将调用Antzilla函数
class Antzilla:
    antvar = "antzilla var"

    def __init__(self):
         self.antvar = Antzilla.antvar

    ...

您还可以将var作为要求添加到构造函数中,以使每个实例都是唯一的。

class Antzilla:
    antvar = "antzilla var"

    def __init__(self, antvar ):
         self.antvar = antvar

    ...

az1 = Antzilla("antzilla unique swag")

重要的是要注意,在处理列表等变量时,您需要专门为每个实例创建一个新列表。幸运的是,最好的地方也是构造函数。

现在回到你的问题,..对于你的两个类,我会添加像这样的构造函数

对于殖民地:

class Colony(object):
    workerAnts = 0
    list = []
    temp = []
    foodAmount = 10

    def __init__(self):
        self.workerAnts = 0
        self.list = []
        self.temp = []
        self.foodAmount = 10

    ....

对于Ant

class Ant(object):  
    health = 10
    def __init__(self):
        self.health = 10
    ....

最后,在进入数学或逻辑错误之前,您需要做的是用self或给定范围内的变量名称替换您调用基本或超级变量的所有位置。

即:

 Colony.foodAmount -= 5 

更改为:

 self.foodAmount -= 5

=============================================== =============================

PS那个你写的地方:

Colony.temp.append("ant")

实际上是将字符串附加到 base 列表中。您可能希望将其更改为Ant的构造函数..它返回Ant类的新实例,并使其将变量添加到colony的实例而不是基础colony

self.temp.append(Ant())

=============================================== =============================

希望这会有所帮助!!

干杯,

校准