Function won't sucessfully loop over class ins

2019-08-19 04:54发布

问题:

This uses a similar sort of registry to this question I asked. Inside a class, I have a registry (in the form of a list this time) of all instances of that class. An instance is initialised with some coordinates, but these will be changed as the user uses the program. I have made a function that resets these coordinates (simplified version)

class Foobar:
    _registry = []
    def __init__(self, position=[0,0,0], direction=[0,0,1]):
        self._pos = position # can change later
        self._pos0 = position # stored static copy of initial position
        self._dir = direction
        self._dir0 = direction # stored initial direction
        self._registry.append(self) # adds instance to registry
        ...
    def remove(self):
        Foobar._registry.remove(self) # removes instance from registry
    def reset(self):
        self.remove()
        Foobar.__init__(self, self._pos0, self._dir0)
        # re-initialises instance with starting parameters
    ...
def reset_all():
    # note: outside of Foobar
    for item in Foobar._registry:
        item.reset()

Now, this works if I do

>>> A = Foobar([0,0,0], [0,0,1])
>>> A.do_something_that_adds_more_pos_&_dir_vectors()
>>> B = Foobar(... # same sort of thing. C, D etc
>>> A.reset()
>>> B.reset()
>>> C.reset()
>>> D.reset()

Those all reset fine. If I enter into the IPython console

>>> for item in Foobar._registry:
...     item.reset()

All the objects reset fine. But if I do reset_all() instead, I find that some of the instances reset, whilst others don't. If I keep doing reset_all() eventually they will all have reset, but not in one go. What's going on!?

Extra info: I append position and direction vectors to these objects. I then plot the paths dictated by the vectors. If I try reset_all() and then try to plot them again, some of them get reset and no longer show up on the plot (as expected), but about half still show up.

回答1:

You're indirectly mutating Foobar._registry as you iterate over it. This is illegal, and can in theory lead to anything from working fine to reformatting your hard drive, but in practice it usually means you end up skipping over some of the values.

The simplest change is to iterate over a copy: for item in Foobar._registry[:]: