List of Python objects with random attributes
(Edit: randrange is just random.randrange, I didn't write my own RNG)
I am trying to create a list of instances of a specific class. Here's the whole class (as requested):
from random import randrange
class Poly:
points = [0] * 8
fill = 'red'
alpha = 1.0
def __init__(self, width=100, height=100):
for i in range(0, 8, 2):
self.points[i] = randrange(width)
self.points[i+1] = randrange(height)
self.alpha = random()
return
Seems to work well:
>>> for i in range(5):
Poly().points
[28, 64, 93, 26, 15, 31, 44, 50]
[24, 14, 47, 14, 35, 17, 63, 62]
[99, 28, 90, 29, 56, 59, 57, 33]
[62, 56, 48, 28, 40, 73, 70, 99]
[99, 32, 27, 99, 42, 57, 86, 12]
But if I try to create a list of these objects, I get separate instances (different memory addresses), but they all have the same random values:
>>> p = []
>>> for i in range(5):
p.append(Poly())
>>> p
[<gen_image.Poly instance at 0x02D773C8>, <gen_image.Poly instance at 0x02D77FD0>, <gen_image.Poly instance at 0x0321D030>, <gen_image.Poly instance at 0x02D51E40>, <gen_image.Poly instance at 0x02D51DA0>]
>>> for poly in p:
print poly.points
[75, 18, 5, 76, 6, 64, 95, 54]
[75, 18, 5, 76, 6, 64, 95, 54]
[75, 18, 5, 76, 6, 64, 95, 54]
[75, 18, 5, 76, 6, 64, 95, 54]
[75, 18, 5, 76, 6, 64, 95, 54]
What's going on here? And what's the correct way to do what I am trying to do?
a source to share
Move array creation to method __init__
.
You are working with a common array among all objects.
The reason the former shows the other is because you are printing the contents of that array before you create a new Poly object and thus trample the contents of the array. If you saved them and checked them later, they all seem to have the same content as the previous one.
Oh, and try not to simplify your code when submitting questions. Always submit complete, but short, programs that reproduce the problem.
Here is a short but complete program that demonstrates the problem you are facing:
from random import randrange
class Poly:
points = [0]*8
def __init__(self, width=100, height=100):
for i in range(0, 8, 2):
self.points[i] = randrange(width)
self.points[i+1] = randrange(height)
return
p1 = Poly()
print "p1:", p1.points
p2 = Poly()
print "p2:", p2.points
print "p1:", p1.points
Output example:
[C:\Temp] test.py
p1: [19, 5, 1, 46, 93, 18, 18, 57]
p2: [92, 71, 42, 84, 54, 29, 27, 71]
p1: [92, 71, 42, 84, 54, 29, 27, 71]
Notice how p1 has changed.
The fixed code can be as simple as:
from random import randrange
class Poly:
def __init__(self, width=100, height=100):
self.points = [0]*8
for i in range(0, 8, 2):
self.points[i] = randrange(width)
self.points[i+1] = randrange(height)
return
a source to share
You have a class attribute Poly.points
. In your method, __init__
you are executing self.points[i] = ...
. This now makes Python use Poly.points
that is used by all instances. But you want to points
be an instance attribute. I would suggest the following:
class Poly:
# you don't need this here
#points = [0] * 8
#fill = 'red'
#alpha = 1.0
def __init__(self, width=100, height=100):
self.points = [0]*8
self.fill = 'red'
self.alpha = random()
for i in range(0, 8, 2):
self.points[i] = randrange(width)
self.points[i+1] = randrange(height)
a source to share
All lists of shared lists. It would seem that you are declaring points as a list of an instance or class. This is not the way to do things in Python unless you want to share the list between instances. Try:
def __init__(self, width=100, height=100):
self.points = [] #Create a new list
for i in range(0, 8, 2):
self.points.append(randrange(width))
self.points.append(randrange(height))
return
a source to share