Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm writing a small Python application that performs model simulation for many different parameters. The iterator of parameters isn't completely known ahead of time. Rather, the iterator needs to change and adapt based on the results of the previous simulations.

The code illustrates how I implemented a prototype of the parameter scanning algorithm, but the solution feels non-pythonic (ugly, implicit, complex,....). Specifically, it feels problematic to modify the iterator over which I'm looping inside the for loop. I've consulted google looking for pythonic constructs that meet my needs, but have been unable to find any ("adaptable iterator", "modifiable generator",....).

Is there a more pythonic way to express the logic in the function scan()?

import random as r


def scan(simulate, iterator, process):
    """A simple scanning procedure of parameters in an iterator. Perform a simulation on
    each parameter in the iterator, process the output of the simulation, update the iterator"""
    for parameter in iterator:
        print(parameter)  # for prototype logging

        # simulate a model for a particular parameter value
        result = simulate(parameter)

        # update the process object via the call method
        process.call(result)

        # update the iterator based on the currently processed simulations (e.g. stochastic optimization)
        iterator.update(process)

    return process.finish()


# toy simulator
def mysimulate(p):
    return r.random() > .5


# example adaptable iterator
class MyIter:
    def __init__(self, n):
        self.i = 0
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):
        if self.i < self.n:
            i = self.i
            self.i += 1
            return i
        else:
            raise StopIteration()

    def update(self, process):
        """update takes in a process object and modifies the iterator according to some algorithm to change
        the values returned by __next__"""
        if r.random() < .4:
            self.i -= 1


class MyProcess:
    """Toy processing object."""
    log = []

    def call(self, trajectory):
        self.log.append(trajectory)

    def finish(self):
        return sum(self.log)


out = scan(mysimulate, MyIter(20), MyProcess())

print(out)
share|improve this question
    
Do you really want to ask the question like that? Using def random_repeat(x): for val in itertools.repeat(x): yield val; if r.random() >= 4: break I could propose to shorten it to print(sum(r.random() > .5 for x in range(20) for v in random_repeat(x)) (even though you'd lose your "logging" print(v)). But since your code is hypothetical and stripped off of all its context, this has probably nothing in common with the problem you are trying to solve. See also this meta post – Mathias Ettinger Apr 24 '16 at 14:41
    
Is this supposed to be a generic solver or do you have a specific purpose with it? Your function names are ambiguous. – Mast Apr 24 '16 at 18:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.