简体   繁体   中英

For loop does not update its range when list gets updated in Python

As a part of a small project using object orientated programming in Python. I've tried making a simple setup/simulation program for a computing cluster. The cluster consists of a set of racks, and each rack consists of 12 nodes each. I've almost finished the program, although I'm struggling to see why this happens and how to solve it.

The entire program spans over three classes, a node, a rack, and a cluster.

What I'm trying to do here is to create a method which checks if a rack is full (Full being that it contains 12 nodes), and if so, create a new rack instance, then fill the newest rack instance with nodes.

This is the relevant code for the cluster

class Cluster:
    def __init__(self, nodesPerRack, racks=[]):
        self.nodesPerRack = nodesPerRack
        self.racks = racks

    def addNode(self, node):
        if len(self.racks) == 0:
            newRack = Rack()
            self.racks.append(newRack)
            print(len(self.racks))

        for i in range(len(self.racks)):
            if self.racks[i].getNodes() < self.nodesPerRack:
                print("IM ADDING TO A RACK")

                self.racks[i].settInn(node)

            elif self.racks[i].getNodes() >= self.nodesPerRack:
                print("New rack is being made")
                newRack = Rack()

                newRack.insertInto(node)

                self.racks.append(newRack)

If the program is run, it seems to not do anything, and I suspect it generates countless instances of Rack or it repetitively checks if there the rack has space (thus consuming a bunch of ram?)

I've tried several methods, and I'm starting to suspect that the range it is iterating over is not getting updated, making it hang, even though a new Rack element is added, which should update the following statement

for i in range(len(self.racks)):

How would i make the for loop update its range? I have tried using the following method using a while loop

i = 0
while i < self.nodesPerRack:
    do something
i += 1

It still resorts to the same problem as with the for loop.

Additionally here is the relevant parts for Rack

class Rack: 
    def __init__(self, nodes=[]):
        self.nodes = nodes

    def addTo(self, node):
        self.nodes.append(node)

and the class for Node

class Node:
    def __init__(self, minne, antPros):
        self.minne = minne
        self.antpros = antPros

Here is the code that I used to start the test

from node import Node
from rack import Rack
from cluster import Cluster

cluster = Cluster(12)

for i in range(0,650):
    newNode = Node(64,1)
    cluster.addNode(newNode)

for i in range(0,16):
    newNode = Node(1024, 2)
    cluster.addNode(newNode)

range(len(self.racks)) takes the length once, when executing that expression. A for loop does not re-evaluate that expression each iteration.

You can avoid the whole issue by just looping over the list itself:

for rack in self.racks:

and use rack instead of self.racks[i] . The iterator that is created for a list object remains connected to the list, and each time you ask for the next value it'll re-check the length. This means a for loop over a list that is being extended within the loop will iterate over the extra elements too:

>>> l = [42, 81]
>>> for i in l:
...     print(i)
...     if i == 42:
...         l.append(117)
...
42
81
117

In other cases, you could use a while loop that tests a counter against the length each time:

i = 0
while i < len(self.racks):
    # ...
    i += 1

while does re-evaluate the expression each iteration:

>>> l = [42, 81]
>>> i = 0
>>> while i < len(l):
...     print(l[i])
...     if l[i] == 42:
...         l.append(117)
...     i += 1
...
42
81
117

A while loop is more cumbersome for this task, as now you have to manually maintain the counter, index into your self.racks list each time, and it's easy to forget or miss the i += 1 at the end.

In addition of Martijn's answer I'm not sure whether

self.racks[i].getNodes()

returns the number of nodes by the name of the method. If it returns them, that my answer isn't relevant.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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