BBedit
BBedit

Reputation: 8057

How to stop elements in list from changing?

I'm not really sure what is going on here. But the elements in my list keep changing.

table._row_gen is a generator instance, and it creates the rows for my table. Source is here.

It returns a dict; I can also get the dict directly from table._row_gen.stats.

def test_append(self):
        start_stats = {'step':250,'offset':13,'inc':113,'danger':0,'input':None}
        gen = StatGenerator(start_stats)
        table = PathTable(gen)

        stats_list = []

        for i in xrange(50):
            stats_list.append(table._row_gen.stats)
            print stats_list[i]
            table._row_gen.next()

        assert stats_list[0]['step'] == 250

This should build a list of rows to stats_list.

The print works fine and displays the correct output:

{'danger': 0, 'input': None, 'step': 250, 'inc': 113, 'offset': 13}
{'enc': False, 'danger': 113, 'rnd': 216, 'step': 252, 'limit': 55552, 'offset': 13, 'inpu
{'enc': False, 'danger': 226, 'rnd': 163, 'step': 254, 'limit': 41984, 'offset': 13, 'inpu
{'enc': False, 'danger': 339, 'rnd': 151, 'step': 0, 'limit': 38912, 'offset': 26, 'input'
{'enc': False, 'danger': 452, 'rnd': 212, 'step': 2, 'limit': 54528, 'offset': 26, 'input'
{'enc': False, 'danger': 565, 'rnd': 64, 'step': 4, 'limit': 16640, 'offset': 26, 'input'

But the list is malformed, and the assert fails:

>           assert stats_list[0]['step'] == 250
E           assert 94 == 250

test_int_path_table.py:47: AssertionError

After the loop:

print stats_list[0]
{'enc': True, 'danger': 5650, 'rnd': 6, 'step': 94, 'limit': 1792, 'offset': 26, 'input':

94 should the last row. Yet all of the rows are reporting to be the same:

print stats_list[0] is stats_list[48]
True

I don't really understand why this is happening, and I would like the list to be correct (like the print output).

Upvotes: 0

Views: 81

Answers (1)

AI Generated Response
AI Generated Response

Reputation: 8845

The simple solution is to make a copy. For this, you can do

def test_append(self):
        start_stats = {'step':250,'offset':13,'inc':113,'danger':0,'input':None}
        gen = StatGenerator(start_stats)
        table = PathTable(gen)

        stats_list = []

        for i in xrange(50):
            stats_list.append(table._row_gen.stats.copy()) # <=== the copy call makes a new copy and solves your problem.
            print stats_list[i]
            table._row_gen.next()

        assert stats_list[0]['step'] == 250

Also, the next call at the end of the for block is extraneous. It can be combined using

def test_append(self):
        start_stats = {'step':250,'offset':13,'inc':113,'danger':0,'input':None}
        gen = StatGenerator(start_stats)
        table = PathTable(gen)

        stats_list = []

        for i in xrange(50):
            stats_list.append(next(table._row_gen).copy())
            print stats_list[i]

        assert stats_list[0]['step'] == 250

If you're in control of the pastebin code, the stats property should return a defensive copy.

    @property
    def stats(self):
            return self._stats.copy()

and the next method should return a defensive copy too.

    def next(self):
            ''' Generates and returns stats. '''
            row = self._stats
            row['step'] = self._genStepId(self._stats['step'])
            row['offset'] = self._genOffset(self._stats['offset'], self._stats['step'])
            row['danger'] = self._genDanger(self._stats['danger'], self.stats['inc'])
            row['rnd'] = self._genRnd(self.rnlut[self._stats['step']], self._stats['offset'])
            row['limit'] = self._genDangerLimit(self._stats['rnd'])
            row['enc'] = self._genEnc(self._stats['danger'], self._stats['limit'])

            return self.stats

If you do the above two blocks, the copy in the first two is no longer necessary.

Upvotes: 1

Related Questions