views:

81

answers:

3

The below code attempts to illustrate what I want. I basically want two instances of "random" that operate independently of each other. I want to seed "random" within one class without affecting "random" in another class. How can I do that?

class RandomSeeded:
    def __init__(self, seed):
        import random as r1
        self.random = r1
        self.random.seed(seed)
    def get(self):
        print self.random.choice([4,5,6,7,8,9,2,3,4,5,6,7,])

class Random:
    def __init__(self):
        import random as r2
        self.random = r2
        self.random.seed()
    def get(self): 
        print self.random.choice([4,5,6,7,8,9,2,3,4,5,6,7,])

if __name__ == '__main__':
    t = RandomSeeded('asdf')
    t.get()       # random is seeded within t
    s = Random()
    s.get()       
    t.get()       # random should still be seeded within t, but is no longer
+6  A: 

Class random.Random exists specifically to allow the behavior you want -- modules are intrinsically singletons, but classes are meant to be multiply instantiated, so both kinds of needs are covered.

Should you ever need an independent copy of a module (which you definitely don't in the case of random!), try using copy.deepcopy on it -- in many cases it will work. However, the need is very rare, because modules don't normally keep global mutable states except by keeping one privileged instance of a class they also offer for "outside consumption" (other examples besided random include fileinput).

Alex Martelli
Answers the specific case as well as my general problem. Thanks a lot!
Lin
Deepcopying a module sounds scary.
FogleBird
It's hard to think of a case when making a copy of a module makes sense within a remotely reasonable design.
Mike Graham
@Mike, maybe, but not all people are remotely reasonable designers. @FogleBird, what's so scary?
Alex Martelli
@Alex, It seems strange to give people advice to accomplish unreasonable routines using buggy, fragile methods that violate basic assumptions, especially when it isn't even applicable to their problem.
Mike Graham
@Mike, when you program in the real world you'd better have a quiver of general-purpose practical hacks (I dispute the "buggy" claim!-) as well as better point-solutions -- only in an ivory tower of idealized perfection do you never have to deal with third-party or legacy code whose design is, ahem, not gonna win any prize soon;-).
Alex Martelli
@Alex, I say it is buggy because you do not know what is in the module in general, and it might not be deepcopyable; if not, you could have shared state and not know it. I do program in the real world and have had to use tons of bad third-party code and even worse legacy code. When I use awful hacks, I'm giving my successors more ugly, crazy legacy code to work with. "Write reasonable code" is not naive or academic or uneconomical.
Mike Graham
+3  A: 

For the seeded random numbers, make your own instance of random.Random. The random documentation explains this class, which the module depends on a single instance of when you use the functions directly within it.

Mike Graham
+2  A: 

Sadly, having two independent RNG's is can be less random than having a single RNG using an "offset" into the generated sequence.

Using an "offset" means you have to generate both complete sequences of samples, and then use them for your simulation. Something like this.

def makeSequences( sequences=2, size=1000000 ):
    g = random.Random()
    return [ [ g.random() for g in xrange(size) ] for s in xrange(sequences) ] ]

t, s = makeSequences( 2 )

RNG's can only be proven to have desirable randomness properties for a single seed and a single sequence of numbers. Because two parallel sequences use the same constants for the multiplier and modulus, there's a chance that they can have a detectable correlation with each other.

S.Lott