Copying a generator without bloating memory

I am writing a python class that finds all possible magic squares with an integer sizeand a generator for the possible combinations. These combinations are tuples of length size**2and are split into a grid size& times; size. The code itself works fine, but reuse of the generator is required itertools.tee. In the example shown below, this causes the memory used by the thread to jump to 300 MB, since each value in the iterator is stored in a list.

from itertools import permutations, tee

class MagicSquare:
    def __init__(self, size, combinations):
        self.size = size
        self.range = range(self.size)
        self.combinations = combinations

    def getGrid(self, entries):
        return [ entries[self.size*i:self.size*(i+1)] for i in self.range ]

    def checkGrid(self, grid):
        check_sum = sum(grid[0])
        if any( sum(row) != check_sum for row in grid ): 
            return False
        if any( sum(row[col] for row in grid) != check_sum for col in self.range ): 
            return False
        if sum(grid[diag][diag] for diag in self.range) != check_sum: 
            return False
        if sum(grid[diag][self.size-diag-1] for diag in self.range) != check_sum: 
            return False
        return True

    def solutions(self):
        combinations, self.combinations = tee(self.combinations)
        for entries in combinations:
            grid = self.getGrid(entries)
            if self.checkGrid(grid):
                yield grid

if __name__ == '__main__':
    combs = permutations(range(20,30), 9)
    ms = MagicSquare(3, combs)
    for solution in ms.solutions():
        for row in solution:
            print row
        print

, . -, , , , , . -, . , , , , checkGrid combinations.

, : ? , , , .

, Python 3.X copy.deepcopy itertools, .

+4
4

...

itertools.permutations . , , !

>>> from itertools import permutations
>>> combs = permutations(range(20,30), 9)
>>> from copy import deepcopy
>>> combs2 = deepcopy(combs)
>>> next(combs)
(20, 21, 22, 23, 24, 25, 26, 27, 28)
>>> next(combs2)
(20, 21, 22, 23, 24, 25, 26, 27, 28)
+2

. ; , , - itertools.tee. , , , .

, API, . , API MagicSquare, , solutions.

MagicSquare. , , , , solutions . , , MagicSquare(size, combinations).solutions() ?

0

, , . MagicSquare , , .

:

class MagicSquare:
    def __init__(self, size, get_combinations):
        ...
        self.get_combinations = get_combinations

    ...

    def solutions(self):
        for entries in self.get_combinations():
            ...

if __name__ == '__main__':
    combs2 = lambda: permutations(range(20,30), 9) # 
    ms2 = MagicSquare(3, combs2)
    ...
0

Since your generator is autonomous and deterministic, the best way to work with two instances is to create two of them. (If necessary, change the signature MagicSquareto accept two generators, but it looks like you want a copy for other purposes?)

combs2a = permutations(range(20,30), 9)
combs2b = permutations(range(20,30), 9)
-1
source

Source: https://habr.com/ru/post/1625580/


All Articles